Compare commits

...

60 Commits

Author SHA1 Message Date
c501c19750 Add a version field to blobs (bp #5057) (#5068)
automerge
2019-07-12 14:38:32 -07:00
acd55660da Add --no-snapshot to disable booting a validator from a snapshot (#5050) (#5073)
automerge
2019-07-12 15:35:42 -06:00
855bd7d3b8 apt-get update before installing certbot (#5054) (#5056)
* apt-get update before installing certbot

(cherry picked from commit f093377805)
2019-07-12 11:54:56 -06:00
a2e9d8e0bf Enable GPUs and secondary disks for TdS net, pull external account file (#5031) (#5053) 2019-07-12 10:17:46 -06:00
81dbe3c49b Add support for additional disks for config-local (#5030) (#5040)
* Add support for additional disks for config-local

(cherry picked from commit e4861f52e0)
2019-07-12 10:01:07 -06:00
086e20f6c7 Restore ledger-tool print and json commands (#5048) (#5049)
automerge
2019-07-11 21:14:37 -07:00
d08a810c08 v0.16: Expand Config program; implement Validator Info CLI (#5045)
* Update config program to accommodate multiple signers (#4946)

* Update config program to accommodate multiple signers

* Update install CLI

* Remove account_type u32; add handling for unsigned keys in list

* ConfigKeys doc

* Make config_api more robust (#4980)

* Make config_api more robust

* Add test and update store instruction

* Improve signature checks in config_api (#5001)

automerge

* Add validator-info CLI (#4970)

* Add validator-info CLI

* Add GetProgramAccounts method to solana-client

* Update validator-info args, and add get subcommand

* Update ValidatorInfo lengths

* Add account filter for get --all

* Update testnet participation doc to reflect validator-info

* Flesh out tests

* Review comments
2019-07-11 18:28:49 -06:00
400610bf6a v0.16: AccountsDB updates and getProgramAccounts RPC fix (#5044)
* reduce replicode in accounts, fix cast to i64 (#5025)

* add accounts_index_scan_accounts (#5020)

* Plumb scan_accounts into accounts_db, adding load from storage (#5029)

* Fix getProgramAccounts RPC (#5024)

* Use scan_accounts to load accounts by program_id

* Add bank test

* Use get_program_accounts in RPC

* Rebase for v0.16
2019-07-11 17:57:56 -06:00
f759ac3a8d add node_pubkey to vote warning (#5033) (#5034)
(cherry picked from commit a191f3fd90)
2019-07-11 13:58:49 -07:00
558411364e Pass SOLANA_METRICS_CONFIG along to oom-monitor.sh (#5021) (#5026)
(cherry picked from commit 8781aebe06)
2019-07-11 12:43:38 -07:00
d0b5be3051 Rename tds-testnet to tds (#5008) (#5009)
(cherry picked from commit e563a4dda3)
2019-07-10 11:39:57 -06:00
dc6da6fcca Bump @solana/blockexplorer to v1.17.2 2019-07-10 09:33:10 -07:00
8ae11a74fa Move letsencrypt arg to create_args 2019-07-09 21:26:56 -07:00
11f0333728 Include --letsencrypt ($1) 2019-07-09 20:55:41 -07:00
aac74d2357 Fund solana-install deployments from the mint keypair to avoid airdrops (#4997) (#5000)
automerge
2019-07-09 17:29:43 -07:00
508abcf4ed net/ plumbing to manage LetsEncrypt TLS certificates (#4985) (#4996)
automerge
2019-07-09 16:29:45 -07:00
6dbb6c7fe2 Fix always passing in remote filename, even if no accounts file (#4993) (#4994)
* Fix always passing in remote filename, even if no accounts file

* typo

(cherry picked from commit d111223085)
2019-07-09 15:44:04 -07:00
2f58658f61 Add testnet-tds support to testnet manager (#4762) (#4987)
automerge
2019-07-09 14:16:13 -07:00
0ec7ff5e2f Add pubkey (#4971) (#4977)
automerge
2019-07-09 01:28:48 -07:00
4d49820188 Handle replicator errors without panicking (#4957)
* Handle replicator errors without panicking

* Typo

* Handle error with match instead of if-let

* Discard error
2019-07-08 11:23:21 -07:00
6e51babff9 Reduce default commission from 100% to 50% (#4929) 2019-07-05 08:00:39 -07:00
872cf100d7 [Security] Bump smallvec from 0.6.9 to 0.6.10 (#4921)
Bumps [smallvec](https://github.com/servo/rust-smallvec) from 0.6.9 to 0.6.10. **This update includes security fixes.**
- [Release notes](https://github.com/servo/rust-smallvec/releases)
- [Commits](https://github.com/servo/rust-smallvec/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-03 18:12:11 -07:00
78cc4e644c Cargo.lock 2019-07-03 18:10:31 -07:00
81c0152187 install: more little window fixes (#4930)
* Only add .exe extension if no extension was given

* Switch to ctrlc crate for freebie Windows ^C handling
2019-07-03 18:00:27 -07:00
4779625f23 change vote commission to u8 (from u32) (#4887) (#4918)
automerge
2019-07-02 14:52:53 -07:00
3c0b03ba84 Update cargo.toml and cargo.lock files for 0.16.3 (#4917) 2019-07-02 14:33:04 -06:00
c53f163ef5 Add RPC api to return program accounts (#4876) (#4912)
automerge
2019-07-02 11:48:00 -07:00
ca35854417 Add .exe extension before checking for a program file on windows (#4902) (#4903)
automerge
2019-07-02 08:48:35 -07:00
ab1fda2a54 Add curl retries 2019-07-02 08:38:18 -07:00
a6ec77c230 Update Cargo.toml 2019-07-01 23:18:15 -07:00
1d7894f1be Avoid signal-hook crate on windows (#4901) 2019-07-01 22:52:49 -07:00
4866a1fc39 run command now kills child process on SIGTERM to cleanly exit (#4896) (#4899)
automerge
2019-07-01 19:28:12 -07:00
60c5e59a5e Always send pull responses to the origin addr (#4894) (#4897)
automerge
2019-07-01 17:34:51 -07:00
fd93bdadf6 Try to gracefully terminal child process before using SIGKILL (#4890) (#4892)
automerge
2019-07-01 14:43:15 -07:00
6089db2a07 Rework fullnode.sh to recover better from genesis block resets (#4884) (#4888)
automerge
2019-07-01 12:31:53 -07:00
462d0cfc6c Disable Enter prompt when stdin is not a tty (#4874) (#4877)
(cherry picked from commit 41bda18046)
2019-06-28 18:18:39 -07:00
e6d6fc4391 Don't prompt the user to update their PATH if --no-modify-path was supplied (#4872) (#4875)
automerge
2019-06-28 17:39:21 -07:00
092556ae5e Lower warn to info, fetch from validator root instead of root + 1 (#4870) (#4873)
automerge
2019-06-28 16:55:46 -07:00
ad9fa54a47 Ensure validator process is killed when fullnode.sh is killed (#4869) (#4871)
automerge
2019-06-28 15:03:46 -07:00
2d68170747 Update cargo.toml files to version 0.16.2 (#4854) 2019-06-27 11:08:02 -06:00
20f3d18458 Save snapshots followed by accounts to avoid stale account data (#4847) (#4849)
automerge
2019-06-26 23:53:14 -07:00
be79efe9b7 rsync of ledger/ and state.tgz now works on both macOS and Linux (#4845) (#4846)
automerge
2019-06-26 22:45:44 -07:00
5db377f743 Use default pubkey for solana-install sanity check 2019-06-26 21:51:10 -07:00
9c2f45a1e0 Fix possible subtract with overflow if mining pool is not setup (#4836)
automerge
2019-06-26 15:28:37 -07:00
8646918d00 Upload all artifacts 2019-06-26 14:38:55 -07:00
7c44fc3561 Set CI_REPO_SLUG correctly for the solana-secondary pipeline 2019-06-26 14:38:55 -07:00
686403eb1d Setup reward pools in genesis (#4831) (#4834)
automerge
2019-06-26 14:29:27 -07:00
6cf9b60a9c Airdrop more token in wallet sanity due to fee (#4830) (#4832)
automerge
2019-06-26 14:05:17 -07:00
aca142df16 Update cargo.toml files to 0.16.1 (#4829) 2019-06-26 13:25:13 -06:00
b2582196db Create snapshots sparsely (#4815) (#4816)
(cherry picked from commit c5e6ebb496)
2019-06-25 12:13:05 -07:00
85a77bec5f Set proper count value for account stores (#4797) (#4813)
* set count values for store accounts

* Use AppendVecId type

(cherry picked from commit 9e7f618cff)
2019-06-25 07:57:40 -07:00
e781cbf4ba Ignore flaky test_two_unbalanced_stakes (#4794) (#4796)
automerge
2019-06-23 21:30:02 -07:00
59956e4543 Remove --storage-mining-pool-lamports (#4792) (#4793)
automerge
2019-06-23 20:53:31 -07:00
303417f981 Lock blockexplorer version 2019-06-22 22:23:16 -07:00
fea03fdf33 Add storage reward pools (#4779) (#4789)
automerge
2019-06-22 21:26:11 -07:00
e8160efc46 Prevent Travis/Appveyor from trying to build mergify branches (#4786) (#4787)
(cherry picked from commit 23b6b85bf0)
2019-06-22 08:58:13 -07:00
e0ba0d581c Update authorized public key (#4783) 2019-06-22 08:44:00 -07:00
36eda29fc9 Add instructions and processor for stake deactivation (#4781)
automerge
2019-06-22 08:43:17 -07:00
2ec73db6bd Program instruction to withdraw un-staked lamports from stake account (#4780) (#4782) 2019-06-22 00:11:15 -07:00
ef6ce2765e Remove storage-mining-pool-keypair arg 2019-06-21 21:38:43 -07:00
131 changed files with 3763 additions and 1346 deletions

View File

@ -4,7 +4,7 @@ version: '{build}'
branches:
only:
- master
- /v[0-9.]+/
- /^v[0-9.]+/
cache:
- '%USERPROFILE%\.cargo'

View File

@ -17,7 +17,7 @@ script:
branches:
only:
- master
- /v.*/
- /^v\d+\.\d+(\.\d+)?(-\S*)?$/
notifications:
slack:

647
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,7 @@ members = [
"runtime",
"sdk",
"upload-perf",
"validator-info",
"vote-signer",
"wallet",
]

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -24,16 +24,16 @@ serde_derive = "1.0.92"
serde_json = "1.0.39"
serde_yaml = "0.8.9"
# solana-runtime = { path = "../solana/runtime"}
solana = { path = "../core", version = "0.16.0" }
solana-client = { path = "../client", version = "0.16.0" }
solana-drone = { path = "../drone", version = "0.16.0" }
solana-exchange-api = { path = "../programs/exchange_api", version = "0.16.0" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-metrics = { path = "../metrics", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana-runtime = { path = "../runtime", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-client = { path = "../client", version = "0.16.3" }
solana-drone = { path = "../drone", version = "0.16.3" }
solana-exchange-api = { path = "../programs/exchange_api", version = "0.16.3" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.3" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-metrics = { path = "../metrics", version = "0.16.3" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
solana-runtime = { path = "../runtime", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
untrusted = "0.6.2"
ws = "0.8.1"

View File

@ -2,16 +2,16 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
solana = { path = "../core", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
[features]
cuda = ["solana/cuda"]

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-tps"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -15,14 +15,14 @@ serde = "1.0.92"
serde_derive = "1.0.92"
serde_json = "1.0.39"
serde_yaml = "0.8.9"
solana = { path = "../core", version = "0.16.0" }
solana-client = { path = "../client", version = "0.16.0" }
solana-drone = { path = "../drone", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-metrics = { path = "../metrics", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana-runtime = { path = "../runtime", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-client = { path = "../client", version = "0.16.3" }
solana-drone = { path = "../drone", version = "0.16.3" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-metrics = { path = "../metrics", version = "0.16.3" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
solana-runtime = { path = "../runtime", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[features]
cuda = ["solana/cuda"]

View File

@ -25,6 +25,7 @@ Methods
* [getAccountInfo](#getaccountinfo)
* [getBalance](#getbalance)
* [getClusterNodes](#getclusternodes)
* [getProgramAccounts](#getprogramaccounts)
* [getRecentBlockhash](#getrecentblockhash)
* [getSignatureStatus](#getsignaturestatus)
* [getSlotLeader](#getslotleader)
@ -96,6 +97,32 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
{"jsonrpc":"2.0","result":true,"id":1}
```
---
### getAccountInfo
Returns all information associated with the account of provided Pubkey
##### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
##### Results:
The result field will be a JSON object with the following sub fields:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to
* `data`, array of bytes representing any data associated with the account
* `executable`, boolean indicating if the account contains a program (and is strictly read-only)
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
```
---
### getBalance
@ -142,28 +169,29 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
---
### getAccountInfo
Returns all information associated with the account of provided Pubkey
### getProgramAccounts
Returns all accounts owned by the provided program Pubkey
##### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
* `string` - Pubkey of program, as base-58 encoded string
##### Results:
The result field will be a JSON object with the following sub fields:
The result field will be an array of arrays. Each sub array will contain:
* `string` - a the account Pubkey as base-58 encoded string
and a JSON object, with the following sub fields:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to
* `data`, array of bytes representing any data associated with the account
* `executable`, boolean indicating if the account contains a program (and is strictly read-only)
* `loader`, array of 32 bytes representing the loader for this program (if `executable`), otherwise all
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["8nQwAgzN2yyUzrukXsCa3JELBYqDQrqJ3UyHiWazWxHR"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
{"jsonrpc":"2.0","result":[["BqGKYtAKu69ZdWEBtZHh4xgJY1BYa2YBiBReQE3pe383", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":1,"data":[]], ["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":10,"data":[]]]},"id":1}
```
---
@ -402,7 +430,7 @@ for a given account public key changes
##### Notification Format:
```bash
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
```
---

View File

@ -240,3 +240,18 @@ A local InfluxDB and Grafana instance is now running on your machine. Define
`start.sh` output and restart your validator.
Metrics should now be streaming and visible from your local Grafana dashboard.
#### Publishing Validator Info
You can publish your validator information to the chain to be publicly visible
to other users.
Run the solana-validator-info CLI to populate a validator-info account:
```bash
$ solana-validator-info publish -k ~/validator-keypair.json <VALIDATOR_INFO_ARGS>
```
Available fields for VALIDATOR_INFO_ARGS:
* Name (required)
* Website
* Keybase ID
* Details

View File

@ -1,6 +1,6 @@
[package]
name = "solana-chacha-sys"
version = "0.16.0"
version = "0.16.3"
description = "Solana chacha-sys"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -33,9 +33,15 @@ if [[ -n $CI ]]; then
export CI_PULL_REQUEST=
fi
export CI_OS_NAME=linux
export CI_REPO_SLUG=$BUILDKITE_ORGANIZATION_SLUG/$BUILDKITE_PIPELINE_SLUG
if [[ -n $BUILDKITE_TRIGGERED_FROM_BUILD_PIPELINE_SLUG ]]; then
# The solana-secondary pipeline should use the slug of the pipeline that
# triggered it
export CI_REPO_SLUG=$BUILDKITE_ORGANIZATION_SLUG/$BUILDKITE_TRIGGERED_FROM_BUILD_PIPELINE_SLUG
else
export CI_REPO_SLUG=$BUILDKITE_ORGANIZATION_SLUG/$BUILDKITE_PIPELINE_SLUG
fi
# TRIGGERED_BUILDKITE_TAG is a workaround to propagate BUILDKITE_TAG into
# the solana-secondary builder
# the solana-secondary pipeline
if [[ -n $TRIGGERED_BUILDKITE_TAG ]]; then
export CI_TAG=$TRIGGERED_BUILDKITE_TAG
else

View File

@ -120,16 +120,16 @@ if [[ "$CI_OS_NAME" = linux ]]; then
MAYBE_METRICS_TARBALL=solana-metrics.tar.bz2
fi
echo --- Saving build artifacts
source ci/upload-ci-artifact.sh
upload-ci-artifact solana-release-$TARGET.tar.bz2
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then
echo Skipped due to DO_NOT_PUBLISH_TAR
exit 0
fi
for file in solana-release-$TARGET.tar.bz2 solana-install-init-"$TARGET"* $MAYBE_METRICS_TARBALL; do
upload-ci-artifact "$file"
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then
echo "Skipped $file due to DO_NOT_PUBLISH_TAR"
continue
fi
if [[ -n $BUILDKITE ]]; then
echo --- AWS S3 Store: "$file"
(

View File

@ -24,6 +24,11 @@ blockstreamer=false
deployUpdateManifest=true
fetchLogs=true
maybeHashesPerTick=
maybeStakeNodesInGenesisBlock=
maybeExternalPrimordialAccountsFile=
maybeLamports=
maybeLetsEncrypt=
maybeFullnodeAdditionalDiskSize=
usage() {
exitcode=0
@ -62,11 +67,22 @@ Deploys a CD testnet
-s - Skip start. Nodes will still be created or configured, but network software will not be started.
-S - Stop network software without tearing down nodes.
-f - Discard validator nodes that didn't bootup successfully
-w - Skip time-consuming "bells and whistles" that are
unnecessary for a high-node count demo testnet
--stake-internal-nodes NUM_LAMPORTS
- Amount to stake internal nodes. If set, airdrops are disabled.
--external-accounts-file FILE_PATH
- Path to external Primordial Accounts file, if it exists.
--hashes-per-tick NUM_HASHES|sleep|auto
- Override the default --hashes-per-tick for the cluster
--lamports NUM_LAMPORTS
- Specify the number of lamports to mint (default 100000000000000)
--skip-deploy-update
- If set, will skip software update deployment
--skip-remote-log-retrieval
- If set, will not fetch logs from remote nodes
--letsencrypt [dns name]
- Attempt to generate a TLS certificate using this DNS name
--fullnode-additional-disk-size-gb [number]
- Size of additional disk in GB for all fullnodes
Note: the SOLANA_METRICS_CONFIG environment variable is used to configure
metrics
@ -82,6 +98,30 @@ while [[ -n $1 ]]; do
if [[ $1 = --hashes-per-tick ]]; then
maybeHashesPerTick="$1 $2"
shift 2
elif [[ $1 = --lamports ]]; then
maybeLamports="$1 $2"
shift 2
elif [[ $1 = --stake-internal-nodes ]]; then
maybeStakeNodesInGenesisBlock="$1 $2"
shift 2
elif [[ $1 = --external-accounts-file ]]; then
maybeExternalPrimordialAccountsFile="$1 $2"
shift 2
elif [[ $1 = --skip-deploy-update ]]; then
deployUpdateManifest=false
shift 1
elif [[ $1 = --skip-remote-log-retrieval ]]; then
fetchLogs=false
shift 1
elif [[ $1 = --letsencrypt ]]; then
maybeLetsEncrypt="$1 $2"
shift 2
elif [[ $1 = --fullnode-additional-disk-size-gb ]]; then
maybeFullnodeAdditionalDiskSize="$1 $2"
shift 2
elif [[ $1 == --machine-type* ]]; then # Bypass quoted long args for GPUs
shortArgs+=("$1")
shift
else
usage "Unknown long option: $1"
fi
@ -228,6 +268,11 @@ if ! $skipCreate; then
# shellcheck disable=SC2206
create_args+=(${zone_args[@]})
if [[ -n $maybeLetsEncrypt ]]; then
# shellcheck disable=SC2206 # Do not want to quote $maybeLetsEncrypt
create_args+=($maybeLetsEncrypt)
fi
if $blockstreamer; then
create_args+=(-u)
fi
@ -256,6 +301,11 @@ if ! $skipCreate; then
create_args+=(-f)
fi
if [[ -n $maybeFullnodeAdditionalDiskSize ]]; then
# shellcheck disable=SC2206 # Do not want to quote
create_args+=($maybeFullnodeAdditionalDiskSize)
fi
time net/"$cloudProvider".sh create "${create_args[@]}"
else
echo "--- $cloudProvider.sh config"
@ -318,7 +368,6 @@ if ! $skipStart; then
# shellcheck disable=SC2206 # Do not want to quote $maybeHashesPerTick
args+=($maybeHashesPerTick)
fi
if $reuseLedger; then
args+=(-r)
fi
@ -334,7 +383,19 @@ if ! $skipStart; then
args+=(--deploy-update windows)
fi
# shellcheck disable=SC2086 # Don't want to double quote the $maybeXYZ variables
if [[ -n $maybeStakeNodesInGenesisBlock ]]; then
# shellcheck disable=SC2206 # Do not want to quote $maybeStakeNodesInGenesisBlock
args+=($maybeStakeNodesInGenesisBlock)
fi
if [[ -n $maybeExternalPrimordialAccountsFile ]]; then
# shellcheck disable=SC2206 # Do not want to quote $maybeExternalPrimordialAccountsFile
args+=($maybeExternalPrimordialAccountsFile)
fi
if [[ -n $maybeLamports ]]; then
# shellcheck disable=SC2206 # Do not want to quote $maybeLamports
args+=($maybeLamports)
fi
time net/net.sh "${args[@]}"
) || ok=false

View File

@ -44,6 +44,8 @@ steps:
value: "testnet-beta-perf"
- label: "testnet-demo"
value: "testnet-demo"
- label: "tds"
value: "tds"
- select: "Operation"
key: "testnet-operation"
default: "sanity-or-restart"
@ -153,6 +155,11 @@ testnet-demo)
: "${GCE_NODE_COUNT:=150}"
: "${GCE_LOW_QUOTA_NODE_COUNT:=70}"
;;
tds)
CHANNEL_OR_TAG=beta
CHANNEL_BRANCH=$BETA_CHANNEL
: "${GCE_NODE_COUNT:=3}"
;;
*)
echo "Error: Invalid TESTNET=$TESTNET"
exit 1
@ -287,6 +294,14 @@ sanity() {
$ok
)
;;
tds)
(
set -x
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-sanity.sh tds-solana-com gce "${GCE_ZONES[0]}" -f
)
;;
*)
echo "Error: Invalid TESTNET=$TESTNET"
exit 1
@ -321,7 +336,8 @@ deploy() {
(
set -x
ci/testnet-deploy.sh -p edge-testnet-solana-com -C ec2 -z us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0ccd4f2239886fa94 \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P \
-a eipalloc-0ccd4f2239886fa94 --letsencrypt edge.testnet.solana.com \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
@ -347,7 +363,8 @@ deploy() {
set -x
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p beta-testnet-solana-com -C ec2 -z us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0f286cf8a0771ce35 \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P \
-a eipalloc-0f286cf8a0771ce35 --letsencrypt beta.testnet.solana.com \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
@ -378,7 +395,8 @@ deploy() {
# shellcheck disable=SC2068
ci/testnet-deploy.sh -p testnet-solana-com -C ec2 ${EC2_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$EC2_NODE_COUNT" -c 0 -u -P -f -a eipalloc-0fa502bf95f6f18b2 \
-t "$CHANNEL_OR_TAG" -n "$EC2_NODE_COUNT" -c 0 -u -P -f \
-a eipalloc-0fa502bf95f6f18b2 --letsencrypt testnet.solana.com \
${skipCreate:+-e} \
${maybeSkipStart:+-s} \
${maybeStop:+-S} \
@ -424,7 +442,9 @@ deploy() {
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p demo-testnet-solana-com -C gce ${GCE_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$GCE_NODE_COUNT" -c 0 -P -u -f -w \
-t "$CHANNEL_OR_TAG" -n "$GCE_NODE_COUNT" -c 0 -P -u -f \
--skip-deploy-update \
--skip-remote-log-retrieval \
-a demo-testnet-solana-com \
${skipCreate:+-e} \
${maybeSkipStart:+-s} \
@ -436,7 +456,9 @@ deploy() {
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p demo-testnet-solana-com2 -C gce ${GCE_LOW_QUOTA_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$GCE_LOW_QUOTA_NODE_COUNT" -c 0 -P -f -x -w \
-t "$CHANNEL_OR_TAG" -n "$GCE_LOW_QUOTA_NODE_COUNT" -c 0 -P -f -x \
--skip-deploy-update \
--skip-remote-log-retrieval \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
@ -444,6 +466,41 @@ deploy() {
fi
)
;;
tds)
(
set -x
EXTERNAL_ACCOUNTS_FILE_URL=https://raw.githubusercontent.com/solana-labs/tour-de-sol/master/stage1/validator.yml
EXTERNAL_ACCOUNTS_FILE=/tmp/validator.yml
wget ${EXTERNAL_ACCOUNTS_FILE_URL} -O ${EXTERNAL_ACCOUNTS_FILE}
# Multiple V100 GPUs are available in us-west1, us-central1 and europe-west4
# shellcheck disable=SC2068
# shellcheck disable=SC2086
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p tds-solana-com -C gce \
-G "--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100" \
-d pd-ssd \
-z us-west1-a \
-z us-central1-a \
-z europe-west4-a \
-t "$CHANNEL_OR_TAG" -n "$GCE_NODE_COUNT" -c 1 -P -u \
-a tds-solana-com --letsencrypt tds.solana.com \
--hashes-per-tick auto \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--stake-internal-nodes 1000000000000 \
--external-accounts-file "$EXTERNAL_ACCOUNTS_FILE" \
--lamports 8589934592000000000 \
--skip-deploy-update \
--fullnode-additional-disk-size-gb 32000
)
;;
*)
echo "Error: Invalid TESTNET=$TESTNET"
exit 1

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "0.16.0"
version = "0.16.3"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -19,10 +19,10 @@ reqwest = "0.9.18"
serde = "1.0.92"
serde_derive = "1.0.92"
serde_json = "1.0.39"
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[dev-dependencies]
jsonrpc-core = "12.0.0"
jsonrpc-http-server = "12.0.0"
solana-logger = { path = "../logger", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.3" }

View File

@ -274,6 +274,40 @@ impl RpcClient {
self.get_account(pubkey).map(|account| account.lamports)
}
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> io::Result<Vec<(Pubkey, Account)>> {
let params = json!([format!("{}", pubkey)]);
let response = self
.client
.send(&RpcRequest::GetProgramAccounts, Some(params), 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}: {}", pubkey, err),
)
})?;
let accounts: Vec<(String, Account)> =
serde_json::from_value::<Vec<(String, Account)>>(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetProgramAccounts parse failure: {:?}", err),
)
})?;
println!("{:?}", accounts);
let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new();
for (string, account) in accounts.into_iter() {
let pubkey = string.parse().map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetProgramAccounts parse failure: {:?}", err),
)
})?;
pubkey_accounts.push((pubkey, account));
}
Ok(pubkey_accounts)
}
/// Request the transaction count. If the response packet is dropped by the network,
/// this method will try again 5 times.
pub fn get_transaction_count(&self) -> io::Result<u64> {

View File

@ -10,6 +10,7 @@ pub enum RpcRequest {
GetBalance,
GetClusterNodes,
GetNumBlocksSinceSignatureConfirmation,
GetProgramAccounts,
GetRecentBlockhash,
GetSignatureStatus,
GetSlot,
@ -38,6 +39,7 @@ impl RpcRequest {
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
"getNumBlocksSinceSignatureConfirmation"
}
RpcRequest::GetProgramAccounts => "getProgramAccounts",
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
RpcRequest::GetSignatureStatus => "getSignatureStatus",
RpcRequest::GetSlot => "getSlot",

View File

@ -1,7 +1,7 @@
[package]
name = "solana"
description = "Blockchain, Rebuilt for Scale"
version = "0.16.0"
version = "0.16.3"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -45,27 +45,27 @@ rocksdb = "0.11.0"
serde = "1.0.92"
serde_derive = "1.0.92"
serde_json = "1.0.39"
solana-budget-api = { path = "../programs/budget_api", version = "0.16.0" }
solana-budget-program = { path = "../programs/budget_program", version = "0.16.0" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.16.0" }
solana-client = { path = "../client", version = "0.16.0" }
solana-config-program = { path = "../programs/config_program", version = "0.16.0" }
solana-drone = { path = "../drone", version = "0.16.0" }
solana-budget-api = { path = "../programs/budget_api", version = "0.16.3" }
solana-budget-program = { path = "../programs/budget_program", version = "0.16.3" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.16.3" }
solana-client = { path = "../client", version = "0.16.3" }
solana-config-program = { path = "../programs/config_program", version = "0.16.3" }
solana-drone = { path = "../drone", version = "0.16.3" }
solana-ed25519-dalek = "0.2.0"
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.0" }
solana-kvstore = { path = "../kvstore", version = "0.16.0", optional = true }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-metrics = { path = "../metrics", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana-runtime = { path = "../runtime", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-stake-api = { path = "../programs/stake_api", version = "0.16.0" }
solana-stake-program = { path = "../programs/stake_program", version = "0.16.0" }
solana-storage-api = { path = "../programs/storage_api", version = "0.16.0" }
solana-storage-program = { path = "../programs/storage_program", version = "0.16.0" }
solana-vote-api = { path = "../programs/vote_api", version = "0.16.0" }
solana-vote-program = { path = "../programs/vote_program", version = "0.16.0" }
solana-vote-signer = { path = "../vote-signer", version = "0.16.0" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.3" }
solana-kvstore = { path = "../kvstore", version = "0.16.3", optional = true }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-metrics = { path = "../metrics", version = "0.16.3" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
solana-runtime = { path = "../runtime", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
solana-stake-api = { path = "../programs/stake_api", version = "0.16.3" }
solana-stake-program = { path = "../programs/stake_program", version = "0.16.3" }
solana-storage-api = { path = "../programs/storage_api", version = "0.16.3" }
solana-storage-program = { path = "../programs/storage_program", version = "0.16.3" }
solana-vote-api = { path = "../programs/vote_api", version = "0.16.3" }
solana-vote-program = { path = "../programs/vote_program", version = "0.16.3" }
solana-vote-signer = { path = "../vote-signer", version = "0.16.3" }
sys-info = "0.5.7"
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -329,8 +329,9 @@ impl BankForks {
names.sort();
let mut bank_maps = vec![];
let status_cache_rc = StatusCacheRc::default();
let id = (names[names.len() - 1] + 1) as usize;
let mut bank0 =
Bank::create_with_genesis(&genesis_block, account_paths.clone(), &status_cache_rc);
Bank::create_with_genesis(&genesis_block, account_paths.clone(), &status_cache_rc, id);
bank0.freeze();
let bank_root = BankForks::load_snapshots(
&names,

View File

@ -722,70 +722,6 @@ impl Blocktree {
iter.map(|(_, blob_data)| Blob::new(&blob_data))
}
/// Return an iterator for all the entries in the given file.
pub fn read_ledger(&self) -> Result<impl Iterator<Item = Entry>> {
use crate::entry::EntrySlice;
use std::collections::VecDeque;
struct EntryIterator {
db_iterator: Cursor<cf::Data>,
// TODO: remove me when replay_stage is iterating by block (Blocktree)
// this verification is duplicating that of replay_stage, which
// can do this in parallel
blockhash: Option<Hash>,
// https://github.com/rust-rocksdb/rust-rocksdb/issues/234
// rocksdb issue: the _blocktree member must be lower in the struct to prevent a crash
// when the db_iterator member above is dropped.
// _blocktree is unused, but dropping _blocktree results in a broken db_iterator
// you have to hold the database open in order to iterate over it, and in order
// for db_iterator to be able to run Drop
// _blocktree: Blocktree,
entries: VecDeque<Entry>,
}
impl Iterator for EntryIterator {
type Item = Entry;
fn next(&mut self) -> Option<Entry> {
if !self.entries.is_empty() {
return Some(self.entries.pop_front().unwrap());
}
if self.db_iterator.valid() {
if let Some(value) = self.db_iterator.value_bytes() {
if let Ok(next_entries) =
deserialize::<Vec<Entry>>(&value[BLOB_HEADER_SIZE..])
{
if let Some(blockhash) = self.blockhash {
if !next_entries.verify(&blockhash) {
return None;
}
}
self.db_iterator.next();
if next_entries.is_empty() {
return None;
}
self.entries = VecDeque::from(next_entries);
let entry = self.entries.pop_front().unwrap();
self.blockhash = Some(entry.hash);
return Some(entry);
}
}
}
None
}
}
let mut db_iterator = self.db.cursor::<cf::Data>()?;
db_iterator.seek_to_first();
Ok(EntryIterator {
entries: VecDeque::new(),
db_iterator,
blockhash: None,
})
}
pub fn get_slot_entries_with_blob_count(
&self,
slot: u64,
@ -1662,9 +1598,7 @@ pub fn tmp_copy_blocktree(from: &str, name: &str) -> String {
#[cfg(test)]
pub mod tests {
use super::*;
use crate::entry::{
create_ticks, make_tiny_test_entries, make_tiny_test_entries_from_hash, Entry, EntrySlice,
};
use crate::entry::{create_ticks, make_tiny_test_entries, Entry, EntrySlice};
use crate::erasure::{CodingGenerator, NUM_CODING, NUM_DATA};
use crate::packet;
use rand::seq::SliceRandom;
@ -2192,59 +2126,6 @@ pub mod tests {
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
}
#[test]
pub fn test_genesis_and_entry_iterator() {
let entries = make_tiny_test_entries_from_hash(&Hash::default(), 10);
let ledger_path = get_tmp_ledger_path("test_genesis_and_entry_iterator");
{
genesis(&ledger_path, &Keypair::new(), &entries).unwrap();
let ledger = Blocktree::open(&ledger_path).expect("open failed");
let read_entries: Vec<Entry> =
ledger.read_ledger().expect("read_ledger failed").collect();
assert!(read_entries.verify(&Hash::default()));
assert_eq!(entries, read_entries);
}
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
}
#[test]
pub fn test_entry_iterator_up_to_consumed() {
let entries = make_tiny_test_entries_from_hash(&Hash::default(), 3);
let ledger_path = get_tmp_ledger_path("test_genesis_and_entry_iterator");
{
// put entries except last 2 into ledger
genesis(&ledger_path, &Keypair::new(), &entries[..entries.len() - 2]).unwrap();
let ledger = Blocktree::open(&ledger_path).expect("open failed");
// now write the last entry, ledger has a hole in it one before the end
// +-+-+-+-+-+-+-+ +-+
// | | | | | | | | | |
// +-+-+-+-+-+-+-+ +-+
ledger
.write_entries(
0u64,
0,
(entries.len() - 1) as u64,
16,
&entries[entries.len() - 1..],
)
.unwrap();
let read_entries: Vec<Entry> =
ledger.read_ledger().expect("read_ledger failed").collect();
assert!(read_entries.verify(&Hash::default()));
// enumeration should stop at the hole
assert_eq!(entries[..entries.len() - 2].to_vec(), read_entries);
}
Blocktree::destroy(&ledger_path).expect("Expected successful database destruction");
}
#[test]
pub fn test_new_blobs_signal() {
// Initialize ledger

View File

@ -133,7 +133,7 @@ mod tests {
hasher.hash(&buf[..size]);
// golden needs to be updated if blob stuff changes....
let golden: Hash = "E2HZjSC6VgH4nmEiTbMDATTeBcFjwSYz7QYvU7doGNhD"
let golden: Hash = "37YzrTgiFRGQG1EoMZVecnGqxEK7UGxEQeBSdGMJcKqp"
.parse()
.unwrap();

View File

@ -748,7 +748,7 @@ impl ClusterInfo {
/// retransmit messages to a list of nodes
/// # Remarks
/// We need to avoid having obj locked while doing any io, such as the `send_to`
/// We need to avoid having obj locked while doing a io, such as the `send_to`
pub fn retransmit_to(
obj: &Arc<RwLock<Self>>,
peers: &[ContactInfo],
@ -1092,7 +1092,7 @@ impl ClusterInfo {
if caller.contact_info().is_none() {
return vec![];
}
let mut from = caller.contact_info().cloned().unwrap();
let from = caller.contact_info().unwrap();
if from.id == self_id {
warn!(
"PullRequest ignored, I'm talking to myself: me={} remoteme={}",
@ -1110,15 +1110,10 @@ impl ClusterInfo {
let len = data.len();
trace!("get updates since response {}", len);
let rsp = Protocol::PullResponse(self_id, data);
// The remote node may not know its public IP:PORT. Record what it looks like to us.
// This may or may not be correct for everybody, but it's better than leaving the remote with
// an unspecified address in our table
if from.gossip.ip().is_unspecified() {
inc_new_counter_debug!("cluster_info-window-request-updates-unspec-gossip", 1);
from.gossip = *from_addr;
}
// The remote node may not know its public IP:PORT. Instead of responding to the caller's
// gossip addr, respond to the origin addr.
inc_new_counter_debug!("cluster_info-pull_request-rsp", len);
to_shared_blob(rsp, from.gossip).ok().into_iter().collect()
to_shared_blob(rsp, *from_addr).ok().into_iter().collect()
}
fn handle_pull_response(me: &Arc<RwLock<Self>>, from: &Pubkey, data: Vec<CrdsValue>) {
let len = data.len();

View File

@ -260,14 +260,16 @@ impl ClusterInfoRepairListener {
num_slots_to_repair: usize,
epoch_schedule: &EpochSchedule,
) -> Result<()> {
let slot_iter = blocktree.rooted_slot_iterator(repairee_epoch_slots.root + 1);
let slot_iter = blocktree.rooted_slot_iterator(repairee_epoch_slots.root);
if slot_iter.is_err() {
warn!("Root for repairee is on different fork OR replay_stage hasn't marked this slot as root yet");
info!(
"Root for repairee is on different fork. My root: {}, repairee_root: {}",
my_root, repairee_epoch_slots.root
);
return Ok(());
}
let slot_iter = slot_iter?;
let mut slot_iter = slot_iter?;
let mut total_data_blobs_sent = 0;
let mut total_coding_blobs_sent = 0;
@ -276,6 +278,10 @@ impl ClusterInfoRepairListener {
epoch_schedule.get_stakers_epoch(repairee_epoch_slots.root);
let max_confirmed_repairee_slot =
epoch_schedule.get_last_slot_in_epoch(max_confirmed_repairee_epoch);
// Skip the first slot in the iterator because we know it's the root slot which the repairee
// already has
slot_iter.next();
for (slot, slot_meta) in slot_iter {
if slot > my_root
|| num_slots_repaired >= num_slots_to_repair

View File

@ -226,11 +226,13 @@ impl CodingGenerator {
let index = data_blob.index();
let slot = data_blob.slot();
let id = data_blob.id();
let version = data_blob.version();
let mut coding_blob = Blob::default();
coding_blob.set_index(index);
coding_blob.set_slot(slot);
coding_blob.set_id(&id);
coding_blob.set_version(version);
coding_blob.set_size(max_data_size);
coding_blob.set_coding();

View File

@ -341,7 +341,8 @@ macro_rules! range {
const SIGNATURE_RANGE: std::ops::Range<usize> = range!(0, Signature);
const FORWARDED_RANGE: std::ops::Range<usize> = range!(SIGNATURE_RANGE.end, bool);
const PARENT_RANGE: std::ops::Range<usize> = range!(FORWARDED_RANGE.end, u64);
const SLOT_RANGE: std::ops::Range<usize> = range!(PARENT_RANGE.end, u64);
const VERSION_RANGE: std::ops::Range<usize> = range!(PARENT_RANGE.end, u64);
const SLOT_RANGE: std::ops::Range<usize> = range!(VERSION_RANGE.end, u64);
const INDEX_RANGE: std::ops::Range<usize> = range!(SLOT_RANGE.end, u64);
const ID_RANGE: std::ops::Range<usize> = range!(INDEX_RANGE.end, Pubkey);
const FLAGS_RANGE: std::ops::Range<usize> = range!(ID_RANGE.end, u32);
@ -391,6 +392,12 @@ impl Blob {
pub fn set_parent(&mut self, ix: u64) {
LittleEndian::write_u64(&mut self.data[PARENT_RANGE], ix);
}
pub fn version(&self) -> u64 {
LittleEndian::read_u64(&self.data[VERSION_RANGE])
}
pub fn set_version(&mut self, version: u64) {
LittleEndian::write_u64(&mut self.data[VERSION_RANGE], version);
}
pub fn slot(&self) -> u64 {
LittleEndian::read_u64(&self.data[SLOT_RANGE])
}
@ -862,4 +869,12 @@ mod tests {
b.sign(&k);
assert!(b.verify());
}
#[test]
fn test_version() {
let mut b = Blob::default();
assert_eq!(b.version(), 0);
b.set_version(1);
assert_eq!(b.version(), 1);
}
}

View File

@ -23,7 +23,6 @@ use solana_sdk::account_utils::State;
use solana_sdk::client::{AsyncClient, SyncClient};
use solana_sdk::hash::{Hash, Hasher};
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::timing::timestamp;
use solana_sdk::transaction::Transaction;
@ -303,7 +302,7 @@ impl Replicator {
})
}
pub fn run(&mut self, mining_pool_pubkey: Pubkey) {
pub fn run(&mut self) {
info!("waiting for ledger download");
self.thread_handles.pop().unwrap().join().unwrap();
self.encrypt_ledger()
@ -330,11 +329,11 @@ impl Replicator {
}
};
self.blockhash = storage_blockhash;
self.redeem_rewards(&mining_pool_pubkey);
self.redeem_rewards();
}
}
fn redeem_rewards(&self, mining_pool_pubkey: &Pubkey) {
fn redeem_rewards(&self) {
let nodes = self.cluster_info.read().unwrap().tvu_peers();
let client = crate::gossip_service::get_client(&nodes);
@ -347,7 +346,6 @@ impl Replicator {
let ix = storage_instruction::claim_reward(
&self.keypair.pubkey(),
&self.storage_keypair.pubkey(),
mining_pool_pubkey,
);
let message = Message::new_with_payer(vec![ix], Some(&self.keypair.pubkey()));
if let Err(e) = client.send_message(&[&self.keypair], message) {
@ -468,7 +466,15 @@ impl Replicator {
// check if the storage account exists
let balance = client.poll_get_balance(&storage_keypair.pubkey());
if balance.is_err() || balance.unwrap() == 0 {
let (blockhash, _fee_calculator) = client.get_recent_blockhash().expect("blockhash");
let blockhash = match client.get_recent_blockhash() {
Ok((blockhash, _)) => blockhash,
Err(_) => {
return Err(Error::IO(<io::Error>::new(
io::ErrorKind::Other,
"unable to get recent blockhash, can't submit proof",
)))
}
};
let ix = storage_instruction::create_replicator_storage_account(
&keypair.pubkey(),
@ -495,16 +501,25 @@ impl Replicator {
// No point if we've got no storage account...
let nodes = self.cluster_info.read().unwrap().tvu_peers();
let client = crate::gossip_service::get_client(&nodes);
assert!(
client
.poll_get_balance(&self.storage_keypair.pubkey())
.unwrap()
> 0
);
let storage_balance = client.poll_get_balance(&self.storage_keypair.pubkey());
if storage_balance.is_err() || storage_balance.unwrap() == 0 {
error!("Unable to submit mining proof, no storage account");
return;
}
// ...or no lamports for fees
assert!(client.poll_get_balance(&self.keypair.pubkey()).unwrap() > 0);
let balance = client.poll_get_balance(&self.keypair.pubkey());
if balance.is_err() || balance.unwrap() == 0 {
error!("Unable to submit mining proof, insufficient Replicator Account balance");
return;
}
let (blockhash, _) = client.get_recent_blockhash().expect("No recent blockhash");
let blockhash = match client.get_recent_blockhash() {
Ok((blockhash, _)) => blockhash,
Err(_) => {
error!("unable to get recent blockhash, can't submit proof");
return;
}
};
let instruction = storage_instruction::mining_proof(
&self.storage_keypair.pubkey(),
self.sha_state,
@ -518,14 +533,14 @@ impl Replicator {
message,
blockhash,
);
client
.send_and_confirm_transaction(
&[&self.keypair, &self.storage_keypair],
&mut transaction,
10,
0,
)
.expect("transfer didn't work!");
if let Err(err) = client.send_and_confirm_transaction(
&[&self.keypair, &self.storage_keypair],
&mut transaction,
10,
0,
) {
error!("Error: {:?}; while sending mining proof", err);
}
}
pub fn close(self) {

View File

@ -70,6 +70,15 @@ impl JsonRpcRequestProcessor {
.ok_or_else(Error::invalid_request)
}
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Result<Vec<(String, Account)>> {
Ok(self
.bank()
.get_program_accounts(&program_id)
.into_iter()
.map(|(pubkey, account)| (pubkey.to_string(), account))
.collect())
}
pub fn get_balance(&self, pubkey: &Pubkey) -> u64 {
self.bank().get_balance(&pubkey)
}
@ -196,8 +205,8 @@ pub struct RpcVoteAccountInfo {
/// The current stake, in lamports, delegated to this vote account
pub stake: u64,
/// A 32-bit integer used as a fraction (commission/MAX_U32) for rewards payout
pub commission: u32,
/// An 8-bit integer used as a fraction (commission/MAX_U8) for rewards payout
pub commission: u8,
}
#[rpc(server)]
@ -210,6 +219,9 @@ pub trait RpcSol {
#[rpc(meta, name = "getAccountInfo")]
fn get_account_info(&self, _: Self::Metadata, _: String) -> Result<Account>;
#[rpc(meta, name = "getProgramAccounts")]
fn get_program_accounts(&self, _: Self::Metadata, _: String) -> Result<Vec<(String, Account)>>;
#[rpc(meta, name = "getBalance")]
fn get_balance(&self, _: Self::Metadata, _: String) -> Result<u64>;
@ -297,6 +309,19 @@ impl RpcSol for RpcSolImpl {
.get_account_info(&pubkey)
}
fn get_program_accounts(
&self,
meta: Self::Metadata,
id: String,
) -> Result<Vec<(String, Account)>> {
debug!("get_program_accounts rpc request received: {:?}", id);
let program_id = verify_pubkey(id)?;
meta.request_processor
.read()
.unwrap()
.get_program_accounts(&program_id)
}
fn get_balance(&self, meta: Self::Metadata, id: String) -> Result<u64> {
debug!("get_balance rpc request received: {:?}", id);
let pubkey = verify_pubkey(id)?;
@ -535,7 +560,7 @@ mod tests {
fn start_rpc_handler_with_tx(
pubkey: &Pubkey,
) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair, Pubkey) {
) -> (MetaIoHandler<Meta>, Meta, Arc<Bank>, Hash, Keypair, Pubkey) {
let (bank_forks, alice) = new_bank_forks();
let bank = bank_forks.read().unwrap().working_bank();
let exit = Arc::new(AtomicBool::new(false));
@ -567,7 +592,7 @@ mod tests {
request_processor,
cluster_info,
};
(io, meta, blockhash, alice, leader.id)
(io, meta, bank, blockhash, alice, leader.id)
}
#[test]
@ -595,7 +620,8 @@ mod tests {
#[test]
fn test_rpc_get_balance() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"#,
@ -613,7 +639,8 @@ mod tests {
#[test]
fn test_rpc_get_cluster_nodes() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getClusterNodes"}}"#);
let res = io.handle_request_sync(&req, meta);
@ -633,7 +660,8 @@ mod tests {
#[test]
fn test_rpc_get_slot_leader() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getSlotLeader"}}"#);
let res = io.handle_request_sync(&req, meta);
@ -649,7 +677,8 @@ mod tests {
#[test]
fn test_rpc_get_tx_count() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"#);
let res = io.handle_request_sync(&req, meta);
@ -664,7 +693,8 @@ mod tests {
#[test]
fn test_rpc_get_total_supply() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTotalSupply"}}"#);
let rep = io.handle_request_sync(&req, meta);
@ -689,7 +719,8 @@ mod tests {
#[test]
fn test_rpc_get_account_info() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}"]}}"#,
@ -713,10 +744,46 @@ mod tests {
assert_eq!(expected, result);
}
#[test]
fn test_rpc_get_program_accounts() {
let bob = Keypair::new();
let (io, meta, bank, blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob.pubkey());
let new_program_id = Pubkey::new_rand();
let tx = system_transaction::assign(&bob, blockhash, &new_program_id);
bank.process_transaction(&tx).unwrap();
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getProgramAccounts","params":["{}"]}}"#,
new_program_id
);
let res = io.handle_request_sync(&req, meta);
let expected = format!(
r#"{{
"jsonrpc":"2.0",
"result":[["{}", {{
"owner": {:?},
"lamports": 20,
"data": [],
"executable": false
}}]],
"id":1}}
"#,
bob.pubkey(),
new_program_id.as_ref()
);
let expected: Response =
serde_json::from_str(&expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
assert_eq!(expected, result);
}
#[test]
fn test_rpc_confirm_tx() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, blockhash, alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, blockhash, alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
let req = format!(
@ -735,7 +802,8 @@ mod tests {
#[test]
fn test_rpc_get_signature_status() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, blockhash, alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, blockhash, alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
let req = format!(
@ -799,7 +867,8 @@ mod tests {
#[test]
fn test_rpc_get_recent_blockhash() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}}"#);
let res = io.handle_request_sync(&req, meta);
@ -824,7 +893,8 @@ mod tests {
#[test]
fn test_rpc_fail_request_airdrop() {
let bob_pubkey = Pubkey::new_rand();
let (io, meta, _blockhash, _alice, _leader_pubkey) = start_rpc_handler_with_tx(&bob_pubkey);
let (io, meta, _bank, _blockhash, _alice, _leader_pubkey) =
start_rpc_handler_with_tx(&bob_pubkey);
// Expect internal error because no drone is available
let req = format!(

View File

@ -118,6 +118,7 @@ fn test_leader_failure_4() {
);
}
#[test]
#[ignore]
fn test_two_unbalanced_stakes() {
solana_logger::setup();
let mut validator_config = ValidatorConfig::default();

View File

@ -1,6 +1,6 @@
[package]
name = "solana-drone"
version = "0.16.0"
version = "0.16.3"
description = "Solana Drone"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -20,9 +20,9 @@ clap = "2.33"
log = "0.4.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../logger", version = "0.16.0" }
solana-metrics = { path = "../metrics", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-metrics = { path = "../metrics", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-genesis"
description = "Blockchain, Rebuilt for Scale"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -15,24 +15,24 @@ serde = "1.0.92"
serde_derive = "1.0.92"
serde_json = "1.0.39"
serde_yaml = "0.8.9"
solana = { path = "../core", version = "0.16.0" }
solana-bpf-loader-api = { path = "../programs/bpf_loader_api", version = "0.16.0" }
solana-bpf-loader-program = { path = "../programs/bpf_loader_program", version = "0.16.0" }
solana-budget-api = { path = "../programs/budget_api", version = "0.16.0" }
solana-budget-program = { path = "../programs/budget_program", version = "0.16.0" }
solana-config-api = { path = "../programs/config_api", version = "0.16.0" }
solana-config-program = { path = "../programs/config_program", version = "0.16.0" }
solana-exchange-api = { path = "../programs/exchange_api", version = "0.16.0" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-stake-api = { path = "../programs/stake_api", version = "0.16.0" }
solana-stake-program = { path = "../programs/stake_program", version = "0.16.0" }
solana-storage-api = { path = "../programs/storage_api", version = "0.16.0" }
solana-storage-program = { path = "../programs/storage_program", version = "0.16.0" }
solana-token-api = { path = "../programs/token_api", version = "0.16.0" }
solana-token-program = { path = "../programs/token_program", version = "0.16.0" }
solana-vote-api = { path = "../programs/vote_api", version = "0.16.0" }
solana-vote-program = { path = "../programs/vote_program", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-bpf-loader-api = { path = "../programs/bpf_loader_api", version = "0.16.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader_program", version = "0.16.3" }
solana-budget-api = { path = "../programs/budget_api", version = "0.16.3" }
solana-budget-program = { path = "../programs/budget_program", version = "0.16.3" }
solana-config-api = { path = "../programs/config_api", version = "0.16.3" }
solana-config-program = { path = "../programs/config_program", version = "0.16.3" }
solana-exchange-api = { path = "../programs/exchange_api", version = "0.16.3" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
solana-stake-api = { path = "../programs/stake_api", version = "0.16.3" }
solana-stake-program = { path = "../programs/stake_program", version = "0.16.3" }
solana-storage-api = { path = "../programs/storage_api", version = "0.16.3" }
solana-storage-program = { path = "../programs/storage_program", version = "0.16.3" }
solana-token-api = { path = "../programs/token_api", version = "0.16.3" }
solana-token-program = { path = "../programs/token_program", version = "0.16.3" }
solana-vote-api = { path = "../programs/vote_api", version = "0.16.3" }
solana-vote-program = { path = "../programs/vote_program", version = "0.16.3" }
[dev-dependencies]
hashbrown = "0.3.0"

View File

@ -147,14 +147,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.required(true)
.help("Path to file containing the bootstrap leader's storage keypair"),
)
.arg(
Arg::with_name("storage_mining_pool_lamports")
.long("storage-mining-pool-lamports")
.value_name("LAMPORTS")
.takes_value(true)
.required(true)
.help("Number of lamports to assign to the storage mining pool"),
)
.arg(
Arg::with_name("bootstrap_leader_lamports")
.long("bootstrap-leader-lamports")
@ -261,7 +253,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let bootstrap_leader_lamports = value_t_or_exit!(matches, "bootstrap_leader_lamports", u64);
let bootstrap_leader_stake_lamports =
value_t_or_exit!(matches, "bootstrap_leader_stake_lamports", u64);
let storage_pool_lamports = value_t_or_exit!(matches, "storage_mining_pool_lamports", u64);
let bootstrap_leader_keypair = read_keypair(bootstrap_leader_keypair_file)?;
let bootstrap_vote_keypair = read_keypair(bootstrap_vote_keypair_file)?;
@ -306,12 +297,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
1,
),
),
(
"StorageMiningPoo111111111111111111111111111"
.parse()
.unwrap(),
storage_contract::create_mining_pool_account(storage_pool_lamports),
),
])
.native_instruction_processors(&[
solana_bpf_loader_program!(),
@ -370,6 +355,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
builder = append_primordial_accounts(file, AccountFileFormat::Keypair, builder)?;
}
// add the reward pools
builder = solana_storage_api::rewards_pools::genesis(builder);
builder = solana_stake_api::rewards_pools::genesis(builder);
create_new_ledger(ledger_path, &builder.build())?;
Ok(())
}
@ -524,6 +513,8 @@ mod tests {
)
.expect("builder");
builder = solana_storage_api::rewards_pools::genesis(builder);
remove_file(path).unwrap();
let genesis_block = builder.clone().build();

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-gossip"
description = "Blockchain, Rebuilt for Scale"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,10 +11,10 @@ homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
env_logger = "0.6.1"
solana = { path = "../core", version = "0.16.0" }
solana-client = { path = "../client", version = "0.16.0" }
solana-netutil = { path = "../netutil", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-client = { path = "../client", version = "0.16.3" }
solana-netutil = { path = "../netutil", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[features]
cuda = []

View File

@ -41,12 +41,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
SubCommand::with_name("spy")
.about("Monitor the gossip entrypoint")
.setting(AppSettings::DisableVersion)
.arg(
clap::Arg::with_name("pull_only")
.long("pull-only")
.takes_value(false)
.help("Use a partial gossip node (Pulls only) to spy on the cluster. By default it will use a full fledged gossip node (Pushes and Pulls). Useful when behind a NAT"),
)
.arg(
Arg::with_name("num_nodes")
.short("N")
@ -120,9 +114,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.value_of("node_pubkey")
.map(|pubkey_str| pubkey_str.parse::<Pubkey>().unwrap());
let gossip_addr = if matches.is_present("pull_only") {
None
} else {
let gossip_addr = {
let mut addr = socketaddr_any!();
addr.set_ip(
solana_netutil::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| {

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-install"
description = "The solana cluster software installer"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -13,25 +13,28 @@ cuda = []
[dependencies]
atty = "0.2.11"
bincode = "1.1.4"
bs58 = "0.2.0"
bzip2 = "0.3.3"
chrono = { version = "0.4.0", features = ["serde"] }
clap = { version = "2.33.0" }
console = "0.7.5"
console = "0.7.7"
ctrlc = { version = "3.1.3", features = ["termination"] }
dirs = "2.0.1"
indicatif = "0.11.0"
lazy_static = "1.3.0"
log = "0.4.2"
nix = "0.14.1"
reqwest = "0.9.18"
ring = "0.13.2"
serde = "1.0.92"
serde_derive = "1.0.92"
serde_yaml = "0.8.9"
solana-client = { path = "../client", version = "0.16.0" }
solana-config-api = { path = "../programs/config_api", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-client = { path = "../client", version = "0.16.3" }
solana-config-api = { path = "../programs/config_api", version = "0.16.3" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
tar = "0.4.26"
tempdir = "0.3.7"
url = "1.7.2"

View File

@ -1,11 +1,12 @@
use crate::config::Config;
use crate::stop_process::stop_process;
use crate::update_manifest::{SignedUpdateManifest, UpdateManifest};
use chrono::{Local, TimeZone};
use console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle};
use ring::digest::{Context, Digest, SHA256};
use solana_client::rpc_client::RpcClient;
use solana_config_api::config_instruction;
use solana_config_api::config_instruction::{self, ConfigKeys};
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil, Signable};
@ -13,7 +14,7 @@ use solana_sdk::transaction::Transaction;
use std::fs::{self, File};
use std::io::{self, BufReader, Read};
use std::path::{Path, PathBuf};
use std::thread::sleep;
use std::sync::mpsc;
use std::time::SystemTime;
use std::time::{Duration, Instant};
use tempdir::TempDir;
@ -202,7 +203,8 @@ fn new_update_manifest(
let new_account = config_instruction::create_account::<SignedUpdateManifest>(
&from_keypair.pubkey(),
&update_manifest_keypair.pubkey(),
1, // lamports
1, // lamports
vec![], // additional keys
);
let mut transaction = Transaction::new_unsigned_instructions(vec![new_account]);
transaction.sign(&[from_keypair], recent_blockhash);
@ -224,6 +226,8 @@ fn store_update_manifest(
let signers = [from_keypair, update_manifest_keypair];
let instruction = config_instruction::store::<SignedUpdateManifest>(
&update_manifest_keypair.pubkey(),
true, // update_manifest_keypair is signer
vec![], // additional keys
update_manifest,
);
@ -238,9 +242,10 @@ fn get_update_manifest(
rpc_client: &RpcClient,
update_manifest_pubkey: &Pubkey,
) -> Result<UpdateManifest, String> {
let data = rpc_client
let mut data = rpc_client
.get_account_data(update_manifest_pubkey)
.map_err(|err| format!("Unable to fetch update manifest: {}", err))?;
data.split_off(ConfigKeys::serialized_size(vec![]));
let signed_update_manifest =
SignedUpdateManifest::deserialize(update_manifest_pubkey, &data)
@ -514,7 +519,7 @@ pub fn init(
false
};
if !path_modified {
if !path_modified && !no_modify_path {
check_env_path_for_bin_dir(&config);
}
Ok(())
@ -748,7 +753,11 @@ pub fn run(
) -> Result<(), String> {
let config = Config::load(config_file)?;
let full_program_path = config.active_release_bin_dir().join(program_name);
let mut full_program_path = config.active_release_bin_dir().join(program_name);
if cfg!(windows) && full_program_path.extension().is_none() {
full_program_path.set_extension("exe");
}
if !full_program_path.exists() {
Err(format!(
"{} does not exist",
@ -758,6 +767,13 @@ pub fn run(
let mut child_option: Option<std::process::Child> = None;
let mut now = Instant::now();
let (signal_sender, signal_receiver) = mpsc::channel();
ctrlc::set_handler(move || {
let _ = signal_sender.send(());
})
.expect("Error setting Ctrl-C handler");
loop {
child_option = match child_option {
Some(mut child) => match child.try_wait() {
@ -793,7 +809,9 @@ pub fn run(
Ok(true) => {
// Update successful, kill current process so it will be restart
if let Some(ref mut child) = child_option {
println!("Killing program: {:?}", child.kill());
stop_process(child).unwrap_or_else(|err| {
eprintln!("Failed to stop child: {:?}", err);
});
}
}
Ok(false) => {} // No update available
@ -803,6 +821,15 @@ pub fn run(
};
now = Instant::now();
}
sleep(Duration::from_secs(1));
if let Ok(()) = signal_receiver.recv_timeout(Duration::from_secs(1)) {
// Handle SIGTERM...
if let Some(ref mut child) = child_option {
stop_process(child).unwrap_or_else(|err| {
eprintln!("Failed to stop child: {:?}", err);
});
}
std::process::exit(0);
}
}
}

View File

@ -8,6 +8,7 @@ mod build_env;
mod command;
mod config;
mod defaults;
mod stop_process;
mod update_manifest;
// Return an error if a url cannot be parsed.

View File

@ -1,22 +1,21 @@
use atty;
use std::process::exit;
#[cfg(windows)]
fn press_enter() {
// On windows, where installation happens in a console that may have opened just for this
// purpose, give the user an opportunity to see the error before the window closes.
println!();
println!("Press the Enter key to continue.");
if cfg!(windows) && atty::is(atty::Stream::Stdin) {
println!();
println!("Press the Enter key to continue.");
use std::io::BufRead;
let stdin = std::io::stdin();
let stdin = stdin.lock();
let mut lines = stdin.lines();
lines.next();
use std::io::BufRead;
let stdin = std::io::stdin();
let stdin = stdin.lock();
let mut lines = stdin.lines();
lines.next();
}
}
#[cfg(not(windows))]
fn press_enter() {}
fn main() {
solana_install::main_init().unwrap_or_else(|err| {
println!("Error: {}", err);

View File

@ -0,0 +1,67 @@
use std::io;
use std::process::Child;
fn kill_process(process: &mut Child) -> Result<(), io::Error> {
if let Ok(()) = process.kill() {
process.wait()?;
} else {
println!("Process {} has already exited", process.id());
}
Ok(())
}
#[cfg(windows)]
pub fn stop_process(process: &mut Child) -> Result<(), io::Error> {
kill_process(process)
}
#[cfg(not(windows))]
pub fn stop_process(process: &mut Child) -> Result<(), io::Error> {
use nix::errno::Errno::{EINVAL, EPERM, ESRCH};
use nix::sys::signal::{kill, Signal};
use nix::unistd::Pid;
use nix::Error::Sys;
use std::io::ErrorKind;
use std::thread;
use std::time::{Duration, Instant};
let nice_wait = Duration::from_secs(5);
let pid = Pid::from_raw(process.id() as i32);
match kill(pid, Signal::SIGINT) {
Ok(()) => {
let expire = Instant::now() + nice_wait;
while let Ok(None) = process.try_wait() {
if Instant::now() > expire {
break;
}
thread::sleep(nice_wait / 10);
}
if let Ok(None) = process.try_wait() {
kill_process(process)?;
}
}
Err(Sys(EINVAL)) => {
println!("Invalid signal. Killing process {}", pid);
kill_process(process)?;
}
Err(Sys(EPERM)) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Insufficient permissions to signal process {}", pid),
));
}
Err(Sys(ESRCH)) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Process {} does not exist", pid),
));
}
Err(e) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Unexpected error {}", e),
));
}
};
Ok(())
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-keygen"
version = "0.16.0"
version = "0.16.3"
description = "Solana key generation utility"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -15,7 +15,7 @@ cuda = []
[dependencies]
clap = "2.33"
dirs = "2.0.1"
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[[bin]]
name = "solana-keygen"

View File

@ -1,7 +1,7 @@
[package]
name = "solana-kvstore"
description = "Embedded Key-Value store for solana"
version = "0.16.0"
version = "0.16.3"
homepage = "https://solana.com/"
repository = "https://github.com/solana-labs/solana"
authors = ["Solana Maintainers <maintainers@solana.com>"]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-ledger-tool"
description = "Blockchain, Rebuilt for Scale"
version = "0.16.0"
version = "0.16.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,10 +11,10 @@ homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
serde_json = "1.0.39"
solana = { path = "../core", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.0" }
solana-runtime = { path = "../runtime", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana = { path = "../core", version = "0.16.3" }
solana-logger = { path = "../logger", version = "0.16.3" }
solana-runtime = { path = "../runtime", version = "0.16.3" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[dev-dependencies]
assert_cmd = "0.11"

View File

@ -1,13 +1,66 @@
use clap::{crate_description, crate_name, crate_version, App, Arg, SubCommand};
use clap::{crate_description, crate_name, crate_version, value_t, App, Arg, SubCommand};
use solana::blocktree::Blocktree;
use solana::blocktree_processor::process_blocktree;
use solana_sdk::genesis_block::GenesisBlock;
use std::io::{stdout, Write};
use std::process::exit;
#[derive(PartialEq)]
enum LedgerOutputMethod {
Print,
Json,
}
fn output_ledger(blocktree: Blocktree, starting_slot: u64, method: LedgerOutputMethod) {
let rooted_slot_iterator = blocktree
.rooted_slot_iterator(starting_slot)
.unwrap_or_else(|err| {
eprintln!(
"Failed to load entries starting from slot {}: {:?}",
starting_slot, err
);
exit(1);
});
if method == LedgerOutputMethod::Json {
stdout().write_all(b"{\"ledger\":[\n").expect("open array");
}
for (slot, slot_meta) in rooted_slot_iterator {
match method {
LedgerOutputMethod::Print => println!("Slot {}", slot),
LedgerOutputMethod::Json => {
serde_json::to_writer(stdout(), &slot_meta).expect("serialize slot_meta");
stdout().write_all(b",\n").expect("newline");
}
}
let entries = blocktree
.get_slot_entries(slot, 0, None)
.unwrap_or_else(|err| {
eprintln!("Failed to load entries for slot {}: {:?}", slot, err);
exit(1);
});
for entry in entries {
match method {
LedgerOutputMethod::Print => println!("{:?}", entry),
LedgerOutputMethod::Json => {
serde_json::to_writer(stdout(), &entry).expect("serialize entry");
stdout().write_all(b",\n").expect("newline");
}
}
}
}
if method == LedgerOutputMethod::Json {
stdout().write_all(b"\n]}\n").expect("close array");
}
}
fn main() {
solana_logger::setup();
let matches = App::new(crate_name!()).about(crate_description!())
let matches = App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.arg(
Arg::with_name("ledger")
@ -19,26 +72,12 @@ fn main() {
.help("Use directory for ledger location"),
)
.arg(
Arg::with_name("head")
.short("n")
.long("head")
Arg::with_name("starting_slot")
.long("starting-slot")
.value_name("NUM")
.takes_value(true)
.help("Limit to at most the first NUM entries in ledger\n (only applies to print and json commands)"),
)
.arg(
Arg::with_name("min-hashes")
.short("h")
.long("min-hashes")
.value_name("NUM")
.takes_value(true)
.help("Skip entries with fewer than NUM hashes\n (only applies to print and json commands)"),
)
.arg(
Arg::with_name("continue")
.short("c")
.long("continue")
.help("Continue verify even if verification fails"),
.default_value("0")
.help("Start at this slot (only applies to print and json commands)"),
)
.subcommand(SubCommand::with_name("print").about("Print the ledger"))
.subcommand(SubCommand::with_name("json").about("Print the ledger in JSON format"))
@ -63,63 +102,27 @@ fn main() {
}
};
let entries = match blocktree.read_ledger() {
Ok(entries) => entries,
Err(err) => {
eprintln!("Failed to read ledger at {}: {}", ledger_path, err);
exit(1);
}
};
let head = match matches.value_of("head") {
Some(head) => head.parse().expect("please pass a number for --head"),
None => <usize>::max_value(),
};
let min_hashes = match matches.value_of("min-hashes") {
Some(hashes) => hashes
.parse()
.expect("please pass a number for --min-hashes"),
None => 0,
} as u64;
let starting_slot = value_t!(matches, "starting_slot", u64).unwrap_or_else(|e| e.exit());
match matches.subcommand() {
("print", _) => {
for (i, entry) in entries.enumerate() {
if i >= head {
break;
}
if entry.num_hashes < min_hashes {
continue;
}
println!("{:?}", entry);
}
output_ledger(blocktree, starting_slot, LedgerOutputMethod::Print);
}
("json", _) => {
stdout().write_all(b"{\"ledger\":[\n").expect("open array");
for (i, entry) in entries.enumerate() {
if i >= head {
break;
}
if entry.num_hashes < min_hashes {
continue;
}
serde_json::to_writer(stdout(), &entry).expect("serialize");
stdout().write_all(b",\n").expect("newline");
}
stdout().write_all(b"\n]}\n").expect("close array");
output_ledger(blocktree, starting_slot, LedgerOutputMethod::Json);
}
("verify", _) => match process_blocktree(&genesis_block, &blocktree, None) {
Ok((_bank_forks, bank_forks_info, _)) => {
println!("{:?}", bank_forks_info);
("verify", _) => {
println!("Verifying ledger...");
match process_blocktree(&genesis_block, &blocktree, None) {
Ok((_bank_forks, bank_forks_info, _)) => {
println!("{:?}", bank_forks_info);
}
Err(err) => {
eprintln!("Ledger verification failed: {:?}", err);
exit(1);
}
}
Err(err) => {
eprintln!("Ledger verification failed: {:?}", err);
exit(1);
}
},
}
("", _) => {
eprintln!("{}", matches.usage());
exit(1);

View File

@ -45,20 +45,5 @@ fn nominal() {
// Print everything
let output = run_ledger_tool(&["-l", &ledger_path, "print"]);
assert!(output.status.success());
assert_eq!(count_newlines(&output.stdout), ticks);
// Only print the first 5 items
let output = run_ledger_tool(&["-l", &ledger_path, "-n", "5", "print"]);
assert!(output.status.success());
assert_eq!(count_newlines(&output.stdout), 5);
// Skip entries with no hashes
let output = run_ledger_tool(&["-l", &ledger_path, "-h", "1", "print"]);
assert!(output.status.success());
assert_eq!(count_newlines(&output.stdout), ticks);
// Skip entries with fewer than 2 hashes (skip everything)
let output = run_ledger_tool(&["-l", &ledger_path, "-h", "2", "print"]);
assert!(output.status.success());
assert_eq!(count_newlines(&output.stdout), 0);
assert_eq!(count_newlines(&output.stdout), ticks + 1);
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-logger"
version = "0.16.0"
version = "0.16.3"
description = "Solana Logger"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-merkle-tree"
version = "0.16.0"
version = "0.16.3"
description = "Solana Merkle Tree"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -9,7 +9,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
[dev-dependencies]
hex = "0.3.2"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-metrics"
version = "0.16.0"
version = "0.16.3"
description = "Solana Metrics"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,7 +14,7 @@ influx_db_client = "0.3.6"
lazy_static = "1.3.0"
log = "0.4.2"
reqwest = "0.9.18"
solana-sdk = { path = "../sdk", version = "0.16.0" }
solana-sdk = { path = "../sdk", version = "0.16.3" }
sys-info = "0.5.7"
[dev-dependencies]

View File

@ -72,6 +72,14 @@ SOLANA_RSYNC_CONFIG_DIR=$SOLANA_ROOT/config
# Configuration that remains local
SOLANA_CONFIG_DIR=$SOLANA_ROOT/config-local
# If there is a secondary disk, symlink the config-local dir there
SECONDARY_DISK_MOUNT_POINT=/mnt/extra-disk
if [[ -d $SECONDARY_DISK_MOUNT_POINT ]]; then
mkdir -p $SECONDARY_DISK_MOUNT_POINT/config-local
mkdir -p "$SOLANA_ROOT"
ln -s $SECONDARY_DISK_MOUNT_POINT/config-local "$SOLANA_ROOT"
fi
default_arg() {
declare name=$1
declare value=$2
@ -88,3 +96,18 @@ default_arg() {
args+=("$name")
fi
}
replace_arg() {
declare name=$1
declare value=$2
default_arg "$name" "$value"
declare index=0
for arg in "${args[@]}"; do
index=$((index + 1))
if [[ $arg = "$name" ]]; then
args[$index]="$value"
fi
done
}

View File

@ -9,6 +9,7 @@ source "$here"/common.sh
# shellcheck source=scripts/oom-score-adj.sh
source "$here"/../scripts/oom-score-adj.sh
fullnode_usage() {
if [[ -n $1 ]]; then
echo "$*"
@ -76,24 +77,8 @@ rsync_url() { # adds the 'rsync://` prefix to URLs that need it
setup_validator_accounts() {
declare entrypoint_ip=$1
declare node_keypair_path=$2
declare vote_keypair_path=$3
declare stake_keypair_path=$4
declare storage_keypair_path=$5
declare node_lamports=$6
declare stake_lamports=$7
declare node_pubkey
node_pubkey=$($solana_keygen pubkey "$node_keypair_path")
declare vote_pubkey
vote_pubkey=$($solana_keygen pubkey "$vote_keypair_path")
declare stake_pubkey
stake_pubkey=$($solana_keygen pubkey "$stake_keypair_path")
declare storage_pubkey
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
declare node_lamports=$2
declare stake_lamports=$3
if [[ -f $configured_flag ]]; then
echo "Vote and stake accounts have already been configured"
@ -101,75 +86,66 @@ setup_validator_accounts() {
if ((airdrops_enabled)); then
# Fund the node with enough tokens to fund its Vote, Staking, and Storage accounts
declare fees=100 # TODO: No hardcoded transaction fees, fetch the current cluster fees
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" airdrop $((node_lamports+stake_lamports+fees)) || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" airdrop $((node_lamports+stake_lamports+fees)) || return $?
else
echo "current account balance is "
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" balance || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" balance || return $?
fi
# Fund the vote account from the node, with the node as the node_pubkey
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
create-vote-account "$vote_pubkey" "$node_pubkey" 1 --commission 65535 || return $?
# Fund the vote account from the node, with the node as the identity_pubkey
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
create-vote-account "$vote_pubkey" "$identity_pubkey" 1 --commission 127 || return $?
# Fund the stake account from the node, with the node as the node_pubkey
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
# Fund the stake account from the node, with the node as the identity_pubkey
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
create-stake-account "$stake_pubkey" "$stake_lamports" || return $?
# Delegate the stake. The transaction fee is paid by the node but the
# transaction must be signed by the stake_keypair
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
delegate-stake "$stake_keypair_path" "$vote_pubkey" "$stake_lamports" || return $?
# Setup validator storage account
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
create-validator-storage-account "$node_pubkey" "$storage_pubkey" || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
create-validator-storage-account "$identity_pubkey" "$storage_pubkey" || return $?
touch "$configured_flag"
fi
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
show-vote-account "$vote_pubkey"
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
show-stake-account "$stake_pubkey"
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
show-storage-account "$storage_pubkey"
echo "Identity account balance:"
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" balance
echo "========================================================================"
return 0
}
setup_replicator_account() {
declare entrypoint_ip=$1
declare node_keypair_path=$2
declare storage_keypair_path=$3
declare node_lamports=$4
declare node_pubkey
node_pubkey=$($solana_keygen pubkey "$node_keypair_path")
declare storage_pubkey
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
declare node_lamports=$2
if [[ -f $configured_flag ]]; then
echo "Replicator account has already been configured"
else
if ((airdrops_enabled)); then
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" airdrop "$node_lamports" || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" airdrop "$node_lamports" || return $?
else
echo "current account balance is "
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" balance || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" balance || return $?
fi
# Setup replicator storage account
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
create-replicator-storage-account "$node_pubkey" "$storage_pubkey" || return $?
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
create-replicator-storage-account "$identity_pubkey" "$storage_pubkey" || return $?
touch "$configured_flag"
fi
$solana_wallet --keypair "$node_keypair_path" --url "http://$entrypoint_ip:8899" \
$solana_wallet --keypair "$identity_keypair_path" --url "http://$entrypoint_ip:8899" \
show-storage-account "$storage_pubkey"
return 0
@ -192,6 +168,7 @@ identity_keypair_path=
no_restart=0
airdrops_enabled=1
generate_snapshots=0
boot_from_snapshot=1
positional_args=()
while [[ -n $1 ]]; do
@ -209,6 +186,9 @@ while [[ -n $1 ]]; do
elif [[ $1 = --generate-snapshots ]]; then
generate_snapshots=1
shift
elif [[ $1 = --no-snapshot ]]; then
boot_from_snapshot=0
shift
elif [[ $1 = --replicator ]]; then
node_type=replicator
shift
@ -275,24 +255,13 @@ if [[ $node_type = replicator ]]; then
shift "$shift"
: "${identity_keypair_path:=$SOLANA_CONFIG_DIR/replicator-keypair$label.json}"
mkdir -p "$SOLANA_CONFIG_DIR"
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
storage_keypair_path="$SOLANA_CONFIG_DIR"/replicator-storage-keypair$label.json
ledger_config_dir=$SOLANA_CONFIG_DIR/replicator-ledger$label
configured_flag=$SOLANA_CONFIG_DIR/replicator$label.configured
mkdir -p "$SOLANA_CONFIG_DIR"
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
[[ -r "$storage_keypair_path" ]] || $solana_keygen new -o "$storage_keypair_path"
identity_pubkey=$($solana_keygen pubkey "$identity_keypair_path")
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
cat <<EOF
======================[ $node_type configuration ]======================
replicator pubkey: $identity_pubkey
storage pubkey: $storage_pubkey
ledger: $ledger_config_dir
======================================================================
EOF
program=$solana_replicator
default_arg --entrypoint "$entrypoint_address"
default_arg --identity "$identity_keypair_path"
@ -300,6 +269,7 @@ EOF
default_arg --ledger "$ledger_config_dir"
rsync_entrypoint_url=$(rsync_url "$entrypoint")
elif [[ $node_type = bootstrap_leader ]]; then
if [[ ${#positional_args[@]} -ne 0 ]]; then
fullnode_usage "Unknown argument: ${positional_args[0]}"
@ -311,9 +281,11 @@ elif [[ $node_type = bootstrap_leader ]]; then
$solana_ledger_tool --ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger verify
: "${identity_keypair_path:=$SOLANA_CONFIG_DIR/bootstrap-leader-keypair.json}"
vote_keypair_path="$SOLANA_CONFIG_DIR"/bootstrap-leader-vote-keypair.json
ledger_config_dir="$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger
state_dir="$SOLANA_CONFIG_DIR"/bootstrap-leader-state
stake_keypair_path=$SOLANA_CONFIG_DIR/bootstrap-leader-stake-keypair.json
storage_keypair_path=$SOLANA_CONFIG_DIR/bootstrap-leader-storage-keypair.json
configured_flag=$SOLANA_CONFIG_DIR/bootstrap-leader.configured
@ -332,19 +304,16 @@ elif [[ $node_type = validator ]]; then
shift "$shift"
: "${identity_keypair_path:=$SOLANA_CONFIG_DIR/validator-keypair$label.json}"
mkdir -p "$SOLANA_CONFIG_DIR"
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
vote_keypair_path=$SOLANA_CONFIG_DIR/validator-vote-keypair$label.json
ledger_config_dir=$SOLANA_CONFIG_DIR/validator-ledger$label
state_dir="$SOLANA_CONFIG_DIR"/validator-state$label
storage_keypair_path=$SOLANA_CONFIG_DIR/validator-storage-keypair$label.json
stake_keypair_path=$SOLANA_CONFIG_DIR/validator-stake-keypair$label.json
storage_keypair_path=$SOLANA_CONFIG_DIR/validator-storage-keypair$label.json
configured_flag=$SOLANA_CONFIG_DIR/validator$label.configured
mkdir -p "$SOLANA_CONFIG_DIR"
[[ -r "$identity_keypair_path" ]] || $solana_keygen new -o "$identity_keypair_path"
[[ -r "$vote_keypair_path" ]] || $solana_keygen new -o "$vote_keypair_path"
[[ -r "$stake_keypair_path" ]] || $solana_keygen new -o "$stake_keypair_path"
[[ -r "$storage_keypair_path" ]] || $solana_keygen new -o "$storage_keypair_path"
default_arg --entrypoint "$entrypoint_address"
if ((airdrops_enabled)); then
default_arg --rpc-drone-address "${entrypoint_address%:*}:9900"
@ -356,29 +325,14 @@ else
exit 1
fi
identity_pubkey=$($solana_keygen pubkey "$identity_keypair_path")
if [[ $node_type != replicator ]]; then
accounts_config_dir="$state_dir"/accounts
snapshot_config_dir="$state_dir"/snapshots
identity_pubkey=$($solana_keygen pubkey "$identity_keypair_path")
vote_pubkey=$($solana_keygen pubkey "$vote_keypair_path")
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
cat <<EOF
======================[ $node_type configuration ]======================
identity pubkey: $identity_pubkey
vote pubkey: $vote_pubkey
storage pubkey: $storage_pubkey
ledger: $ledger_config_dir
accounts: $accounts_config_dir
snapshots: $snapshot_config_dir
========================================================================
EOF
default_arg --identity "$identity_keypair_path"
default_arg --voting-keypair "$vote_keypair_path"
default_arg --vote-account "$vote_pubkey"
default_arg --storage-keypair "$storage_keypair_path"
default_arg --ledger "$ledger_config_dir"
default_arg --accounts "$accounts_config_dir"
@ -397,72 +351,136 @@ if [[ -z $CI ]]; then # Skip in CI
fi
new_gensis_block() {
(
set -x
$rsync -r "${rsync_entrypoint_url:?}"/config/ledger "$SOLANA_RSYNC_CONFIG_DIR"
) || (
echo "Error: failed to rsync genesis ledger"
)
! diff -q "$SOLANA_RSYNC_CONFIG_DIR"/ledger/genesis.bin "$ledger_config_dir"/genesis.bin >/dev/null 2>&1
}
set -e
PS4="$(basename "$0"): "
pid=
trap '[[ -n $pid ]] && kill "$pid" >/dev/null 2>&1 && wait "$pid"' INT TERM ERR
kill_fullnode() {
if [[ -n $pid ]]; then
declare _pid=$pid
pid=
echo "killing pid $_pid"
kill "$_pid" || true
wait "$_pid" || true
echo "$_pid killed"
fi
}
trap 'kill_fullnode' INT TERM ERR
while true; do
if new_gensis_block; then
# If the genesis block has changed remove the now stale ledger and vote
# keypair for the node and start all over again
if [[ $node_type != bootstrap_leader ]] && new_gensis_block; then
# If the genesis block has changed remove the now stale ledger and
# vote/stake/storage keypairs for the node and start all over again
(
set -x
rm -rf "$ledger_config_dir" "$state_dir" "$configured_flag"
)
if [[ $node_type = validator ]]; then
$solana_keygen new -f -o "$vote_keypair_path"
$solana_keygen new -f -o "$stake_keypair_path"
$solana_keygen new -f -o "$storage_keypair_path"
fi
if [[ $node_type = replicator ]]; then
$solana_keygen new -f -o "$storage_keypair_path"
fi
fi
if [[ ! -d "$SOLANA_RSYNC_CONFIG_DIR"/ledger ]]; then
if [[ $node_type = bootstrap_leader ]]; then
if [[ $node_type = replicator ]]; then
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
setup_replicator_account "${entrypoint_address%:*}" \
"$node_lamports"
cat <<EOF
======================[ $node_type configuration ]======================
replicator pubkey: $identity_pubkey
storage pubkey: $storage_pubkey
ledger: $ledger_config_dir
======================================================================
EOF
else
if [[ $node_type = bootstrap_leader && ! -d "$SOLANA_RSYNC_CONFIG_DIR"/ledger ]]; then
ledger_not_setup "$SOLANA_RSYNC_CONFIG_DIR/ledger does not exist"
elif [[ $node_type = validator ]]; then
(
SECONDS=0
set -x
cd "$SOLANA_RSYNC_CONFIG_DIR"
$rsync -qPr "${rsync_entrypoint_url:?}"/config/{ledger,state.tgz} .
echo "Fetched snapshot in $SECONDS seconds"
) || true
fi
fi
(
set -x
if [[ $node_type = validator ]]; then
if [[ -f "$SOLANA_RSYNC_CONFIG_DIR"/state.tgz ]]; then
mkdir -p "$state_dir"
SECONDS=
tar -C "$state_dir" -zxf "$SOLANA_RSYNC_CONFIG_DIR"/state.tgz
echo "Extracted snapshot in $SECONDS seconds"
fi
fi
if [[ ! -d "$ledger_config_dir" ]]; then
cp -a "$SOLANA_RSYNC_CONFIG_DIR"/ledger/ "$ledger_config_dir"
fi
)
if [[ $node_type = validator ]]; then
(
cd "$SOLANA_RSYNC_CONFIG_DIR"
if ((stake_lamports)); then
if [[ $node_type = validator ]]; then
echo "Rsyncing genesis ledger from ${rsync_entrypoint_url:?}..."
SECONDS=
while ! $rsync -Pr "${rsync_entrypoint_url:?}"/config/ledger .; do
echo "Genesis ledger rsync failed"
sleep 5
done
echo "Fetched genesis ledger in $SECONDS seconds"
if ((boot_from_snapshot)); then
SECONDS=
echo "Rsyncing state snapshot ${rsync_entrypoint_url:?}..."
if ! $rsync -P "${rsync_entrypoint_url:?}"/config/state.tgz .; then
echo "State snapshot rsync failed"
rm -f "$SOLANA_RSYNC_CONFIG_DIR"/state.tgz
exit
fi
echo "Fetched snapshot in $SECONDS seconds"
SECONDS=
mkdir -p "$state_dir"
(
set -x
tar -C "$state_dir" -zxf "$SOLANA_RSYNC_CONFIG_DIR"/state.tgz
)
echo "Extracted snapshot in $SECONDS seconds"
fi
)
fi
(
set -x
cp -a "$SOLANA_RSYNC_CONFIG_DIR"/ledger/ "$ledger_config_dir"
)
fi
vote_pubkey=$($solana_keygen pubkey "$vote_keypair_path")
stake_pubkey=$($solana_keygen pubkey "$stake_keypair_path")
storage_pubkey=$($solana_keygen pubkey "$storage_keypair_path")
replace_arg --vote-account "$vote_pubkey"
if [[ $node_type = validator ]] && ((stake_lamports)); then
setup_validator_accounts "${entrypoint_address%:*}" \
"$identity_keypair_path" \
"$vote_keypair_path" \
"$stake_keypair_path" \
"$storage_keypair_path" \
"$node_lamports" \
"$stake_lamports"
elif [[ $node_type = replicator ]]; then
setup_replicator_account "${entrypoint_address%:*}" \
"$identity_keypair_path" \
"$storage_keypair_path" \
"$node_lamports"
fi
cat <<EOF
======================[ $node_type configuration ]======================
identity pubkey: $identity_pubkey
vote pubkey: $vote_pubkey
storage pubkey: $storage_pubkey
ledger: $ledger_config_dir
accounts: $accounts_config_dir
snapshots: $snapshot_config_dir
========================================================================
EOF
fi
echo "$PS4$program ${args[*]}"
$program "${args[@]}" &
pid=$!
echo "pid: $pid"
oom_score_adj "$pid" 1000
if ((no_restart)); then
@ -488,9 +506,15 @@ while true; do
new_state_archive="$SOLANA_RSYNC_CONFIG_DIR"/new_state.tgz
(
rm -rf "$new_state_dir" "$new_state_archive"
cp -a "$state_dir" "$new_state_dir"
mkdir -p "$new_state_dir"
# When saving the state, its necessary to have the snapshots be saved first
# followed by the accounts folder. This would avoid conditions where incomplete
# accounts gets picked while its still in the process of being updated and are
# not frozen yet.
cp -a "$state_dir"/snapshots "$new_state_dir"
cp -a "$state_dir"/accounts "$new_state_dir"
cd "$new_state_dir"
tar zcf "$new_state_archive" ./*
tar zcfS "$new_state_archive" ./*
)
ln -f "$new_state_archive" "$SOLANA_RSYNC_CONFIG_DIR"/state.tgz
rm -rf "$new_state_dir" "$new_state_archive"
@ -504,21 +528,16 @@ while true; do
if ((poll_for_new_genesis_block && --secs_to_next_genesis_poll == 0)); then
echo "Polling for new genesis block..."
(
set -x
$rsync -r "${rsync_entrypoint_url:?}"/config/ledger "$SOLANA_RSYNC_CONFIG_DIR"
) || (
echo "Error: failed to rsync ledger"
)
new_gensis_block && break
if new_gensis_block; then
echo "############## New genesis detected, restarting $node_type ##############"
break
fi
secs_to_next_genesis_poll=60
fi
done
echo "############## New genesis detected, restarting $node_type ##############"
kill "$pid" || true
wait "$pid" || true
kill_fullnode
# give the cluster time to come back up
(
set -x

View File

@ -23,7 +23,6 @@ default_arg --ledger "$SOLANA_RSYNC_CONFIG_DIR"/ledger
default_arg --mint "$SOLANA_CONFIG_DIR"/mint-keypair.json
default_arg --lamports 100000000000000
default_arg --bootstrap-leader-lamports 424242
default_arg --storage-mining-pool-lamports 100000000
default_arg --target-lamports-per-signature 42
default_arg --target-signatures-per-slot 42
default_arg --hashes-per-tick auto

View File

@ -25,6 +25,7 @@ entrypointIp=
publicNetwork=
netBasename=
sshPrivateKey=
letsEncryptDomainName=
externalNodeSshKey=
sshOptions=()
fullnodeIpList=()

View File

@ -63,10 +63,12 @@ blockstreamer=false
fullNodeBootDiskSizeInGb=1000
clientBootDiskSizeInGb=75
replicatorBootDiskSizeInGb=1000
fullNodeAdditionalDiskSizeInGb=
externalNodes=false
failOnValidatorBootupFailure=true
publicNetwork=false
letsEncryptDomainName=
enableGpu=false
customAddress=
zones=()
@ -122,7 +124,13 @@ Manage testnet instances
* For EC2, [address] is the "allocation ID" of the desired
Elastic IP.
-d [disk-type] - Specify a boot disk type (default None) Use pd-ssd to get ssd on GCE.
--letsencrypt [dns name] - Attempt to generate a TLS certificate using this
DNS name (useful only when the -a and -P options
are also provided)
--fullnode-additional-disk-size-gb [number]
- Add an additional [number] GB SSD to all fullnodes to store the config-local directory.
If not set, config-local will be written to the boot disk by default.
Only supported on GCE.
config-specific options:
-P - Use public network IP addresses (default: $publicNetwork)
@ -136,14 +144,34 @@ EOF
exit $exitcode
}
command=$1
[[ -n $command ]] || usage
shift
[[ $command = create || $command = config || $command = info || $command = delete ]] ||
usage "Invalid command: $command"
while getopts "h?p:Pn:c:r:z:gG:a:d:uxf" opt; do
shortArgs=()
while [[ -n $1 ]]; do
if [[ ${1:0:2} = -- ]]; then
if [[ $1 = --letsencrypt ]]; then
letsEncryptDomainName="$2"
shift 2
elif [[ $1 = --fullnode-additional-disk-size-gb ]]; then
fullNodeAdditionalDiskSizeInGb="$2"
shift 2
elif [[ $1 == --machine-type* ]]; then # Bypass quoted long args for GPUs
shortArgs+=("$1")
shift
else
usage "Unknown long option: $1"
fi
else
shortArgs+=("$1")
shift
fi
done
while getopts "h?p:Pn:c:r:z:gG:a:d:uxf" opt "${shortArgs[@]}"; do
case $opt in
h | \?)
usage
@ -199,7 +227,6 @@ while getopts "h?p:Pn:c:r:z:gG:a:d:uxf" opt; do
;;
esac
done
shift $((OPTIND - 1))
[[ ${#zones[@]} -gt 0 ]] || zones+=("$(cloud_DefaultZone)")
@ -217,8 +244,14 @@ case $cloudProvider in
gce)
;;
ec2)
if [[ -n $fullNodeAdditionalDiskSizeInGb ]] ; then
usage "Error: --fullnode-additional-disk-size-gb currently only supported with cloud provider: gce"
fi
;;
azure)
if [[ -n $fullNodeAdditionalDiskSizeInGb ]] ; then
usage "Error: --fullnode-additional-disk-size-gb currently only supported with cloud provider: gce"
fi
;;
*)
echo "Error: Unknown cloud provider: $cloudProvider"
@ -328,6 +361,7 @@ prepareInstancesAndWriteConfigFile() {
netBasename=$prefix
publicNetwork=$publicNetwork
sshPrivateKey=$sshPrivateKey
letsEncryptDomainName=$letsEncryptDomainName
EOF
fi
touch "$geoipConfigFile"
@ -598,6 +632,7 @@ $(
disable-background-upgrades.sh \
create-solana-user.sh \
add-solana-user-authorized_keys.sh \
install-certbot.sh \
install-earlyoom.sh \
install-libssl-compatability.sh \
install-nodejs.sh \
@ -611,6 +646,10 @@ $(
cat enable-nvidia-persistence-mode.sh
fi
if [[ -n $fullNodeAdditionalDiskSizeInGb ]]; then
cat mount-additional-disk.sh
fi
)
cat > /etc/motd <<EOM
@ -637,7 +676,7 @@ EOF
else
cloud_CreateInstances "$prefix" "$prefix-bootstrap-leader" 1 \
"$enableGpu" "$bootstrapLeaderMachineType" "${zones[0]}" "$fullNodeBootDiskSizeInGb" \
"$startupScript" "$bootstrapLeaderAddress" "$bootDiskType"
"$startupScript" "$bootstrapLeaderAddress" "$bootDiskType" "$fullNodeAdditionalDiskSizeInGb"
fi
if [[ $additionalFullNodeCount -gt 0 ]]; then
@ -657,7 +696,7 @@ EOF
fi
cloud_CreateInstances "$prefix" "$prefix-$zone-fullnode" "$numNodesPerZone" \
"$enableGpu" "$fullNodeMachineType" "$zone" "$fullNodeBootDiskSizeInGb" \
"$startupScript" "" "$bootDiskType" &
"$startupScript" "" "$bootDiskType" "$fullNodeAdditionalDiskSizeInGb" &
done
wait

View File

@ -50,17 +50,16 @@ Operate a configured testnet
-c bench-tps=2="--tx_count 25000"
This will start 2 bench-tps clients, and supply "--tx_count 25000"
to the bench-tps client.
-n NUM_FULL_NODES - Number of fullnodes to apply command to.
--hashes-per-tick NUM_HASHES|sleep|auto
- Override the default --hashes-per-tick for the cluster
-n NUM_FULL_NODES - Number of fullnodes to apply command to.
-x Accounts and Stakes for external nodes
- A YML file with a list of account pubkeys and corresponding stakes
for external nodes
-s Num lamports per node in genesis block
- Create account keypairs for internal nodes and assign these many lamports
--lamports NUM_LAMPORTS_TO_MINT
- Override the default 100000000000000 lamports minted in genesis
--stake-internal-nodes NUM_LAMPORTS_PER_NODE
- Amount to stake internal nodes in genesis block. If set, airdrops are disabled.
--external-accounts-file FILE_PATH
- A YML file with a list of account pubkeys and corresponding stakes for external nodes
sanity/start/update-specific options:
-F - Discard validator nodes that didn't bootup successfully
-o noLedgerVerify - Skip ledger verification
@ -96,6 +95,7 @@ failOnValidatorBootupFailure=true
genesisOptions=
numFullnodesRequested=
externalPrimordialAccountsFile=
remoteExternalPrimordialAccountsFile=
stakeNodesInGenesisBlock=
command=$1
@ -111,9 +111,19 @@ while [[ -n $1 ]]; do
elif [[ $1 = --target-lamports-per-signature ]]; then
genesisOptions="$genesisOptions $1 $2"
shift 2
elif [[ $1 = --lamports ]]; then
genesisOptions="$genesisOptions $1 $2"
shift 2
elif [[ $1 = --deploy-update ]]; then
updatePlatforms="$updatePlatforms $2"
shift 2
elif [[ $1 = --stake-internal-nodes ]]; then
stakeNodesInGenesisBlock="$2"
shift 2
elif [[ $1 = --external-accounts-file ]]; then
externalPrimordialAccountsFile="$2"
remoteExternalPrimordialAccountsFile=/tmp/external-primordial-accounts.yml
shift 2
else
usage "Unknown long option: $1"
fi
@ -123,7 +133,7 @@ while [[ -n $1 ]]; do
fi
done
while getopts "h?T:t:o:f:rD:c:Fn:i:x:s:" opt "${shortArgs[@]}"; do
while getopts "h?T:t:o:f:rD:c:Fn:i:" opt "${shortArgs[@]}"; do
case $opt in
h | \?)
usage
@ -202,12 +212,6 @@ while getopts "h?T:t:o:f:rD:c:Fn:i:x:s:" opt "${shortArgs[@]}"; do
F)
failOnValidatorBootupFailure=false
;;
x)
externalPrimordialAccountsFile=$OPTARG
;;
s)
stakeNodesInGenesisBlock=$OPTARG
;;
i)
nodeAddress=$OPTARG
;;
@ -321,7 +325,7 @@ startBootstrapLeader() {
set -x
startCommon "$ipAddress" || exit 1
[[ -z "$externalPrimordialAccountsFile" ]] || rsync -vPrc -e "ssh ${sshOptions[*]}" "$externalPrimordialAccountsFile" \
"$ipAddress:~/solana/config/external-primodial-accounts.yml"
"$ipAddress:$remoteExternalPrimordialAccountsFile"
case $deployMethod in
tar)
rsync -vPrc -e "ssh ${sshOptions[*]}" "$SOLANA_ROOT"/solana-release/bin/* "$ipAddress:~/.cargo/bin/"
@ -343,7 +347,7 @@ startBootstrapLeader() {
\"$RUST_LOG\" \
$skipSetup \
$failOnValidatorBootupFailure \
\"$externalPrimordialAccountsFile\" \
\"$remoteExternalPrimordialAccountsFile\" \
\"$stakeNodesInGenesisBlock\" \
$nodeIndex \
$numBenchTpsClients \"$benchTpsExtraArgs\" \
@ -368,6 +372,23 @@ startNode() {
(
set -x
startCommon "$ipAddress"
if [[ $nodeType = blockstreamer ]] && [[ -n $letsEncryptDomainName ]]; then
#
# Create/renew TLS certificate
#
declare localArchive=~/letsencrypt-"$letsEncryptDomainName".tgz
if [[ -r "$localArchive" ]]; then
timeout 30s scp "${sshOptions[@]}" "$localArchive" "$ipAddress:letsencrypt.tgz"
fi
ssh "${sshOptions[@]}" -n "$ipAddress" \
"sudo -H /certbot-restore.sh $letsEncryptDomainName maintainers@solana.com"
rm -f letsencrypt.tgz
timeout 30s scp "${sshOptions[@]}" "$ipAddress:/letsencrypt.tgz" letsencrypt.tgz
test -s letsencrypt.tgz # Ensure non-empty before overwriting $localArchive
cp letsencrypt.tgz "$localArchive"
fi
ssh "${sshOptions[@]}" -n "$ipAddress" \
"./solana/net/remote/remote-node.sh \
$deployMethod \
@ -377,7 +398,7 @@ startNode() {
\"$RUST_LOG\" \
$skipSetup \
$failOnValidatorBootupFailure \
\"$externalPrimordialAccountsFile\" \
\"$remoteExternalPrimordialAccountsFile\" \
\"$stakeNodesInGenesisBlock\" \
$nodeIndex \
\"$genesisOptions\" \
@ -477,7 +498,8 @@ start() {
declare updateDownloadUrl=http://release.solana.com/"$releaseChannel"/solana-release-x86_64-unknown-linux-gnu.tar.bz2
(
set -x
curl -o "$SOLANA_ROOT"/solana-release.tar.bz2 "$updateDownloadUrl"
curl --retry 5 --retry-delay 2 --retry-connrefused \
-o "$SOLANA_ROOT"/solana-release.tar.bz2 "$updateDownloadUrl"
)
tarballFilename="$SOLANA_ROOT"/solana-release.tar.bz2
else

View File

@ -34,4 +34,6 @@ loadConfigFile
PATH="$HOME"/.cargo/bin:"$PATH"
set -x
scripts/solana-install-deploy.sh localhost "$releaseChannel" "$updatePlatform"
scripts/solana-install-deploy.sh \
--keypair config-local/mint-keypair.json \
localhost "$releaseChannel" "$updatePlatform"

View File

@ -92,7 +92,7 @@ local|tar)
SUDO_OK=1 source scripts/tune-system.sh
(
sudo scripts/oom-monitor.sh
sudo SOLANA_METRICS_CONFIG="$SOLANA_METRICS_CONFIG" scripts/oom-monitor.sh
) > oom-monitor.log 2>&1 &
echo $! > oom-monitor.pid
scripts/net-stats.sh > net-stats.log 2>&1 &
@ -223,8 +223,15 @@ local|tar)
if [[ -z $stakeNodesInGenesisBlock ]]; then
./multinode-demo/drone.sh > drone.log 2>&1 &
fi
# Grab the TLS cert generated by /certbot-restore.sh
if [[ -f /.cert.pem ]]; then
sudo install -o $UID -m 400 /.cert.pem /.key.pem .
ls -l .cert.pem .key.pem
fi
export BLOCKEXPLORER_GEOIP_WHITELIST=$PWD/net/config/geoip.yml
npm install @solana/blockexplorer@1
npm install @solana/blockexplorer@1.17.2
npx solana-blockexplorer > blockexplorer.log 2>&1 &
# Confirm the blockexplorer is accessible

View File

@ -183,13 +183,11 @@ if $installCheck && [[ -r update_manifest_keypair.json ]]; then
(
set -x
update_manifest_pubkey=$($solana_keygen pubkey update_manifest_keypair.json)
rm -rf install-data-dir
$solana_install init \
--no-modify-path \
--data-dir install-data-dir \
--url http://"$sanityTargetIp":8899 \
--pubkey "$update_manifest_pubkey"
$solana_install info
)

View File

@ -14,6 +14,8 @@ set -ex
# 2. Inline ~/.ssh/id-solana-testnet.pub below
cat > /solana-authorized_keys <<EOF
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFBNwLw0i+rI312gWshojFlNw9NV7WfaKeeUsYADqOvM2o4yrO2pPw+sgW8W+/rPpVyH7zU9WVRgTME8NgFV1Vc=
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGqZAwAZeBl0buOMz4FpUYrtpwk1L5aGKlbd7lI8dpbSx5WVRPWCVKhWzsGMtDUIfmozdzJouk1LPyihghTDgsE=
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOk4jgcX/VWSk3j//wXeIynSQjsOt+AjYXM/XZUMa7R1Q8lfIJGK/qHLBP86CMXdpyEKJ5i37QLYOL+0VuRy0CI=
EOF
sudo -u solana bash -c "

View File

@ -309,3 +309,12 @@ cloud_FetchFile() {
cloud_GetConfigValueFromInstanceName "$instanceName" osProfile.adminUsername
scp "${config_value}@${publicIp}:${remoteFile}" "$localFile"
}
#
# cloud_CreateAndAttachPersistentDisk
#
# Not yet implemented for this cloud provider
cloud_CreateAndAttachPersistentDisk() {
echo "ERROR: cloud_CreateAndAttachPersistentDisk is not yet implemented for azure"
exit 1
}

View File

@ -381,3 +381,12 @@ cloud_FetchFile() {
"solana@$publicIp:$remoteFile" "$localFile"
)
}
#
# cloud_CreateAndAttachPersistentDisk
#
# Not yet implemented for this cloud provider
cloud_CreateAndAttachPersistentDisk() {
echo "ERROR: cloud_CreateAndAttachPersistentDisk is not yet implemented for ec2"
exit 1
}

View File

@ -81,7 +81,7 @@
"FromPort": 3001,
"IpRanges": [
{
"Description": "blockexplorer API port",
"Description": "blockexplorer http API port",
"CidrIp": "0.0.0.0/0"
}
],
@ -91,7 +91,26 @@
"Ipv6Ranges": [
{
"CidrIpv6": "::/0",
"Description": "blockexplorer API port"
"Description": "blockexplorer http API port"
}
]
},
{
"PrefixListIds": [],
"FromPort": 3443,
"IpRanges": [
{
"Description": "blockexplorer https API port",
"CidrIp": "0.0.0.0/0"
}
],
"ToPort": 3443,
"IpProtocol": "tcp",
"UserIdGroupPairs": [],
"Ipv6Ranges": [
{
"CidrIpv6": "::/0",
"Description": "blockexplorer https API port"
}
]
},

View File

@ -126,6 +126,7 @@ cloud_CreateInstances() {
declare optionalStartupScript="$8"
declare optionalAddress="$9"
declare optionalBootDiskType="${10}"
declare optionalAdditionalDiskSize="${11}"
if $enableGpu; then
# Custom Ubuntu 18.04 LTS image with CUDA 9.2 and CUDA 10.0 installed
@ -198,6 +199,22 @@ cloud_CreateInstances() {
set -x
gcloud beta compute instances create "${nodes[@]}" "${args[@]}"
)
if [[ -n $optionalAdditionalDiskSize ]]; then
if [[ $numNodes = 1 ]]; then
(
set -x
cloud_CreateAndAttachPersistentDisk "${namePrefix}" "$optionalAdditionalDiskSize" "pd-ssd" "$zone"
)
else
for node in $(seq -f "${namePrefix}%0${#numNodes}g" 1 "$numNodes"); do
(
set -x
cloud_CreateAndAttachPersistentDisk "${node}" "$optionalAdditionalDiskSize" "pd-ssd" "$zone"
)
done
fi
fi
}
#
@ -256,3 +273,31 @@ cloud_FetchFile() {
gcloud compute scp --zone "$zone" "$instanceName:$remoteFile" "$localFile"
)
}
#
# cloud_CreateAndAttachPersistentDisk [instanceName] [diskSize] [diskType]
#
# Create a persistent disk and attach it to a pre-existing VM instance.
# Set disk to auto-delete upon instance deletion
#
cloud_CreateAndAttachPersistentDisk() {
declare instanceName="$1"
declare diskSize="$2"
declare diskType="$3"
declare zone="$4"
diskName="${instanceName}-pd"
gcloud beta compute disks create "$diskName" \
--size "$diskSize" \
--type "$diskType" \
--zone "$zone"
gcloud compute instances attach-disk "$instanceName" \
--disk "$diskName" \
--zone "$zone"
gcloud compute instances set-disk-auto-delete "$instanceName" \
--disk "$diskName" \
--zone "$zone" \
--auto-delete
}

52
net/scripts/install-certbot.sh Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -ex
[[ $(uname) = Linux ]] || exit 1
[[ $USER = root ]] || exit 1
apt-get update
add-apt-repository --yes ppa:certbot/certbot
apt-get --assume-yes install certbot
cat > /certbot-restore.sh <<'EOF'
#!/usr/bin/env bash
set -e
domain=$1
email=$2
if [[ $USER != root ]]; then
echo "Run as root"
exit 1
fi
if [[ -f /.cert.pem ]]; then
echo "Certificate already initialized"
exit 0
fi
set -x
if [[ -r letsencrypt.tgz ]]; then
tar -C / -zxf letsencrypt.tgz
fi
cd /
rm -f letsencrypt.tgz
maybeDryRun=
# Uncomment during testing to avoid hitting LetsEncrypt API limits while iterating
#maybeDryRun="--dry-run"
certbot certonly --standalone -d "$domain" --email "$email" --agree-tos -n $maybeDryRun
tar zcf letsencrypt.tgz /etc/letsencrypt
ls -l letsencrypt.tgz
# Copy certificates to / for easy access without knowing the value of "$domain"
rm -f /.key.pem /.cert.pem
cp /etc/letsencrypt/live/$domain/privkey.pem /.key.pem
cp /etc/letsencrypt/live/$domain/cert.pem /.cert.pem
EOF
chmod +x /certbot-restore.sh

View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -x
mount_point=/mnt/extra-disk
disk=sdb
if ! lsblk | grep -q ${disk} ; then
echo "${disk} does not exist"
else
if mount | grep -q ${disk} ; then
echo "${disk} is already mounted"
else
sudo mkfs.ext4 -F /dev/"$disk"
sudo mkdir -p "$mount_point"
sudo mount /dev/"$disk" "$mount_point"
sudo chmod a+w "$mount_point"
if ! mount | grep -q ${mount_point} ; then
echo "${disk} failed to mount!"
exit 1
fi
fi
fi

View File

@ -1,6 +1,6 @@
[package]
name = "solana-netutil"
version = "0.16.0"
version = "0.16.3"
description = "Solana Network Utilities"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -15,7 +15,7 @@ log = "0.4.2"
nix = "0.14.1"
rand = "0.6.1"
socket2 = "0.3.9"
solana-logger = { path = "../logger", version = "0.16.0" }
solana-logger = { path = "../logger", version = "0.16.3" }
tokio = "0.1"
[lib]

View File

@ -1,7 +1,7 @@
[package]
name = "solana-bpf-programs"
description = "Blockchain, Rebuilt for Scale"
version = "0.16.0"
version = "0.16.3"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "README.md"
@ -21,10 +21,10 @@ walkdir = "2"
bincode = "1.1.4"
byteorder = "1.3.2"
elf = "0.0.10"
solana-bpf-loader-api = { path = "../bpf_loader_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-bpf-loader-api = { path = "../bpf_loader_api", version = "0.16.3" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana_rbpf = "=0.1.13"
[[bench]]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-128bit"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF iter program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,8 +12,8 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-128bit-dep"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF many-args-dep program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-alloc"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF alloc program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-dep-crate"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF dep-crate program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,7 +13,7 @@ edition = "2018"
[dependencies]
byteorder = { version = "1", default-features = false }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-iter"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF iter program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-many-args"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF many-args program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,8 +12,8 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-many-args-dep"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF many-args-dep program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-noop"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF noop program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-panic"
version = "0.15.0"
version = "0.16.3"
description = "Solana BPF iter program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-tick-height"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF noop program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,7 +14,7 @@ edition = "2018"
[dependencies]
byteorder = { version = "1", default-features = false }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.0" }
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust/rust-utils", version = "0.16.3" }
[workspace]
members = []

View File

@ -1,6 +1,6 @@
[package]
name = "solana-bpf-loader-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF Loader"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,8 +14,8 @@ byteorder = "1.3.2"
libc = "0.2.58"
log = "0.4.2"
serde = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana_rbpf = "=0.1.13"
[lib]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-bpf-loader-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana BPF Loader"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,9 +10,9 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-bpf-loader-api = { path = "../bpf_loader_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana-bpf-loader-api = { path = "../bpf_loader_api", version = "0.16.3" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-budget-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana Budget program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,10 +16,10 @@ num-derive = "0.2"
num-traits = "0.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
[lib]
crate-type = ["lib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-budget-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana budget program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,9 +10,9 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-budget-api = { path = "../budget_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-budget-api = { path = "../budget_api", version = "0.16.3" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-config-api"
version = "0.16.0"
version = "0.16.3"
description = "config program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,13 +13,12 @@ bincode = "1.1.4"
log = "0.4.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
[lib]
crate-type = ["lib"]
name = "solana_config_api"

View File

@ -1,26 +1,59 @@
use crate::id;
use crate::ConfigState;
use bincode::serialize;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::short_vec;
use solana_sdk::system_instruction;
/// A collection of keys to be stored in Config account data.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct ConfigKeys {
// Each key tuple comprises a unique `Pubkey` identifier,
// and `bool` whether that key is a signer of the data
#[serde(with = "short_vec")]
pub keys: Vec<(Pubkey, bool)>,
}
impl ConfigKeys {
pub fn serialized_size(keys: Vec<(Pubkey, bool)>) -> usize {
serialize(&ConfigKeys { keys })
.unwrap_or_else(|_| vec![])
.len()
}
}
/// Create a new, empty configuration account
pub fn create_account<T: ConfigState>(
from_account_pubkey: &Pubkey,
config_account_pubkey: &Pubkey,
lamports: u64,
keys: Vec<(Pubkey, bool)>,
) -> Instruction {
let space = T::max_space() + ConfigKeys::serialized_size(keys) as u64;
system_instruction::create_account(
from_account_pubkey,
config_account_pubkey,
lamports,
T::max_space(),
space,
&id(),
)
}
/// Store new data in a configuration account
pub fn store<T: ConfigState>(config_account_pubkey: &Pubkey, data: &T) -> Instruction {
let account_metas = vec![AccountMeta::new(*config_account_pubkey, true)];
Instruction::new(id(), data, account_metas)
pub fn store<T: ConfigState>(
config_account_pubkey: &Pubkey,
is_config_signer: bool,
keys: Vec<(Pubkey, bool)>,
data: &T,
) -> Instruction {
let mut account_metas = vec![AccountMeta::new(*config_account_pubkey, is_config_signer)];
for (signer_pubkey, _) in keys.iter().filter(|(_, is_signer)| *is_signer) {
if signer_pubkey != config_account_pubkey {
account_metas.push(AccountMeta::new(*signer_pubkey, true));
}
}
let account_data = (ConfigKeys { keys }, data);
Instruction::new(id(), &account_data, account_metas)
}

View File

@ -1,5 +1,7 @@
//! Config program
use crate::config_instruction::ConfigKeys;
use bincode::deserialize;
use log::*;
use solana_sdk::account::KeyedAccount;
use solana_sdk::instruction::InstructionError;
@ -10,8 +12,81 @@ pub fn process_instruction(
keyed_accounts: &mut [KeyedAccount],
data: &[u8],
) -> Result<(), InstructionError> {
if keyed_accounts[0].signer_key().is_none() {
error!("account[0].signer_key().is_none()");
let key_list: ConfigKeys = deserialize(data).map_err(|err| {
error!("Invalid ConfigKeys data: {:?} {:?}", data, err);
InstructionError::InvalidInstructionData
})?;
let current_data: ConfigKeys = deserialize(&keyed_accounts[0].account.data).map_err(|err| {
error!("Invalid data in account[0]: {:?} {:?}", data, err);
InstructionError::InvalidAccountData
})?;
let current_signer_keys: Vec<Pubkey> = current_data
.keys
.iter()
.filter(|(_, is_signer)| *is_signer)
.map(|(pubkey, _)| *pubkey)
.collect();
if current_signer_keys.is_empty() {
// Config account keypair must be a signer on account initilization,
// or when no signers specified in Config data
if keyed_accounts[0].signer_key().is_none() {
error!("account[0].signer_key().is_none()");
Err(InstructionError::MissingRequiredSignature)?;
}
}
let mut counter = 0;
for (i, (signer, _)) in key_list
.keys
.iter()
.filter(|(_, is_signer)| *is_signer)
.enumerate()
{
counter += 1;
if signer != keyed_accounts[0].unsigned_key() {
let account_index = i + 1;
let signer_account = keyed_accounts.get(account_index);
if signer_account.is_none() {
error!("account {:?} is not in account list", signer);
Err(InstructionError::MissingRequiredSignature)?;
}
let signer_key = signer_account.unwrap().signer_key();
if signer_key.is_none() {
error!("account {:?} signer_key().is_none()", signer);
Err(InstructionError::MissingRequiredSignature)?;
}
if signer_key.unwrap() != signer {
error!(
"account[{:?}].signer_key() does not match Config data)",
account_index
);
Err(InstructionError::MissingRequiredSignature)?;
}
// If Config account is already initialized, update signatures must match Config data
if !current_data.keys.is_empty()
&& current_signer_keys
.iter()
.find(|&pubkey| pubkey == signer)
.is_none()
{
error!("account {:?} is not in stored signer list", signer);
Err(InstructionError::MissingRequiredSignature)?;
}
} else if keyed_accounts[0].signer_key().is_none() {
error!("account[0].signer_key().is_none()");
Err(InstructionError::MissingRequiredSignature)?;
}
}
// Check for Config data signers not present in incoming account update
if current_signer_keys.len() > counter {
error!(
"too few signers: {:?}; expected: {:?}",
counter,
current_signer_keys.len()
);
Err(InstructionError::MissingRequiredSignature)?;
}
@ -20,7 +95,7 @@ pub fn process_instruction(
Err(InstructionError::InvalidInstructionData)?;
}
keyed_accounts[0].account.data[0..data.len()].copy_from_slice(data);
keyed_accounts[0].account.data[0..data.len()].copy_from_slice(&data);
Ok(())
}
@ -64,7 +139,11 @@ mod tests {
(bank, mint_keypair)
}
fn create_config_account(bank: Bank, mint_keypair: &Keypair) -> (BankClient, Keypair) {
fn create_config_account(
bank: Bank,
mint_keypair: &Keypair,
keys: Vec<(Pubkey, bool)>,
) -> (BankClient, Keypair) {
let config_keypair = Keypair::new();
let config_pubkey = config_keypair.pubkey();
@ -76,6 +155,7 @@ mod tests {
&mint_keypair.pubkey(),
&config_pubkey,
1,
keys,
),
)
.expect("new_account");
@ -87,7 +167,7 @@ mod tests {
fn test_process_create_ok() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair, vec![]);
let config_account_data = bank_client
.get_account_data(&config_keypair.pubkey())
.unwrap()
@ -102,13 +182,16 @@ mod tests {
fn test_process_store_ok() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair);
let keys = vec![];
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, &my_config);
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &config_keypair], message)
.unwrap();
@ -117,6 +200,8 @@ mod tests {
.get_account_data(&config_pubkey)
.unwrap()
.unwrap();
let meta_length = ConfigKeys::serialized_size(keys);
let config_account_data = &config_account_data[meta_length..config_account_data.len()];
assert_eq!(
my_config,
MyConfig::deserialize(&config_account_data).unwrap()
@ -127,12 +212,12 @@ mod tests {
fn test_process_store_fail_instruction_data_too_large() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair, vec![]);
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
let mut instruction = config_instruction::store(&config_pubkey, &my_config);
let mut instruction = config_instruction::store(&config_pubkey, true, vec![], &my_config);
instruction.data = vec![0; 123]; // <-- Replace data with a vector that's too large
let message = Message::new(vec![instruction]);
bank_client
@ -148,13 +233,14 @@ mod tests {
let system_pubkey = system_keypair.pubkey();
bank.transfer(42, &mint_keypair, &system_pubkey).unwrap();
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair);
let (bank_client, config_keypair) = create_config_account(bank, &mint_keypair, vec![]);
let config_pubkey = config_keypair.pubkey();
let transfer_instruction =
system_instruction::transfer(&system_pubkey, &Pubkey::new_rand(), 42);
let my_config = MyConfig::new(42);
let mut store_instruction = config_instruction::store(&config_pubkey, &my_config);
let mut store_instruction =
config_instruction::store(&config_pubkey, true, vec![], &my_config);
store_instruction.accounts[0].is_signer = false; // <----- not a signer
let message = Message::new(vec![transfer_instruction, store_instruction]);
@ -162,4 +248,232 @@ mod tests {
.send_message(&[&system_keypair], message)
.unwrap_err();
}
#[test]
fn test_process_store_with_additional_signers() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let pubkey = Pubkey::new_rand();
let signer0 = Keypair::new();
let signer1 = Keypair::new();
let keys = vec![
(pubkey, false),
(signer0.pubkey(), true),
(signer1.pubkey(), true),
];
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(
&[&mint_keypair, &config_keypair, &signer0, &signer1],
message,
)
.unwrap();
let config_account_data = bank_client
.get_account_data(&config_pubkey)
.unwrap()
.unwrap();
let meta_length = ConfigKeys::serialized_size(keys.clone());
let meta_data: ConfigKeys = deserialize(&config_account_data[0..meta_length]).unwrap();
assert_eq!(meta_data.keys, keys);
let config_account_data = &config_account_data[meta_length..config_account_data.len()];
assert_eq!(
my_config,
MyConfig::deserialize(&config_account_data).unwrap()
);
}
#[test]
fn test_process_store_without_config_signer() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let pubkey = Pubkey::new_rand();
let signer0 = Keypair::new();
let keys = vec![(pubkey, false), (signer0.pubkey(), true)];
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &signer0], message)
.unwrap_err();
}
#[test]
fn test_process_store_with_bad_additional_signer() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let signer0 = Keypair::new();
let signer1 = Keypair::new();
let keys = vec![(signer0.pubkey(), true)];
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
// Config-data pubkey doesn't match signer
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let mut message =
Message::new_with_payer(vec![instruction.clone()], Some(&mint_keypair.pubkey()));
message.account_keys[2] = signer1.pubkey();
bank_client
.send_message(&[&mint_keypair, &config_keypair, &signer1], message)
.unwrap_err();
// Config-data pubkey not a signer
let mut message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
message.header.num_required_signatures = 2;
bank_client
.send_message(&[&mint_keypair, &config_keypair], message)
.unwrap_err();
}
#[test]
fn test_config_updates() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let pubkey = Pubkey::new_rand();
let signer0 = Keypair::new();
let signer1 = Keypair::new();
let keys = vec![
(pubkey, false),
(signer0.pubkey(), true),
(signer1.pubkey(), true),
];
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(
&[&mint_keypair, &config_keypair, &signer0, &signer1],
message,
)
.unwrap();
// Update with expected signatures
let new_config = MyConfig::new(84);
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &new_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &signer0, &signer1], message)
.unwrap();
let config_account_data = bank_client
.get_account_data(&config_pubkey)
.unwrap()
.unwrap();
let meta_length = ConfigKeys::serialized_size(keys.clone());
let meta_data: ConfigKeys = deserialize(&config_account_data[0..meta_length]).unwrap();
assert_eq!(meta_data.keys, keys);
let config_account_data = &config_account_data[meta_length..config_account_data.len()];
assert_eq!(
new_config,
MyConfig::deserialize(&config_account_data).unwrap()
);
// Attempt update with incomplete signatures
let keys = vec![(pubkey, false), (signer0.pubkey(), true)];
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &signer0], message)
.unwrap_err();
// Attempt update with incorrect signatures
let signer2 = Keypair::new();
let keys = vec![
(pubkey, false),
(signer0.pubkey(), true),
(signer2.pubkey(), true),
];
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &signer0, &signer2], message)
.unwrap_err();
}
#[test]
fn test_config_updates_requiring_config() {
solana_logger::setup();
let (bank, mint_keypair) = create_bank(10_000);
let pubkey = Pubkey::new_rand();
let signer0 = Keypair::new();
let keys = vec![
(pubkey, false),
(signer0.pubkey(), true),
(signer0.pubkey(), true),
]; // Dummy keys for account sizing
let (bank_client, config_keypair) =
create_config_account(bank, &mint_keypair, keys.clone());
let config_pubkey = config_keypair.pubkey();
let keys = vec![
(pubkey, false),
(signer0.pubkey(), true),
(config_keypair.pubkey(), true),
];
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &config_keypair, &signer0], message)
.unwrap();
// Update with expected signatures
let new_config = MyConfig::new(84);
let instruction =
config_instruction::store(&config_pubkey, true, keys.clone(), &new_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &config_keypair, &signer0], message)
.unwrap();
let config_account_data = bank_client
.get_account_data(&config_pubkey)
.unwrap()
.unwrap();
let meta_length = ConfigKeys::serialized_size(keys.clone());
let meta_data: ConfigKeys = deserialize(&config_account_data[0..meta_length]).unwrap();
assert_eq!(meta_data.keys, keys);
let config_account_data = &config_account_data[meta_length..config_account_data.len()];
assert_eq!(
new_config,
MyConfig::deserialize(&config_account_data).unwrap()
);
// Attempt update with incomplete signatures
let keys = vec![(pubkey, false), (config_keypair.pubkey(), true)];
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let message = Message::new_with_payer(vec![instruction], Some(&mint_keypair.pubkey()));
bank_client
.send_message(&[&mint_keypair, &config_keypair], message)
.unwrap_err();
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-config-program"
version = "0.16.0"
version = "0.16.3"
description = "config program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,9 +10,9 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-config-api = { path = "../config_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-config-api = { path = "../config_api", version = "0.16.3" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-exchange-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana Exchange program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,12 +13,12 @@ bincode = "1.1.4"
log = "0.4.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-metrics = { path = "../../metrics", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-metrics = { path = "../../metrics", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
[lib]
crate-type = ["lib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-exchange-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana exchange program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,9 +10,9 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-exchange-api = { path = "../exchange_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-exchange-api = { path = "../exchange_api", version = "0.16.3" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-failure-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana failure program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,10 +10,10 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
[lib]
crate-type = ["cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-noop-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana noop program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,8 +10,8 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-stake-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana Stake program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,10 +14,10 @@ log = "0.4.2"
rand = "0.6.5"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-metrics = { path = "../../metrics", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-vote-api = { path = "../vote_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-metrics = { path = "../../metrics", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana-vote-api = { path = "../vote_api", version = "0.16.3" }
[lib]
crate-type = ["lib"]

View File

@ -31,6 +31,24 @@ pub enum StakeInstruction {
/// 2 - RewardsPool Stake Account from which to redeem credits
/// 3 - Rewards syscall Account that carries points values
RedeemVoteCredits,
/// Withdraw unstaked lamports from the stake account
///
/// Expects 3 Accounts:
/// 0 - Delegate StakeAccount
/// 1 - System account to which the lamports will be transferred,
/// 2 - Syscall Account that carries epoch
///
/// The u64 is the portion of the Stake account balance to be withdrawn,
/// must be <= StakeAccount.lamports - staked lamports
Withdraw(u64),
/// Deactivates the stake in the account
///
/// Expects 2 Accounts:
/// 0 - Delegate StakeAccount
/// 1 - Syscall Account that carries epoch
Deactivate,
}
pub fn create_stake_account(
@ -77,6 +95,23 @@ pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey, stake: u64) -
Instruction::new(id(), &StakeInstruction::DelegateStake(stake), account_metas)
}
pub fn withdraw(stake_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
let account_metas = vec![
AccountMeta::new(*stake_pubkey, true),
AccountMeta::new(*to_pubkey, false),
AccountMeta::new(syscall::current::id(), false),
];
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
}
pub fn deactivate_stake(stake_pubkey: &Pubkey) -> Instruction {
let account_metas = vec![
AccountMeta::new(*stake_pubkey, true),
AccountMeta::new(syscall::current::id(), false),
];
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
}
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &mut [KeyedAccount],
@ -123,6 +158,27 @@ pub fn process_instruction(
&syscall::rewards::from_keyed_account(&rest[0])?,
)
}
StakeInstruction::Withdraw(lamports) => {
if rest.len() != 2 {
Err(InstructionError::InvalidInstructionData)?;
}
let (to, syscall) = &mut rest.split_at_mut(1);
let mut to = &mut to[0];
me.withdraw(
lamports,
&mut to,
&syscall::current::from_keyed_account(&syscall[0])?,
)
}
StakeInstruction::Deactivate => {
if rest.len() != 1 {
Err(InstructionError::InvalidInstructionData)?;
}
let syscall = &rest[0];
me.deactivate_stake(&syscall::current::from_keyed_account(&syscall)?)
}
}
}
@ -168,6 +224,14 @@ mod tests {
process_instruction(&delegate_stake(&Pubkey::default(), &Pubkey::default(), 0)),
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&withdraw(&Pubkey::default(), &Pubkey::new_rand(), 100)),
Err(InstructionError::InvalidAccountData),
);
assert_eq!(
process_instruction(&deactivate_stake(&Pubkey::default())),
Err(InstructionError::InvalidAccountData),
);
}
#[test]
@ -250,6 +314,76 @@ mod tests {
),
Err(InstructionError::InvalidAccountData),
);
// Tests 3rd keyed account is of correct type (Current instead of rewards) in withdraw
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(
&syscall::rewards::id(),
false,
&mut syscall::rewards::create_account(1, 0.0, 0.0)
),
],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
),
Err(InstructionError::InvalidArgument),
);
// Tests correct number of accounts are provided in withdraw
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(
&syscall::current::id(),
false,
&mut syscall::rewards::create_account(1, 0.0, 0.0)
),
],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
),
Err(InstructionError::InvalidInstructionData),
);
// Tests 2nd keyed account is of correct type (Current instead of rewards) in deactivate
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(
&syscall::rewards::id(),
false,
&mut syscall::rewards::create_account(1, 0.0, 0.0)
),
],
&serialize(&StakeInstruction::Deactivate).unwrap(),
),
Err(InstructionError::InvalidArgument),
);
// Tests correct number of accounts are provided in deactivate
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&mut [
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
KeyedAccount::new(
&syscall::current::id(),
false,
&mut syscall::rewards::create_account(1, 0.0, 0.0)
),
],
&serialize(&StakeInstruction::Deactivate).unwrap(),
),
Err(InstructionError::InvalidInstructionData),
);
}
}

View File

@ -12,6 +12,7 @@ use solana_sdk::pubkey::Pubkey;
use solana_sdk::syscall;
use solana_sdk::timing::Epoch;
use solana_vote_api::vote_state::VoteState;
use std::cmp;
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum StakeState {
@ -196,6 +197,12 @@ pub trait StakeAccount {
rewards_account: &mut KeyedAccount,
rewards: &syscall::rewards::Rewards,
) -> Result<(), InstructionError>;
fn withdraw(
&mut self,
lamports: u64,
to: &mut KeyedAccount,
current: &syscall::current::Current,
) -> Result<(), InstructionError>;
}
impl<'a> StakeAccount for KeyedAccount<'a> {
@ -281,6 +288,44 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
Err(InstructionError::InvalidAccountData)
}
}
fn withdraw(
&mut self,
lamports: u64,
to: &mut KeyedAccount,
current: &syscall::current::Current,
) -> Result<(), InstructionError> {
if self.signer_key().is_none() {
return Err(InstructionError::MissingRequiredSignature);
}
match self.state()? {
StakeState::Stake(mut stake) => {
let staked = if stake.stake(current.epoch) == 0 {
0
} else {
// Assume full stake if the stake is under warmup/cooldown
stake.stake
};
if lamports > self.account.lamports.saturating_sub(staked) {
return Err(InstructionError::InsufficientFunds);
}
self.account.lamports -= lamports;
// Adjust the stake (in case balance dropped below stake)
stake.stake = cmp::min(stake.stake, self.account.lamports);
to.account.lamports += lamports;
Ok(())
}
StakeState::Uninitialized => {
if lamports > self.account.lamports {
return Err(InstructionError::InsufficientFunds);
}
self.account.lamports -= lamports;
to.account.lamports += lamports;
Ok(())
}
_ => Err(InstructionError::InvalidAccountData),
}
}
}
// utility function, used by Bank, tests, genesis
@ -316,6 +361,7 @@ mod tests {
use solana_sdk::account::Account;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_program;
use solana_vote_api::vote_state;
#[test]
@ -418,6 +464,181 @@ mod tests {
assert_eq!(stake.stake(STAKE_WARMUP_EPOCHS * 42), 0);
}
#[test]
fn test_deactivate_stake() {
let stake_pubkey = Pubkey::new_rand();
let stake_lamports = 42;
let mut stake_account =
Account::new(stake_lamports, std::mem::size_of::<StakeState>(), &id());
let current = syscall::current::Current::default();
// unsigned keyed account
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
assert_eq!(
stake_keyed_account.deactivate_stake(&current),
Err(InstructionError::MissingRequiredSignature)
);
// signed keyed account but not staked yet
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
assert_eq!(
stake_keyed_account.deactivate_stake(&current),
Err(InstructionError::InvalidAccountData)
);
// Staking
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
assert_eq!(
stake_keyed_account.delegate_stake(&vote_keyed_account, stake_lamports, &current),
Ok(())
);
// Deactivate after staking
assert_eq!(stake_keyed_account.deactivate_stake(&current), Ok(()));
}
#[test]
fn test_withdraw_stake() {
let stake_pubkey = Pubkey::new_rand();
let mut total_lamports = 100;
let stake_lamports = 42;
let mut stake_account =
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
let current = syscall::current::Current::default();
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
// unsigned keyed account
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &mut stake_account);
assert_eq!(
stake_keyed_account.withdraw(total_lamports, &mut to_keyed_account, &current),
Err(InstructionError::MissingRequiredSignature)
);
// signed keyed account but uninitialized
// try withdrawing more than balance
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
assert_eq!(
stake_keyed_account.withdraw(total_lamports + 1, &mut to_keyed_account, &current),
Err(InstructionError::InsufficientFunds)
);
// try withdrawing some (enough for rest of the test to carry forward)
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
assert_eq!(
stake_keyed_account.withdraw(5, &mut to_keyed_account, &current),
Ok(())
);
total_lamports -= 5;
// Stake some lamports (available lampoorts for withdrawls will reduce)
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
assert_eq!(
stake_keyed_account.delegate_stake(&vote_keyed_account, stake_lamports, &current),
Ok(())
);
// Try to withdraw more than what's available
assert_eq!(
stake_keyed_account.withdraw(
total_lamports - stake_lamports + 1,
&mut to_keyed_account,
&current
),
Err(InstructionError::InsufficientFunds)
);
// Try to withdraw all unstaked lamports
assert_eq!(
stake_keyed_account.withdraw(
total_lamports - stake_lamports,
&mut to_keyed_account,
&current
),
Ok(())
);
}
#[test]
fn test_withdraw_stake_before_warmup() {
let stake_pubkey = Pubkey::new_rand();
let total_lamports = 100;
let stake_lamports = 42;
let mut stake_account =
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
let current = syscall::current::Current::default();
let mut future = syscall::current::Current::default();
future.epoch += 16;
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
// Stake some lamports (available lampoorts for withdrawls will reduce)
let vote_pubkey = Pubkey::new_rand();
let mut vote_account =
vote_state::create_account(&vote_pubkey, &Pubkey::new_rand(), 0, 100);
let mut vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &mut vote_account);
vote_keyed_account.set_state(&VoteState::default()).unwrap();
assert_eq!(
stake_keyed_account.delegate_stake(&vote_keyed_account, stake_lamports, &future),
Ok(())
);
// Try to withdraw including staked
assert_eq!(
stake_keyed_account.withdraw(
total_lamports - stake_lamports + 1,
&mut to_keyed_account,
&current
),
Ok(())
);
}
#[test]
fn test_withdraw_stake_invalid_state() {
let stake_pubkey = Pubkey::new_rand();
let total_lamports = 100;
let mut stake_account =
Account::new(total_lamports, std::mem::size_of::<StakeState>(), &id());
let current = syscall::current::Current::default();
let mut future = syscall::current::Current::default();
future.epoch += 16;
let to = Pubkey::new_rand();
let mut to_account = Account::new(1, 0, &system_program::id());
let mut to_keyed_account = KeyedAccount::new(&to, false, &mut to_account);
let mut stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &mut stake_account);
let stake_state = StakeState::MiningPool {
epoch: 0,
point_value: 0.0,
};
stake_keyed_account.set_state(&stake_state).unwrap();
assert_eq!(
stake_keyed_account.withdraw(total_lamports, &mut to_keyed_account, &current),
Err(InstructionError::InvalidAccountData)
);
}
#[test]
fn test_stake_state_calculate_rewards() {
let mut vote_state = VoteState::default();
@ -486,7 +707,7 @@ mod tests {
None, // would be Some((0, 2 * 1 + 1 * 2, 3)),
stake.calculate_rewards(1.0, &vote_state)
);
vote_state.commission = std::u32::MAX - 1;
vote_state.commission = std::u8::MAX - 1;
assert_eq!(
None, // would be pSome((0, 2 * 1 + 1 * 2, 3)),
stake.calculate_rewards(1.0, &vote_state)

View File

@ -1,6 +1,6 @@
[package]
name = "solana-stake-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana stake program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,9 +10,9 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-stake-api = { path = "../stake_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana-stake-api = { path = "../stake_api", version = "0.16.3" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -0,0 +1,251 @@
use assert_matches::assert_matches;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::genesis_utils::{create_genesis_block, GenesisBlockInfo};
use solana_sdk::account_utils::State;
use solana_sdk::client::SyncClient;
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::syscall;
use solana_sdk::syscall::rewards::Rewards;
use solana_stake_api::id;
use solana_stake_api::stake_instruction;
use solana_stake_api::stake_instruction::process_instruction;
use solana_stake_api::stake_state::StakeState;
use solana_vote_api::vote_instruction;
use solana_vote_api::vote_state::{Vote, VoteState};
use std::sync::Arc;
fn fill_epoch_with_votes(
bank: &Arc<Bank>,
vote_keypair: &Keypair,
mint_keypair: &Keypair,
) -> Arc<Bank> {
let mint_pubkey = mint_keypair.pubkey();
let vote_pubkey = vote_keypair.pubkey();
let old_epoch = bank.epoch();
let mut bank = bank.clone();
while bank.epoch() != old_epoch + 1 {
bank = Arc::new(Bank::new_from_parent(
&bank,
&Pubkey::default(),
1 + bank.slot(),
));
let bank_client = BankClient::new_shared(&bank);
let parent = bank.parent().unwrap();
let message = Message::new_with_payer(
vec![vote_instruction::vote(
&vote_pubkey,
&vote_pubkey,
vec![Vote::new(parent.slot() as u64, parent.hash())],
)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &vote_keypair], message)
.is_ok());
}
bank
}
#[test]
fn test_stake_account_delegate() {
let staker_keypair = Keypair::new();
let staker_pubkey = staker_keypair.pubkey();
let vote_keypair = Keypair::new();
let vote_pubkey = vote_keypair.pubkey();
let node_pubkey = Pubkey::new_rand();
let GenesisBlockInfo {
mut genesis_block,
mint_keypair,
..
} = create_genesis_block(100_000_000_000);
genesis_block
.native_instruction_processors
.push(solana_stake_program::solana_stake_program!());
let bank = Bank::new(&genesis_block);
let mint_pubkey = mint_keypair.pubkey();
let mut bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
// Create Vote Account
let message = Message::new(vote_instruction::create_account(
&mint_pubkey,
&vote_pubkey,
&node_pubkey,
std::u8::MAX / 2,
10,
));
bank_client
.send_message(&[&mint_keypair], message)
.expect("failed to create vote account");
// Create stake account and delegate to vote account
let message = Message::new(stake_instruction::create_stake_account_and_delegate_stake(
&mint_pubkey,
&staker_pubkey,
&vote_pubkey,
20000,
));
bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.expect("failed to create and delegate stake account");
// Test that correct lamports are staked
let account = bank.get_account(&staker_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(stake) = stake_state {
assert_eq!(stake.stake, 20000);
} else {
assert!(false, "wrong account type found")
}
// Test that we cannot withdraw staked lamports
let message = Message::new_with_payer(
vec![stake_instruction::withdraw(
&staker_pubkey,
&Pubkey::new_rand(),
20000,
)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.is_err());
// Test that lamports are still staked
let account = bank.get_account(&staker_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(stake) = stake_state {
assert_eq!(stake.stake, 20000);
} else {
assert!(false, "wrong account type found")
}
// Reward redemption
// Submit enough votes to generate rewards
let old_epoch = bank.epoch();
bank = fill_epoch_with_votes(&bank, &vote_keypair, &mint_keypair);
// Test that votes and credits are there
let account = bank.get_account(&vote_pubkey).expect("account not found");
let vote_state: VoteState = account.state().expect("couldn't unpack account data");
// 1 less vote, as the first vote should have cleared the lockout
assert_eq!(vote_state.votes.len(), 31);
assert_eq!(vote_state.credits(), 1);
assert_ne!(old_epoch, bank.epoch());
// Cycle thru banks until we reach next epoch
bank = fill_epoch_with_votes(&bank, &vote_keypair, &mint_keypair);
// Test that rewards are there
let rewards_account = bank
.get_account(&syscall::rewards::id())
.expect("account not found");
assert_matches!(Rewards::from(&rewards_account), Some(_));
// Redeem the credit
let bank_client = BankClient::new_shared(&bank);
let message = Message::new_with_payer(
vec![stake_instruction::redeem_vote_credits(
&staker_pubkey,
&vote_pubkey,
)],
Some(&mint_pubkey),
);
assert_matches!(bank_client.send_message(&[&mint_keypair], message), Ok(_));
// Test that balance increased, and calculate the rewards
let rewards;
let account = bank.get_account(&staker_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(stake) = stake_state {
assert!(account.lamports > 20000);
assert_eq!(stake.stake, 20000);
rewards = account.lamports - 20000;
} else {
rewards = 0;
assert!(false, "wrong account type found")
}
// Deactivate the stake
let message = Message::new_with_payer(
vec![stake_instruction::deactivate_stake(&staker_pubkey)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.is_ok());
// Test that we cannot withdraw staked lamports due to cooldown period
let message = Message::new_with_payer(
vec![stake_instruction::withdraw(
&staker_pubkey,
&Pubkey::new_rand(),
20000,
)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.is_err());
let old_epoch = bank.epoch();
let slots = bank.get_slots_in_epoch(old_epoch);
// Create a new bank at later epoch (within cooldown period)
let bank = Bank::new_from_parent(&bank, &Pubkey::default(), slots + bank.slot());
assert_ne!(old_epoch, bank.epoch());
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let message = Message::new_with_payer(
vec![stake_instruction::withdraw(
&staker_pubkey,
&Pubkey::new_rand(),
20000,
)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.is_err());
// Create a new bank at later epoch (to account for cooldown of stake)
let mut bank = Bank::new_from_parent(
&bank,
&Pubkey::default(),
genesis_block.slots_per_epoch * 4 + bank.slot(),
);
bank.add_instruction_processor(id(), process_instruction);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
// Test that we can withdraw now
let message = Message::new_with_payer(
vec![stake_instruction::withdraw(
&staker_pubkey,
&Pubkey::new_rand(),
20000,
)],
Some(&mint_pubkey),
);
assert!(bank_client
.send_message(&[&mint_keypair, &staker_keypair], message)
.is_ok());
// Test that balance and stake is updated correctly (we have withdrawn all lamports except rewards)
let account = bank.get_account(&staker_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(stake) = stake_state {
assert_eq!(account.lamports, rewards);
assert_eq!(stake.stake, rewards);
} else {
assert!(false, "wrong account type found")
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-storage-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana Storage program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,12 +12,13 @@ edition = "2018"
assert_matches = "1.3.0"
bincode = "1.1.4"
log = "0.4.2"
rand = "0.6.5"
num-derive = "0.2"
num-traits = "0.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["lib"]

View File

@ -1,3 +1,4 @@
pub mod rewards_pools;
pub mod storage_contract;
pub mod storage_instruction;
pub mod storage_processor;

View File

@ -0,0 +1,63 @@
//! rewards_pools
//! * initialize genesis with rewards pools
//! * keep track of rewards
//! * own mining pools
use crate::storage_contract::create_rewards_pool;
use rand::{thread_rng, Rng};
use solana_sdk::genesis_block::Builder;
use solana_sdk::hash::{hash, Hash};
use solana_sdk::pubkey::Pubkey;
// base rewards pool ID
const ID: [u8; 32] = [
6, 162, 25, 123, 127, 71, 141, 232, 129, 171, 58, 183, 79, 88, 181, 17, 163, 11, 51, 111, 22,
123, 67, 115, 5, 131, 109, 161, 16, 0, 0, 0,
];
solana_sdk::solana_name_id!(ID, "StorageMiningPoo111111111111111111111111111");
// to cut down on collisions for redemptions, we make multiple accounts
pub const NUM_REWARDS_POOLS: usize = 32;
pub fn genesis(mut builder: Builder) -> Builder {
let mut pubkey = id();
for _i in 0..NUM_REWARDS_POOLS {
builder = builder.rewards_pool(pubkey, create_rewards_pool());
pubkey = Pubkey::new(hash(pubkey.as_ref()).as_ref());
}
builder
}
pub fn random_id() -> Pubkey {
let mut id = Hash::new(&ID);
for _i in 0..thread_rng().gen_range(0, NUM_REWARDS_POOLS) {
id = hash(id.as_ref());
}
Pubkey::new(id.as_ref())
}
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::genesis_block::Builder;
#[test]
fn test() {
let builder = Builder::new();
let genesis_block = genesis(builder).build();
for _i in 0..NUM_REWARDS_POOLS {
let id = random_id();
assert!(genesis_block
.rewards_pools
.iter()
.position(|x| x.0 == id)
.is_some());
}
}
}

View File

@ -79,7 +79,7 @@ pub enum StorageContract {
reward_validations: BTreeMap<usize, BTreeMap<Pubkey, Vec<ProofStatus>>>,
},
MiningPool,
RewardsPool,
}
// utility function, used by Bank, tests, genesis
@ -99,17 +99,6 @@ pub fn create_validator_storage_account(owner: Pubkey, lamports: u64) -> Account
storage_account
}
// utility function, used by genesis
pub fn create_mining_pool_account(lamports: u64) -> Account {
let mut storage_account = Account::new(lamports, STORAGE_ACCOUNT_SPACE as usize, &crate::id());
storage_account
.set_state(&StorageContract::MiningPool)
.expect("set_state");
storage_account
}
pub struct StorageAccount<'a> {
pub(crate) id: Pubkey,
account: &'a mut Account,
@ -120,16 +109,6 @@ impl<'a> StorageAccount<'a> {
Self { id, account }
}
pub fn initialize_mining_pool(&mut self) -> Result<(), InstructionError> {
let storage_contract = &mut self.account.state()?;
if let StorageContract::Uninitialized = storage_contract {
*storage_contract = StorageContract::MiningPool;
self.account.set_state(storage_contract)
} else {
Err(InstructionError::AccountAlreadyInitialized)?
}
}
pub fn initialize_replicator_storage(&mut self, owner: Pubkey) -> Result<(), InstructionError> {
let storage_contract = &mut self.account.state()?;
if let StorageContract::Uninitialized = storage_contract {
@ -379,7 +358,7 @@ impl<'a> StorageAccount<'a> {
pub fn claim_storage_reward(
&mut self,
mining_pool: &mut KeyedAccount,
rewards_pool: &mut KeyedAccount,
owner: &mut StorageAccount,
) -> Result<(), InstructionError> {
let mut storage_contract = &mut self.account.state()?;
@ -395,17 +374,10 @@ impl<'a> StorageAccount<'a> {
StorageError::InvalidOwner as u32,
))?
}
let pending = *pending_lamports;
if mining_pool.account.lamports < pending {
Err(InstructionError::CustomError(
StorageError::RewardPoolDepleted as u32,
))?
}
mining_pool.account.lamports -= pending;
owner.account.lamports += pending;
redeem(*pending_lamports, rewards_pool, owner)?;
//clear pending_lamports
*pending_lamports = 0;
self.account.set_state(storage_contract)
} else if let StorageContract::ReplicatorStorage {
owner: account_owner,
@ -429,11 +401,10 @@ impl<'a> StorageAccount<'a> {
})
.collect::<Vec<_>>();
reward_validations.clear();
let total_proofs = checked_proofs.len() as u64;
let num_validations = count_valid_proofs(&checked_proofs);
let reward = num_validations * REPLICATOR_REWARD * (num_validations / total_proofs);
mining_pool.account.lamports -= reward;
owner.account.lamports += reward;
let reward = num_validations * REPLICATOR_REWARD;
redeem(reward, rewards_pool, owner)?;
self.account.set_state(storage_contract)
} else {
Err(InstructionError::InvalidArgument)?
@ -441,6 +412,25 @@ impl<'a> StorageAccount<'a> {
}
}
fn redeem(
rewards: u64,
rewards_pool: &mut KeyedAccount,
owner: &mut StorageAccount,
) -> Result<(), InstructionError> {
if rewards_pool.account.lamports < rewards {
Err(InstructionError::CustomError(
StorageError::RewardPoolDepleted as u32,
))?
}
rewards_pool.account.lamports -= rewards;
owner.account.lamports += rewards;
Ok(())
}
pub fn create_rewards_pool() -> Account {
Account::new_data(std::u64::MAX, &StorageContract::RewardsPool, &crate::id()).unwrap()
}
/// Store the result of a proof validation into the replicator account
fn store_validation_result(
me: &Pubkey,
@ -486,7 +476,7 @@ fn count_valid_proofs(proofs: &[ProofStatus]) -> u64 {
#[cfg(test)]
mod tests {
use super::*;
use crate::id;
use crate::{id, rewards_pools};
use std::collections::BTreeMap;
#[test]
@ -586,4 +576,35 @@ mod tests {
)
.unwrap();
}
#[test]
fn test_redeem() {
let reward = 100;
let mut owner_account = Account {
lamports: 1,
..Account::default()
};
let mut rewards_pool = create_rewards_pool();
let pool_id = rewards_pools::id();
let mut keyed_pool_account = KeyedAccount::new(&pool_id, false, &mut rewards_pool);
let mut owner = StorageAccount {
id: Pubkey::default(),
account: &mut owner_account,
};
// check that redeeming from depleted pools fails
keyed_pool_account.account.lamports = 0;
assert_eq!(
redeem(reward, &mut keyed_pool_account, &mut owner),
Err(InstructionError::CustomError(
StorageError::RewardPoolDepleted as u32,
))
);
assert_eq!(owner.account.lamports, 1);
keyed_pool_account.account.lamports = 200;
assert_eq!(redeem(reward, &mut keyed_pool_account, &mut owner), Ok(()));
// check that the owner's balance increases
assert_eq!(owner.account.lamports, 101);
}
}

View File

@ -1,5 +1,5 @@
use crate::id;
use crate::storage_contract::{ProofStatus, STORAGE_ACCOUNT_SPACE};
use crate::{id, rewards_pools};
use serde_derive::{Deserialize, Serialize};
use solana_sdk::hash::Hash;
use solana_sdk::instruction::{AccountMeta, Instruction};
@ -10,11 +10,10 @@ use solana_sdk::system_instruction;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum StorageInstruction {
/// Initialize the account as a mining pool, validator or replicator
/// Initialize the account as a validator or replicator
///
/// Expects 1 Account:
/// 0 - Account to be initialized
InitializeMiningPool,
InitializeValidatorStorage {
owner: Pubkey,
},
@ -128,27 +127,6 @@ pub fn create_replicator_storage_account(
]
}
pub fn create_mining_pool_account(
from_pubkey: &Pubkey,
storage_pubkey: &Pubkey,
lamports: u64,
) -> Vec<Instruction> {
vec![
system_instruction::create_account(
from_pubkey,
storage_pubkey,
lamports,
STORAGE_ACCOUNT_SPACE,
&id(),
),
Instruction::new(
id(),
&StorageInstruction::InitializeMiningPool,
vec![AccountMeta::new(*storage_pubkey, false)],
),
]
}
pub fn mining_proof(
storage_pubkey: &Pubkey,
sha_state: Hash,
@ -200,15 +178,11 @@ pub fn proof_validation(
Instruction::new(id(), &storage_instruction, account_metas)
}
pub fn claim_reward(
owner_pubkey: &Pubkey,
storage_pubkey: &Pubkey,
mining_pool_pubkey: &Pubkey,
) -> Instruction {
pub fn claim_reward(owner_pubkey: &Pubkey, storage_pubkey: &Pubkey) -> Instruction {
let storage_instruction = StorageInstruction::ClaimStorageReward;
let account_metas = vec![
AccountMeta::new(*storage_pubkey, false),
AccountMeta::new(*mining_pool_pubkey, false),
AccountMeta::new(rewards_pools::random_id(), false),
AccountMeta::new(*owner_pubkey, false),
];
Instruction::new(id(), &storage_instruction, account_metas)

View File

@ -20,12 +20,6 @@ pub fn process_instruction(
let mut storage_account = StorageAccount::new(*me[0].unsigned_key(), &mut me[0].account);
match bincode::deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
StorageInstruction::InitializeMiningPool => {
if !rest.is_empty() {
Err(InstructionError::InvalidArgument)?;
}
storage_account.initialize_mining_pool()
}
StorageInstruction::InitializeReplicatorStorage { owner } => {
if !rest.is_empty() {
Err(InstructionError::InvalidArgument)?;

View File

@ -1,6 +1,6 @@
[package]
name = "solana-storage-program"
version = "0.16.0"
version = "0.16.3"
description = "Solana storage program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,12 +10,12 @@ edition = "2018"
[dependencies]
log = "0.4.2"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-storage-api = { path = "../storage_api", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
solana-storage-api = { path = "../storage_api", version = "0.16.3" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.16.0" }
solana-runtime = { path = "../../runtime", version = "0.16.3" }
assert_matches = "1.3.0"
bincode = "1.1.4"

View File

@ -3,10 +3,10 @@ use bincode::deserialize;
use log::*;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::genesis_utils::{create_genesis_block, GenesisBlockInfo};
use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount};
use solana_sdk::account_utils::State;
use solana_sdk::client::SyncClient;
use solana_sdk::genesis_block::create_genesis_block;
use solana_sdk::hash::{hash, Hash};
use solana_sdk::instruction::{Instruction, InstructionError};
use solana_sdk::message::Message;
@ -53,7 +53,11 @@ fn test_account_owner() {
let validator_storage_pubkey = Pubkey::new_rand();
let replicator_storage_pubkey = Pubkey::new_rand();
let (genesis_block, mint_keypair) = create_genesis_block(1000);
let GenesisBlockInfo {
genesis_block,
mint_keypair,
..
} = create_genesis_block(1000);
let mut bank = Bank::new(&genesis_block);
let mint_pubkey = mint_keypair.pubkey();
bank.add_instruction_processor(id(), process_instruction);
@ -259,7 +263,11 @@ fn test_submit_mining_ok() {
#[test]
fn test_validate_mining() {
solana_logger::setup();
let (mut genesis_block, mint_keypair) = create_genesis_block(100_000);
let GenesisBlockInfo {
mut genesis_block,
mint_keypair,
..
} = create_genesis_block(100_000);
genesis_block
.native_instruction_processors
.push(solana_storage_program::solana_storage_program!());
@ -276,9 +284,6 @@ fn test_validate_mining() {
let validator_storage_keypair = Keypair::new();
let validator_storage_id = validator_storage_keypair.pubkey();
let mining_pool_keypair = Keypair::new();
let mining_pool_pubkey = mining_pool_keypair.pubkey();
let bank = Bank::new(&genesis_block);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
@ -291,12 +296,6 @@ fn test_validate_mining() {
&[&replicator_1_storage_id, &replicator_2_storage_id],
10,
);
let message = Message::new(storage_instruction::create_mining_pool_account(
&mint_pubkey,
&mining_pool_pubkey,
10_000,
));
bank_client.send_message(&[&mint_keypair], message).unwrap();
// create a new bank in segment 2
let bank = Arc::new(Bank::new_from_parent(
@ -407,7 +406,6 @@ fn test_validate_mining() {
vec![storage_instruction::claim_reward(
&owner_pubkey,
&validator_storage_id,
&mining_pool_pubkey,
)],
Some(&mint_pubkey),
);
@ -431,7 +429,6 @@ fn test_validate_mining() {
vec![storage_instruction::claim_reward(
&owner_pubkey,
&replicator_1_storage_id,
&mining_pool_pubkey,
)],
Some(&mint_pubkey),
);
@ -447,7 +444,6 @@ fn test_validate_mining() {
vec![storage_instruction::claim_reward(
&owner_pubkey,
&replicator_2_storage_id,
&mining_pool_pubkey,
)],
Some(&mint_pubkey),
);
@ -561,7 +557,11 @@ fn get_storage_blockhash<C: SyncClient>(client: &C, account: &Pubkey) -> Hash {
#[test]
fn test_bank_storage() {
let (mut genesis_block, mint_keypair) = create_genesis_block(1000);
let GenesisBlockInfo {
mut genesis_block,
mint_keypair,
..
} = create_genesis_block(1000);
genesis_block
.native_instruction_processors
.push(solana_storage_program::solana_storage_program!());

View File

@ -1,6 +1,6 @@
[package]
name = "solana-token-api"
version = "0.16.0"
version = "0.16.3"
description = "Solana Token API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -15,8 +15,8 @@ num-derive = "0.2"
num-traits = "0.2"
serde = "1.0.92"
serde_derive = "1.0.92"
solana-logger = { path = "../../logger", version = "0.16.0" }
solana-sdk = { path = "../../sdk", version = "0.16.0" }
solana-logger = { path = "../../logger", version = "0.16.3" }
solana-sdk = { path = "../../sdk", version = "0.16.3" }
[lib]
crate-type = ["lib"]

Some files were not shown because too many files have changed in this diff Show More