Compare commits

...

36 Commits

Author SHA1 Message Date
d6d3a3c3d8 getBlockTime: Fix RootedSlotIterator lowest root (#7681) (#7687)
automerge
2020-01-05 23:24:34 -08:00
3e229b248f Update getBlockTime rpc docs (#7688) (#7689)
automerge
2020-01-05 23:16:04 -08:00
0470072436 Cli: fund validator-info accounts with rent-exempt lamports
(cherry picked from commit 580ca36a62)
2020-01-04 23:20:38 -07:00
f74fa60c8b Revert "Add a stand-alone gossip node on the blocksteamer instance"
This reverts commit a217920561.

This commit is causing trouble when the TdS cluster is reset and
validators running an older genesis config are still present.
Occasionally an RPC URL from an older validator will be selected,
causing a new node to fail to boot.
2020-01-04 16:44:28 -07:00
c189767090 Bump version to 0.22.2 2020-01-04 14:17:42 -07:00
c82c18353d Don't panic if peer_addr() fails (#7678) (#7679)
automerge
2020-01-04 10:39:22 -08:00
da58a272dd Set default vote account commission to 100% (#7677)
automerge
2020-01-04 09:52:33 -08:00
001f5fbb6b bank: Prune older epoch stakes (bp #7668) (#7676)
automerge
2020-01-04 09:32:16 -08:00
63cd452ab5 Minor book fixes 2020-01-04 08:53:51 -07:00
6ee77e9754 Make validator timestamping more coincident, and increase timestamp sample range (#7673) (#7674)
automerge
2020-01-03 23:30:12 -08:00
cee22262fc Move nonce into system program (bp #7645) (#7671)
automerge
2020-01-03 18:33:40 -08:00
0d13352916 CLI: Fix default nonce authority resolution (#7657) (#7672)
automerge
2020-01-03 17:18:43 -08:00
78a9832f13 Measure heap usage while processing the ledger at validator startup (bp #7667) (#7670)
automerge
2020-01-03 15:43:11 -08:00
795cf14650 Publish bpf-sdk only in Linux build
(cherry picked from commit 078e7246ac)
2020-01-02 23:22:29 -07:00
8c112e8bc4 Publish bpf-sdk releases (#7655) (#7662)
automerge
2020-01-02 21:25:59 -08:00
8e6d213459 Revert "Remov dead code from TdS testnet manager config (#7414)"
This reverts commit 8920ac02f6.
2020-01-02 21:07:23 -07:00
b33df42640 net: Add a stand-alone gossip node on the blocksteamer instance (bp #7654) (#7659)
automerge
2020-01-02 17:26:40 -08:00
e0462e6933 Book - Document nonceable CLI subcommands (#7656) (#7660)
automerge
2020-01-02 17:14:08 -08:00
1f5e30a366 Add input validation for --creation-time/--lockup-date args (#7646) (#7647)
automerge
2019-12-30 22:39:51 -08:00
633eeb1586 Book: Document CLI durable nonce account management (#7595) (#7640)
automerge
2019-12-30 10:17:23 -08:00
c1148a6da3 Use lamports in genesis (#7631) (#7634)
automerge
2019-12-29 10:22:28 -08:00
713e86670d Use lamports in genesis (#7631) (#7633)
automerge
2019-12-29 10:17:16 -08:00
c004c726e7 Support nonced transactions in the CLI (#7624) (#7630)
automerge
2019-12-27 13:22:06 -08:00
5ffb8631e0 Account for rent (#7626) (#7627)
automerge
2019-12-24 18:41:22 -08:00
fd32a0280e Cargo.lock 2019-12-24 09:12:11 -07:00
e76f202eb3 Update gitbook-cage first 2019-12-23 18:17:43 -07:00
ba4558cb92 Update cargo files to 0.22.1 (#7620) 2019-12-23 19:42:33 -05:00
74e5577dd4 Move cleanup to a script so it doesn't kill itself (#7603) (#7619)
automerge
2019-12-23 15:23:47 -08:00
b878002cf5 Specify version for solana-sdk-macro to enable crate.io publishing (#7616) 2019-12-23 12:38:21 -08:00
f111250e3b Groom log messages (#7610) (#7614)
automerge
2019-12-23 10:29:15 -08:00
3d91f650db Fix key in genesis (#7585) (#7608)
automerge
2019-12-22 22:41:01 -08:00
91a88cda6a show-block-production: Rename "missed" to "skipped" as not all skipped slots are missed slots (#7599) (#7607)
(cherry picked from commit 419da18405)

Co-authored-by: Michael Vines <mvines@gmail.com>
2019-12-22 23:21:24 -07:00
2128c17ed0 Extend Stable CI job timeout to 60 minutes (#7604) (#7606)
automerge
2019-12-22 19:57:43 -08:00
7b819c9b74 MISSED -> SKIPPED 2019-12-22 10:19:12 -07:00
eec5c661af Remove stray SOLANA_CUDA=1 2019-12-22 10:09:26 -07:00
0398f6b87a ledger-tool: Add --all option to bounds, to display all non-empty slots (#7592) (#7598)
automerge
2019-12-20 21:30:47 -08:00
141 changed files with 3551 additions and 2071 deletions

589
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-archiver"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -10,10 +10,10 @@ homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
console = "0.9.1"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -10,11 +10,11 @@ homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.2.0"
solana-core = { path = "../core", version = "0.22.0" }
solana-ledger = { path = "../ledger", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-measure = { path = "../measure", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.2" }
solana-ledger = { path = "../ledger", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-measure = { path = "../measure", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
rand = "0.6.5"
crossbeam-channel = "0.3"

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -23,19 +23,19 @@ serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-genesis = { path = "../genesis", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-faucet = { path = "../faucet", version = "0.22.0" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-genesis = { path = "../genesis", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-faucet = { path = "../faucet", version = "0.22.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
untrusted = "0.7.0"
ws = "0.9.1"
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "0.22.0" }
solana-local-cluster = { path = "../local-cluster", version = "0.22.2" }

View File

@ -2,14 +2,14 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-tps"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,24 +16,24 @@ serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-genesis = { path = "../genesis", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-faucet = { path = "../faucet", version = "0.22.0" }
solana-librapay = { path = "../programs/librapay", version = "0.22.0", optional = true }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-measure = { path = "../measure", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-move-loader-program = { path = "../programs/move_loader", version = "0.22.0", optional = true }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-genesis = { path = "../genesis", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-faucet = { path = "../faucet", version = "0.22.2" }
solana-librapay = { path = "../programs/librapay", version = "0.22.2", optional = true }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-measure = { path = "../measure", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-move-loader-program = { path = "../programs/move_loader", version = "0.22.2", optional = true }
[dev-dependencies]
serial_test = "0.3.2"
serial_test_derive = "0.3.1"
solana-local-cluster = { path = "../local-cluster", version = "0.22.0" }
solana-local-cluster = { path = "../local-cluster", version = "0.22.2" }
[features]
move = ["solana-librapay", "solana-move-loader-program"]

View File

@ -39,6 +39,7 @@
* [Installation](paper-wallet/installation.md)
* [Paper Wallet Usage](paper-wallet/usage.md)
* [Offline Signing](offline-signing/README.md)
* [Durable Transaction Nonces](offline-signing/durable-nonce.md)
* [API Reference](api-reference/README.md)
* [Transaction](api-reference/transaction-api.md)
* [Instruction](api-reference/instruction-api.md)

View File

@ -177,7 +177,7 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
## Usage
### solana-cli
```text
solana-cli 0.22.0 [channel=unknown commit=unknown]
solana-cli 0.22.2 [channel=unknown commit=unknown]
Blockchain, Rebuilt for Scale
USAGE:
@ -201,6 +201,7 @@ OPTIONS:
SUBCOMMANDS:
address Get your public key
airdrop Request lamports
authorize-nonce-account Assign account authority to a new entity
balance Get your balance
cancel Cancel a transfer
catchup Wait for a validator to catch up to the cluster
@ -305,6 +306,35 @@ ARGS:
<UNIT> Specify unit to use for request and balance display [possible values: SOL, lamports]
```
#### solana-authorize-nonce-account
```text
solana-authorize-nonce-account
Assign account authority to a new entity
USAGE:
solana authorize-nonce-account [FLAGS] [OPTIONS] <NONCE_ACCOUNT> <NEW_AUTHORITY_PUBKEY>
FLAGS:
-h, --help Prints help information
--skip-seed-phrase-validation Skip validation of seed phrases. Use this if your phrase does not use the BIP39
official English word list
-V, --version Prints version information
-v, --verbose Show extra information header
OPTIONS:
--ask-seed-phrase <KEYPAIR NAME> Securely recover a keypair using a seed phrase and optional passphrase
[possible values: keypair]
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--nonce-authority <KEYPAIR> Specify nonce authority if different from account
ARGS:
<NONCE_ACCOUNT> Address of the nonce account
<NEW_AUTHORITY_PUBKEY> Account to be granted authority of the nonce account
```
#### solana-balance
```text
solana-balance
@ -664,14 +694,20 @@ FLAGS:
-v, --verbose Show extra information header
OPTIONS:
--ask-seed-phrase <KEYPAIR NAME> Securely recover a keypair using a seed phrase and optional passphrase
[possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--ask-seed-phrase <KEYPAIR NAME> Securely recover a keypair using a seed phrase and optional passphrase
[possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <nonce_authority> Provide the nonce authority keypair to use when signing a nonced
transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
ARGS:
<STAKE ACCOUNT> Stake account to be deactivated.
@ -694,14 +730,20 @@ FLAGS:
-v, --verbose Show extra information header
OPTIONS:
--ask-seed-phrase <KEYPAIR NAME> Securely recover a keypair using a seed phrase and optional passphrase
[possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--ask-seed-phrase <KEYPAIR NAME> Securely recover a keypair using a seed phrase and optional passphrase
[possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <nonce_authority> Provide the nonce authority keypair to use when signing a nonced
transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
ARGS:
<STAKE ACCOUNT> Stake account to delegate
@ -1004,6 +1046,12 @@ OPTIONS:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <nonce_authority> Provide the nonce authority keypair to use when signing a nonced
transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--after <DATETIME> A timestamp after which transaction will execute
--require-timestamp-from <PUBKEY> Require timestamp from this third party

View File

@ -157,7 +157,7 @@ The result value will be an RpcResponse JSON object containing an AccountInfo JS
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":{"context":{"slot":1},"value":{"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.22.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":{"context":{"slot":1},"value":{"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.22.2,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
@ -213,9 +213,17 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
### getBlockTime
Returns the estimated production time of a block. Validators report their UTC
time to the ledger on a regular interval. A block's time is calculated as an
offset from the median value of the most recent validator time report.
Returns the estimated production time of a block.
Each validator reports their UTC time to the ledger on a regular interval by
intermittently adding a timestamp to a Vote for a particular block. A requested
block's time is calculated from the stake-weighted mean of the Vote timestamps
in a set of recent blocks recorded on the ledger.
Nodes that are booting from snapshot or limiting ledger size (by purging old
slots) will return null timestamps for blocks below their lowest root +
`TIMESTAMP_SLOT_RANGE`. Users interested in having this historical data must
query a node that is built from genesis and retains the entire ledger.
#### Parameters:
@ -855,7 +863,7 @@ Subscribe to an account to receive notifications when the lamports or data for a
#### Notification Format:
```bash
{"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.22.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.22.2,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}}
```
### accountUnsubscribe
@ -913,7 +921,7 @@ Subscribe to a program to receive notifications when the lamports or data for a
* `object` - account info JSON object \(see [getAccountInfo](jsonrpc-api.md#getaccountinfo) for field details\)
```bash
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,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],"data":[1,1,1,0,0,0,0,0,0,0.22.0,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,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],"data":[1,1,1,0,0,0,0,0,0,0.22.2,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,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,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
```
### programUnsubscribe

View File

@ -75,3 +75,11 @@ Output
```text
4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN
```
## Buying More Time to Sign
Typically a Solana transaction must be signed and accepted by the network within
a number of slots from the blockhash in its `recent_blockhash` field (~2min at
the time of this writing). If your signing procedure takes longer than this, a
[Durable Transaction Nonce](durable-nonce.md) can give you the extra time you
need.

View File

@ -0,0 +1,289 @@
# Durable Transaction Nonces
Durable transaction nonces are a mechanism for getting around the typical
short lifetime of a transaction's [`recent_blockhash`](../transaction.md#recent-blockhash).
They are implemented as a Solana Program, the mechanics of which can be read
about in the [proposal](../implemented-proposals/durable-tx-nonces.md).
## Known Issues
### Fee Theft Opportunity
The durable nonce implementation contains a vulernability which allows for fees
to be stolen by a transaction using the feature under certain conditions. If the
transaction fails with an instruction error, the runtime rolls back the step
that advanced the stored nonce, allowing it to be replayed and fees charged.
This can be repeated until the stored nonce is successfully advanced.
- Mitigation
To minimize loss of funds, use a low-balance account to pay fees on a durable
nonce transaction.
If a transaction using the durable nonce feature fails with an instruction error,
immediately submit a new transaction that advances the nonce and will certainly
succeed. The simplest way to do this is with a single-instruction
`NonceInstruction::Nonce` transaction, which can be sent using the CLI
[`new-nonce`](#advancing-the-stored-nonce-value) command.
- Issue Tracking
This issue is being actively addressed, progress can be followed on
[Github](https://github.com/solana-labs/solana/issues/7443).
## Usage Examples
Full usage details for durable nonce CLI commands can be found in the
[CLI reference](../api-reference/cli.md).
### Nonce Authority
Authority over a nonce account can optionally be assigned to another account. In
doing so the new authority inherits full control over the nonce account from the
previous authority, including the account creator. This feature enables the
creation of more complex account ownership arrangements and derived account
addresses not associated with a keypair. The `--nonce-authority <AUTHORITY_KEYPAIR>`
argument is used to specify this account and is supported by the following
commands
* `create-nonce-account`
* `new-nonce`
* `withdraw-from-nonce-account`
* `authorize-nonce-account`
### Nonce Account Creation
The durable transaction nonce feature uses an account to store the next nonce
value. Durable nonce accounts must be [rent-exempt](../implemented-proposals/rent.md#two-tiered-rent-regime),
so need to carry the minimum balance to achieve this.
A nonce account is created by first generating a new keypair, then create the account on chain
- Command
```bash
solana-keygen new -o nonce-keypair.json
solana create-nonce-account nonce-keypair.json 1 SOL
```
- Output
```text
2SymGjGV4ksPdpbaqWFiDoBz8okvtiik4KE9cnMQgRHrRLySSdZ6jrEcpPifW4xUpp4z66XM9d9wM48sA7peG2XL
```
{% hint style="info" %}
To keep the keypair entirely offline, use the [Paper Wallet](../paper-wallet/README.md)
keypair generation [instructions](../paper-wallet/usage.md#seed-phrase-generation.md)
instead
{% endhint %}
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-create-nonce-account)
{% endhint %}
### Querying the Stored Nonce Value
Creating a durable nonce transaction requires passing the stored nonce value as
the value to the `--blockhash` argument upon signing and submission. Obtain the
presently stored nonce value with
- Command
```bash
solana get-nonce nonce-keypair.json
```
- Output
```text
8GRipryfxcsxN8mAGjy8zbFo9ezaUsh47TsPzmZbuytU
```
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-get-nonce)
{% endhint %}
### Advancing the Stored Nonce Value
While not typically needed outside a more useful transaction, the stored nonce
value can be advanced by
- Command
```bash
solana new-nonce nonce-keypair.json
```
- Output
```text
44jYe1yPKrjuYDmoFTdgPjg8LFpYyh1PFKJqm5SC1PiSyAL8iw1bhadcAX1SL7KDmREEkmHpYvreKoNv6fZgfvUK
```
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-new-nonce)
{% endhint %}
### Display Nonce Account
Inspect a nonce account in a more human friendly format with
- Command
```bash
solana show-nonce-account nonce-keypair.json
```
- Output
```text
balance: 0.5 SOL
minimum balance required: 0.00136416 SOL
nonce: DZar6t2EaCFQTbUP4DHKwZ1wT8gCPW2aRfkVWhydkBvS
```
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-show-nonce-account)
{% endhint %}
### Withdraw Funds from a Nonce Account
Withdraw funds from a nonce account with
- Command
```bash
solana withdraw-from-nonce-account nonce-keypair.json ~/.config/solana/id.json 0.5 SOL
```
- Output
```text
3foNy1SBqwXSsfSfTdmYKDuhnVheRnKXpoPySiUDBVeDEs6iMVokgqm7AqfTjbk7QBE8mqomvMUMNQhtdMvFLide
```
{% hint style="info" %}
Close a nonce account by withdrawing the full balance
{% endhint %}
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-withdraw-from-nonce-account)
{% endhint %}
### Assign a New Authority to a Nonce Account
Reassign the authority of a nonce account after creation with
- Command
```bash
solana authorize-nonce-account nonce-keypair.json nonce-authority.json
```
- Output
```text
3F9cg4zN9wHxLGx4c3cUKmqpej4oa67QbALmChsJbfxTgTffRiL3iUehVhR9wQmWgPua66jPuAYeL1K2pYYjbNoT
```
{% hint style="info" %}
[Full usage documentation](../api-reference/cli.md#solana-authorize-nonce-account)
{% endhint %}
## Other Commands Supporting Durable Nonces
To make use of durable nonces with other CLI subcommands, two arguments must be
supported.
* `--nonce`, specifies the account storing the nonce value
* `--nonce-authority`, specifies an optional [nonce authority](#nonce-authority)
The following subcommands have received this treatment so far
* [`pay`](../api-reference/cli.md#solana-pay)
* [`delegate-stake`](../api-reference/cli.md#solana-delegate-stake)
* [`deactivate-stake`](../api-reference/cli.md#solana-deactivate-stake)
### Example Pay Using Durable Nonce
Here we demonstrate Alice paying Bob 1 SOL using a durable nonce. The procedure
is the same for all subcommands supporting durable nonces
#### - Create accounts
First we need some accounts for Alice, Alice's nonce and Bob
```bash
$ solana-keygen new -o alice.json
$ solana-keygen new -o nonce.json
$ solana-keygen new -o bob.json
```
#### - Fund Alice's account
Alice will need some funds to create a nonce account and send to Bob. Airdrop
her some SOL
```bash
$ solana airdrop -k alice.json 10 SOL
10 SOL
```
#### - Create Alice's nonce account
Now Alice needs a nonce account. Create one
{% hint style="info" %}
Here, no separate [nonce authority](#nonce-authority) is employed, so `alice.json`
has full authority over the nonce account
{% endhint %}
```bash
$ solana create-nonce-account -k alice.json nonce.json 1 SOL
3KPZr96BTsL3hqera9up82KAU462Gz31xjqJ6eHUAjF935Yf8i1kmfEbo6SVbNaACKE5z6gySrNjVRvmS8DcPuwV
```
#### - A failed first attempt to pay Bob
Alice attempts to pay Bob, but takes too long to sign. The specified blockhash
expires and the transaction fails
```bash
$ solana pay -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 bob.json 1 SOL
[2020-01-02T18:48:28.462911000Z ERROR solana_cli::cli] Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
Error: Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
```
#### - Nonce to the rescue!
Alice retries the transaction, this time specifying her nonce account and the
blockhash stored there
{% hint style="info" %}
Remember, `alice.json` is the [nonce authority](#nonce-authority) in this example
{% endhint %}
```bash
$ solana show-nonce-account nonce.json
balance: 1 SOL
minimum balance required: 0.00136416 SOL
nonce: F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7
```
```bash
$ solana pay -k alice.json --blockhash F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 1 SOL
HR1368UKHVZyenmH7yVz5sBAijV6XAPeWbEiXEGVYQorRMcoijeNAbzZqEZiH8cDB8tk65ckqeegFjK8dHwNFgQ
```
#### - Success!
The transaction succeeds! Bob receives 1 SOL from Alice and Alice's stored
nonce advances to a new value
```bash
$ solana balance -k bob.json
1 SOL
```
```bash
$ solana show-nonce-account nonce.json
balance: 1 SOL
minimum balance required: 0.00136416 SOL
nonce: 6bjroqDcZgTv6Vavhqf81oBHTv3aMnX19UTB51YhAZnN
```

View File

@ -95,7 +95,7 @@ Download the binaries by navigating to [https://github.com/solana-labs/solana/re
Try running following command to join the gossip network and view all the other nodes in the cluster:
```bash
solana-gossip --entrypoint testnet.solana.com:8001 spy
solana-gossip spy --entrypoint testnet.solana.com:8001
# Press ^C to exit
```
@ -146,7 +146,7 @@ solana-archiver --entrypoint testnet.solana.com:8001 --identity-keypair archiver
From another console, confirm the IP address and **identity pubkey** of your archiver is visible in the gossip network by running:
```bash
solana-gossip --entrypoint testnet.solana.com:8001 spy
solana-gossip spy --entrypoint testnet.solana.com:8001
```
Provide the **storage account pubkey** to the `solana show-storage-account` command to view the recent mining activity from your archiver:

View File

@ -6,7 +6,7 @@ Confirm the IP address and **identity pubkey** of your validator is visible in
the gossip network by running:
```bash
solana-gossip --entrypoint testnet.solana.com:8001 spy
solana-gossip spy --entrypoint testnet.solana.com:8001
```
## Check Your Balance

View File

@ -89,7 +89,7 @@ To monitor your validator during its warmup period:
* View your stake account, the delegation preference and details of your stake:`solana show-stake-account ~/validator-stake-keypair.json`
* `solana uptime ~/validator-vote-keypair.json` will display the voting history \(aka, uptime\) of your validator over recent Epochs
* `solana show-validators` displays the current active stake of all validators, including yours
* `solana show-show-stake-history ` shows the history of stake warming up and cooling down over recent epochs
* `solana show-stake-history ` shows the history of stake warming up and cooling down over recent epochs
* Look for log messages on your validator indicating your next leader slot: `[2019-09-27T20:16:00.319721164Z INFO solana_core::replay_stage] <VALIDATOR_IDENTITY_PUBKEY> voted and reset PoH at tick height ####. My next leader slot is ####`
* Once your stake is warmed up, you will see a stake balance listed for your validator on the [Solana Network Explorer](http://explorer.solana.com/validators)

View File

@ -33,7 +33,7 @@ Try running following command to join the gossip network and view all the other
nodes in the cluster:
```bash
solana-gossip --entrypoint testnet.solana.com:8001 spy
solana-gossip spy --entrypoint testnet.solana.com:8001
# Press ^C to exit
```
@ -42,10 +42,6 @@ solana-gossip --entrypoint testnet.solana.com:8001 spy
If your machine has a GPU with CUDA installed \(Linux-only currently\), include
the `--cuda` argument to `solana-validator`.
```bash
export SOLANA_CUDA=1
```
When your validator is started look for the following log message to indicate
that CUDA is enabled: `"[<timestamp> solana::validator] CUDA is enabled"`

View File

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

View File

@ -20,7 +20,7 @@ steps:
timeout_in_minutes: 30
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
name: "stable"
timeout_in_minutes: 40
timeout_in_minutes: 60
artifact_paths: "log-*.txt"
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-move.sh"
name: "move"

View File

@ -5,7 +5,28 @@ cd "$(dirname "$0")/.."
me=$(basename "$0")
BOOK="book"
echo --- update gitbook-cage
if [[ -n $CI_BRANCH ]]; then
(
set -x
(
. ci/rust-version.sh stable
ci/docker-run.sh "$rust_stable_docker_image" make -Cbook -B svg
)
# make a local commit for the svgs
git add -A -f book/src/.gitbook/assets/.
if ! git diff-index --quiet HEAD; then
git config user.email maintainers@solana.com
git config user.name "$me"
git commit -m "gitbook-cage update $(date -Is)"
git push -f git@github.com:solana-labs/solana-gitbook-cage.git HEAD:refs/heads/"$CI_BRANCH"
# pop off the local commit
git reset --hard HEAD~
fi
)
fi
source ci/rust-version.sh stable
eval "$(ci/channel-info.sh)"
@ -31,6 +52,7 @@ EOF
exit 0
fi
repo=git@github.com:solana-labs/book.git
BOOK="book"
else
# book-edge and book-beta are published automatically on the tip of the branch
case $CHANNEL in
@ -73,27 +95,4 @@ echo "--- publish $BOOK"
fi
)
echo --- update gitbook-cage
(
if [[ -z $CI_BRANCH ]]; then
exit 0
fi
set -x
(
. ci/rust-version.sh
ci/docker-run.sh $rust_stable_docker_image make -Cbook -B svg
)
# make a local commit for the svgs
git add -A -f book/src/.gitbook/assets/.
if ! git diff-index --quiet HEAD; then
git config user.email maintainers@solana.com
git config user.name "$me"
git commit -m "gitbook-cage update $(date -Is)"
git push -f git@github.com:solana-labs/solana-gitbook-cage.git HEAD:refs/heads/"$CI_BRANCH"
# pop off the local commit
git reset --hard HEAD~
fi
)
exit 0

View File

@ -4,7 +4,12 @@ set -e
cd "$(dirname "$0")/.."
eval "$(ci/channel-info.sh)"
echo --- Creating tarball
if [[ -n "$CI_TAG" ]]; then
CHANNEL_OR_TAG=$CI_TAG
else
CHANNEL_OR_TAG=$CHANNEL
fi
(
set -x
sdk/bpf/scripts/package.sh
@ -12,7 +17,7 @@ echo --- Creating tarball
)
echo --- AWS S3 Store
if [[ -z $CHANNEL ]]; then
if [[ -z $CHANNEL_OR_TAG ]]; then
echo Skipped
else
(
@ -24,7 +29,7 @@ else
--volume "$PWD:/solana" \
eremite/aws-cli:2018.12.18 \
/usr/bin/s3cmd --acl-public put /solana/bpf-sdk.tar.bz2 \
s3://solana-sdk/"$CHANNEL"/bpf-sdk.tar.bz2
s3://solana-sdk/"$CHANNEL_OR_TAG"/bpf-sdk.tar.bz2
)
fi

View File

@ -53,7 +53,7 @@ windows)
;;
esac
echo --- Creating tarball
echo --- Creating release tarball
(
set -x
rm -rf solana-release/
@ -89,15 +89,21 @@ echo --- Creating tarball
)
# Metrics tarball is platform agnostic, only publish it from Linux
MAYBE_METRICS_TARBALL=
MAYBE_TARBALLS=
if [[ "$CI_OS_NAME" = linux ]]; then
metrics/create-metrics-tarball.sh
MAYBE_METRICS_TARBALL=solana-metrics.tar.bz2
(
set -x
sdk/bpf/scripts/package.sh
[[ -f bpf-sdk.tar.bz2 ]]
)
MAYBE_TARBALLS="bpf-sdk.tar.bz2 solana-metrics.tar.bz2"
fi
source ci/upload-ci-artifact.sh
for file in solana-release-$TARGET.tar.bz2 solana-release-$TARGET.yml solana-install-init-"$TARGET"* $MAYBE_METRICS_TARBALL; do
for file in solana-release-$TARGET.tar.bz2 solana-release-$TARGET.yml solana-install-init-"$TARGET"* $MAYBE_TARBALLS; do
upload-ci-artifact "$file"
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then

View File

@ -111,7 +111,7 @@ test-move)
;;
test-local-cluster)
_ cargo +"$rust_stable" build --release --bins ${V:+--verbose}
_ cargo +"$rust_stable" test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture
_ cargo +"$rust_stable" test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
exit 0
;;
*)

View File

@ -460,6 +460,14 @@ deploy() {
maybeGpu=(-G "${ENABLE_GPU}")
fi
if [[ -z $HASHES_PER_TICK ]]; then
maybeHashesPerTick="--hashes-per-tick auto"
elif [[ $HASHES_PER_TICK == skip ]]; then
maybeHashesPerTick=""
else
maybeHashesPerTick="--hashes-per-tick ${HASHES_PER_TICK}"
fi
if [[ -z $DISABLE_AIRDROPS ]]; then
DISABLE_AIRDROPS="true"
fi
@ -470,6 +478,22 @@ deploy() {
maybeDisableAirdrops=""
fi
if [[ -z $INTERNAL_NODES_STAKE_LAMPORTS ]]; then
maybeInternalNodesStakeLamports="--internal-nodes-stake-lamports 1000000000" # 1 SOL
elif [[ $INTERNAL_NODES_STAKE_LAMPORTS == skip ]]; then
maybeInternalNodesStakeLamports=""
else
maybeInternalNodesStakeLamports="--internal-nodes-stake-lamports ${INTERNAL_NODES_STAKE_LAMPORTS}"
fi
if [[ -z $INTERNAL_NODES_LAMPORTS ]]; then
maybeInternalNodesLamports="--internal-nodes-lamports 500000000000" # 500 SOL
elif [[ $INTERNAL_NODES_LAMPORTS == skip ]]; then
maybeInternalNodesLamports=""
else
maybeInternalNodesLamports="--internal-nodes-lamports ${INTERNAL_NODES_LAMPORTS}"
fi
EXTERNAL_ACCOUNTS_FILE=/tmp/validator.yml
if [[ -z $EXTERNAL_ACCOUNTS_FILE_URL ]]; then
EXTERNAL_ACCOUNTS_FILE_URL=https://raw.githubusercontent.com/solana-labs/tour-de-sol/master/validators/all.yml
@ -503,11 +527,14 @@ deploy() {
--idle-clients \
-P -u \
-a tds-solana-com --letsencrypt tds.solana.com \
${maybeHashesPerTick} \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
${maybeDisableAirdrops} \
${maybeInternalNodesStakeLamports} \
${maybeInternalNodesLamports} \
${maybeExternalAccountsFile} \
--target-lamports-per-signature 0 \
--slots-per-epoch 4096 \

View File

@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "0.22.0"
version = "0.22.2"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ edition = "2018"
clap = "2.33.0"
rpassword = "4.0"
semver = "0.9.0"
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
tiny-bip39 = "0.6.2"
url = "2.1.0"
chrono = "0.4"

View File

@ -33,7 +33,10 @@ where
}
}
pub fn unix_timestamp_of(matches: &ArgMatches<'_>, name: &str) -> Option<UnixTimestamp> {
pub fn unix_timestamp_from_rfc3339_datetime(
matches: &ArgMatches<'_>,
name: &str,
) -> Option<UnixTimestamp> {
matches.value_of(name).and_then(|value| {
DateTime::parse_from_rfc3339(value)
.ok()

View File

@ -1,4 +1,5 @@
use crate::keypair::ASK_KEYWORD;
use chrono::DateTime;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{read_keypair_file, Signature};
@ -129,3 +130,9 @@ pub fn is_amount(amount: String) -> Result<(), String> {
))
}
}
pub fn is_rfc3339_datetime(value: String) -> Result<(), String> {
DateTime::parse_from_rfc3339(&value)
.map(|_| ())
.map_err(|e| format!("{:?}", e))
}

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -28,24 +28,24 @@ serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-config-program = { path = "../programs/config", version = "0.22.0" }
solana-faucet = { path = "../faucet", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-storage-program = { path = "../programs/storage", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-vote-signer = { path = "../vote-signer", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-config-program = { path = "../programs/config", version = "0.22.2" }
solana-faucet = { path = "../faucet", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-storage-program = { path = "../programs/storage", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
solana-vote-signer = { path = "../vote-signer", version = "0.22.2" }
url = "2.1.0"
[dev-dependencies]
solana-core = { path = "../core", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.2" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
tempfile = "3.1.0"
[[bin]]

View File

@ -72,6 +72,21 @@ impl std::ops::Deref for KeypairEq {
}
}
#[derive(Default, Debug, PartialEq)]
pub struct PayCommand {
pub lamports: u64,
pub to: Pubkey,
pub timestamp: Option<DateTime<Utc>>,
pub timestamp_pubkey: Option<Pubkey>,
pub witnesses: Option<Vec<Pubkey>>,
pub cancelable: bool,
pub sign_only: bool,
pub signers: Option<Vec<(Pubkey, Signature)>>,
pub blockhash: Option<Hash>,
pub nonce_account: Option<Pubkey>,
pub nonce_authority: Option<KeypairEq>,
}
#[derive(Debug, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum CliCommand {
@ -117,18 +132,18 @@ pub enum CliCommand {
// Nonce commands
AuthorizeNonceAccount {
nonce_account: Pubkey,
nonce_authority: KeypairEq,
nonce_authority: Option<KeypairEq>,
new_authority: Pubkey,
},
CreateNonceAccount {
nonce_account: KeypairEq,
nonce_authority: Pubkey,
nonce_authority: Option<Pubkey>,
lamports: u64,
},
GetNonce(Pubkey),
NewNonce {
nonce_account: Pubkey,
nonce_authority: KeypairEq,
nonce_authority: Option<KeypairEq>,
},
ShowNonceAccount {
nonce_account_pubkey: Pubkey,
@ -136,7 +151,7 @@ pub enum CliCommand {
},
WithdrawFromNonceAccount {
nonce_account: Pubkey,
nonce_authority: KeypairEq,
nonce_authority: Option<KeypairEq>,
destination_account_pubkey: Pubkey,
lamports: u64,
},
@ -155,6 +170,8 @@ pub enum CliCommand {
sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
nonce_account: Option<Pubkey>,
nonce_authority: Option<KeypairEq>,
},
DelegateStake {
stake_account_pubkey: Pubkey,
@ -163,6 +180,8 @@ pub enum CliCommand {
sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
nonce_account: Option<Pubkey>,
nonce_authority: Option<KeypairEq>,
},
RedeemVoteCredits(Pubkey, Pubkey),
ShowStakeHistory {
@ -233,17 +252,7 @@ pub enum CliCommand {
},
Cancel(Pubkey),
Confirm(Signature),
Pay {
lamports: u64,
to: Pubkey,
timestamp: Option<DateTime<Utc>>,
timestamp_pubkey: Option<Pubkey>,
witnesses: Option<Vec<Pubkey>>,
cancelable: bool,
sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
},
Pay(PayCommand),
ShowAccount {
pubkey: Pubkey,
output_file: Option<String>,
@ -259,11 +268,12 @@ pub struct CliCommandInfo {
pub require_keypair: bool,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum CliError {
BadParameter(String),
CommandNotRecognized(String),
InsufficientFundsForFee,
InvalidNonce(CliNonceError),
DynamicProgramError(String),
RpcRequestError(String),
KeypairFileNotFound(String),
@ -497,9 +507,19 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
let sign_only = matches.is_present("sign_only");
let signers = pubkeys_sigs_of(&matches, "signer");
let blockhash = value_of(&matches, "blockhash");
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
let authority =
keypair_of(&matches, NONCE_AUTHORITY_ARG.name).ok_or_else(|| {
CliError::BadParameter("Invalid keypair for nonce-authority".into())
})?;
Some(authority.into())
} else {
None
};
Ok(CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports,
to,
timestamp,
@ -509,7 +529,9 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
sign_only,
signers,
blockhash,
},
nonce_account,
nonce_authority,
}),
require_keypair: true,
})
}
@ -663,7 +685,6 @@ pub fn parse_create_address_with_seed(
"STAKE" => solana_stake_program::id(),
"VOTE" => solana_vote_program::id(),
"STORAGE" => solana_storage_program::id(),
"NONCE" => solana_sdk::nonce_program::id(),
_ => pubkey_of(matches, "program_id").unwrap(),
};
@ -887,6 +908,8 @@ fn process_pay(
sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
nonce_account: Option<Pubkey>,
nonce_authority: Option<&Keypair>,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
@ -903,7 +926,20 @@ fn process_pay(
};
if timestamp == None && *witnesses == None {
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash);
let mut tx = if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
system_transaction::nonced_transfer(
&config.keypair,
to,
lamports,
nonce_account,
nonce_authority,
blockhash,
)
} else {
system_transaction::transfer(&config.keypair, to, lamports, blockhash)
};
if let Some(signers) = signers {
replace_signatures(&mut tx, &signers)?;
}
@ -911,6 +947,11 @@ fn process_pay(
if sign_only {
return_signers(&tx)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
let nonce_account = rpc_client.get_account(nonce_account)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &blockhash)?;
}
check_account_for_fee(
rpc_client,
&config.keypair.pubkey(),
@ -1148,13 +1189,13 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
// Assign authority to nonce account
CliCommand::AuthorizeNonceAccount {
nonce_account,
nonce_authority,
ref nonce_authority,
new_authority,
} => process_authorize_nonce_account(
&rpc_client,
config,
nonce_account,
nonce_authority,
nonce_authority.as_deref(),
new_authority,
),
// Create nonce account
@ -1166,7 +1207,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&rpc_client,
config,
nonce_account,
nonce_authority,
*nonce_authority,
*lamports,
),
// Get the current nonce
@ -1176,8 +1217,13 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
// Get a new nonce
CliCommand::NewNonce {
nonce_account,
nonce_authority,
} => process_new_nonce(&rpc_client, config, nonce_account, nonce_authority),
ref nonce_authority,
} => process_new_nonce(
&rpc_client,
config,
nonce_account,
nonce_authority.as_deref(),
),
// Show the contents of a nonce account
CliCommand::ShowNonceAccount {
nonce_account_pubkey,
@ -1186,14 +1232,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
// Withdraw lamports from a nonce account
CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority,
ref nonce_authority,
destination_account_pubkey,
lamports,
} => process_withdraw_from_nonce_account(
&rpc_client,
config,
&nonce_account,
nonce_authority,
nonce_authority.as_deref(),
&destination_account_pubkey,
*lamports,
),
@ -1229,6 +1275,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
sign_only,
ref signers,
blockhash,
nonce_account,
ref nonce_authority,
} => process_deactivate_stake_account(
&rpc_client,
config,
@ -1236,6 +1284,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*sign_only,
signers,
*blockhash,
*nonce_account,
nonce_authority.as_deref(),
),
CliCommand::DelegateStake {
stake_account_pubkey,
@ -1244,6 +1294,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
sign_only,
ref signers,
blockhash,
nonce_account,
ref nonce_authority,
} => process_delegate_stake(
&rpc_client,
config,
@ -1253,6 +1305,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*sign_only,
signers,
*blockhash,
*nonce_account,
nonce_authority.as_deref(),
),
CliCommand::RedeemVoteCredits(stake_account_pubkey, vote_account_pubkey) => {
process_redeem_vote_credits(
@ -1438,7 +1492,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
// Confirm the last client transaction by signature
CliCommand::Confirm(signature) => process_confirm(&rpc_client, signature),
// If client has positive balance, pay lamports to another address
CliCommand::Pay {
CliCommand::Pay(PayCommand {
lamports,
to,
timestamp,
@ -1448,7 +1502,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
sign_only,
ref signers,
blockhash,
} => process_pay(
nonce_account,
ref nonce_authority,
}) => process_pay(
&rpc_client,
config,
*lamports,
@ -1460,6 +1516,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*sign_only,
signers,
*blockhash,
*nonce_account,
nonce_authority.as_deref(),
),
CliCommand::ShowAccount {
pubkey,
@ -1710,7 +1768,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.required(true)
.help(
"The program_id that the address will ultimately be used for, \n\
or one of STAKE, VOTE, NONCE, and STORAGE keywords",
or one of STAKE, VOTE, and STORAGE keywords",
),
)
.arg(
@ -1801,6 +1859,23 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(
Arg::with_name(NONCE_ARG.name)
.long(NONCE_ARG.long)
.takes_value(true)
.value_name("PUBKEY")
.requires("blockhash")
.validator(is_pubkey_or_keypair)
.help(NONCE_ARG.help),
)
.arg(
Arg::with_name(NONCE_AUTHORITY_ARG.name)
.long(NONCE_AUTHORITY_ARG.long)
.takes_value(true)
.requires(NONCE_ARG.name)
.validator(is_keypair_or_ask_keyword)
.help(NONCE_AUTHORITY_ARG.help),
)
.arg(
Arg::with_name("signer")
.long("signer")
@ -1903,12 +1978,18 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
mod tests {
use super::*;
use serde_json::Value;
use solana_client::mock_rpc_client_request::SIGNATURE;
use solana_client::{
mock_rpc_client_request::SIGNATURE,
rpc_request::{self, RpcRequest, RpcResponseContext},
};
use solana_sdk::{
account::Account,
nonce_state::{Meta as NonceMeta, NonceState},
signature::{read_keypair_file, write_keypair_file},
system_program,
transaction::TransactionError,
};
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};
fn make_tmp_path(name: &str) -> String {
let out_dir = std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
@ -2041,7 +2122,6 @@ mod tests {
for (name, program_id) in &[
("STAKE", solana_stake_program::id()),
("VOTE", solana_vote_program::id()),
("NONCE", solana_sdk::nonce_program::id()),
("STORAGE", solana_storage_program::id()),
] {
let test_create_address_with_seed = test_commands.clone().get_matches_from(vec![
@ -2106,17 +2186,11 @@ mod tests {
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2136,17 +2210,12 @@ mod tests {
assert_eq!(
parse_command(&test_pay_multiple_witnesses).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![witness0, witness1]),
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2162,17 +2231,12 @@ mod tests {
assert_eq!(
parse_command(&test_pay_single_witness).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![witness0]),
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2192,17 +2256,13 @@ mod tests {
assert_eq!(
parse_command(&test_pay_timestamp).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(witness0),
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2219,17 +2279,12 @@ mod tests {
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: true,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true,
}
);
@ -2250,17 +2305,12 @@ mod tests {
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: Some(vec![(key1, sig1)]),
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2283,17 +2333,12 @@ mod tests {
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: Some(vec![(key1, sig1), (key2, sig2)]),
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2313,17 +2358,72 @@ mod tests {
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: Some(blockhash),
},
..PayCommand::default()
}),
require_keypair: true
}
);
// Test Pay Subcommand w/ Nonce
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let test_pay = test_commands.clone().get_matches_from(vec![
"test",
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
&pubkey_string,
]);
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
blockhash: Some(blockhash),
nonce_account: Some(pubkey),
..PayCommand::default()
}),
require_keypair: true
}
);
// Test Pay Subcommand w/ Nonce and Nonce Authority
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let keypair = read_keypair_file(&keypair_file).unwrap();
let test_pay = test_commands.clone().get_matches_from(vec![
"test",
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
&pubkey_string,
"--nonce-authority",
&keypair_file,
]);
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
blockhash: Some(blockhash),
nonce_account: Some(pubkey),
nonce_authority: Some(keypair.into()),
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2360,17 +2460,14 @@ mod tests {
assert_eq!(
parse_command(&test_pay_multiple_witnesses).unwrap(),
CliCommandInfo {
command: CliCommand::Pay {
command: CliCommand::Pay(PayCommand {
lamports: 50,
to: pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(witness0),
witnesses: Some(vec![witness0, witness1]),
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
},
..PayCommand::default()
}),
require_keypair: true
}
);
@ -2494,6 +2591,8 @@ mod tests {
sign_only: false,
signers: None,
blockhash: None,
nonce_account: None,
nonce_authority: None,
};
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
@ -2508,33 +2607,23 @@ mod tests {
};
assert_eq!(process_command(&config).unwrap(), "1234");
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
let date_string = "\"2018-09-19T17:30:59Z\"";
let dt: DateTime<Utc> = serde_json::from_str(&date_string).unwrap();
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(config.keypair.pubkey()),
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let result = process_command(&config);
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
assert_eq!(
@ -2548,17 +2637,13 @@ mod tests {
);
let witness = Pubkey::new_rand();
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![witness]),
cancelable: true,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let result = process_command(&config);
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
assert_eq!(
@ -2571,6 +2656,57 @@ mod tests {
SIGNATURE.to_string()
);
// Nonced pay
let blockhash = Hash::default();
let nonce_response = json!(rpc_request::Response {
context: RpcResponseContext { slot: 1 },
value: json!(Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&config.keypair.pubkey()), blockhash),
&system_program::ID,
)
.unwrap()),
});
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, nonce_response);
config.rpc_client = Some(RpcClient::new_mock_with_mocks("".to_string(), mocks));
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
nonce_account: Some(bob_pubkey),
blockhash: Some(blockhash),
..PayCommand::default()
});
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
// Nonced pay w/ non-payer authority
let bob_keypair = Keypair::new();
let bob_pubkey = bob_keypair.pubkey();
let blockhash = Hash::default();
let nonce_authority_response = json!(rpc_request::Response {
context: RpcResponseContext { slot: 1 },
value: json!(Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&bob_pubkey), blockhash),
&system_program::ID,
)
.unwrap()),
});
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, nonce_authority_response);
config.rpc_client = Some(RpcClient::new_mock_with_mocks("".to_string(), mocks));
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
blockhash: Some(blockhash),
nonce_account: Some(bob_pubkey),
nonce_authority: Some(bob_keypair.into()),
..PayCommand::default()
});
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
let process_id = Pubkey::new_rand();
config.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
let signature = process_command(&config);
@ -2669,43 +2805,29 @@ mod tests {
};
assert!(process_command(&config).is_err());
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
assert!(process_command(&config).is_err());
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(config.keypair.pubkey()),
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
assert!(process_command(&config).is_err());
config.command = CliCommand::Pay {
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![witness]),
cancelable: true,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
assert!(process_command(&config).is_err());
config.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);

View File

@ -446,7 +446,7 @@ pub fn process_show_block_production(
first_slot_in_epoch
};
let start_slot_index = (start_slot - first_slot_in_epoch) as usize;
let end_slot_index = (end_slot - start_slot) as usize;
let end_slot_index = (end_slot - first_slot_in_epoch) as usize;
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message(&format!(
@ -458,9 +458,9 @@ pub fn process_show_block_production(
let total_slots = end_slot_index - start_slot_index + 1;
let total_blocks = confirmed_blocks.len();
assert!(total_blocks <= total_slots);
let total_slots_missed = total_slots - total_blocks;
let total_slots_skipped = total_slots - total_blocks;
let mut leader_slot_count = HashMap::new();
let mut leader_missed_slots = HashMap::new();
let mut leader_skipped_slots = HashMap::new();
progress_bar.set_message(&format!("Fetching leader schedule for epoch {}...", epoch));
let leader_schedule = rpc_client
@ -482,7 +482,7 @@ pub fn process_show_block_production(
progress_bar.set_message(&format!(
"Processing {} slots containing {} blocks and {} empty slots...",
total_slots, total_blocks, total_slots_missed
total_slots, total_blocks, total_slots_skipped
));
let mut confirmed_blocks_index = 0;
@ -491,7 +491,7 @@ pub fn process_show_block_production(
let slot = start_slot + slot_index as u64;
let slot_count = leader_slot_count.entry(leader).or_insert(0);
*slot_count += 1;
let missed_slots = leader_missed_slots.entry(leader).or_insert(0);
let skipped_slots = leader_skipped_slots.entry(leader).or_insert(0);
loop {
if !confirmed_blocks.is_empty() {
@ -506,9 +506,9 @@ pub fn process_show_block_production(
break;
}
}
*missed_slots += 1;
*skipped_slots += 1;
individual_slot_status.push(
style(format!(" {:<15} {:<44} MISSED", slot, leader))
style(format!(" {:<15} {:<44} SKIPPED", slot, leader))
.red()
.to_string(),
);
@ -524,23 +524,23 @@ pub fn process_show_block_production(
"Identity Pubkey",
"Leader Slots",
"Blocks Produced",
"Missed Slots",
"Missed Block Percentage",
"Skipped Slots",
"Skipped Slot Percentage",
))
.bold()
);
let mut table = vec![];
for (leader, leader_slots) in leader_slot_count.iter() {
let missed_slots = leader_missed_slots.get(leader).unwrap();
let blocks_produced = leader_slots - missed_slots;
let skipped_slots = leader_skipped_slots.get(leader).unwrap();
let blocks_produced = leader_slots - skipped_slots;
table.push(format!(
" {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
leader,
leader_slots,
blocks_produced,
missed_slots,
*missed_slots as f64 / *leader_slots as f64 * 100.
skipped_slots,
*skipped_slots as f64 / *leader_slots as f64 * 100.
));
}
table.sort();
@ -551,8 +551,8 @@ pub fn process_show_block_production(
format!("Epoch {} total:", epoch),
total_slots,
total_blocks,
total_slots_missed,
total_slots_missed as f64 / total_slots as f64 * 100.
total_slots_skipped,
total_slots_skipped as f64 / total_slots as f64 * 100.
);
println!(
" (using data from {} slots: {} to {})",

View File

@ -4,20 +4,47 @@ use crate::cli::{
CliError, ProcessResult,
};
use clap::{App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*};
use solana_clap_utils::{input_parsers::*, input_validators::*, ArgConstant};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
account::Account,
account_utils::State,
hash::Hash,
nonce_instruction::{authorize, create_nonce_account, nonce, withdraw, NonceError},
nonce_program,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
system_instruction::SystemError,
system_instruction::{
create_nonce_account, nonce_advance, nonce_authorize, nonce_withdraw, NonceError,
SystemError,
},
system_program,
transaction::Transaction,
};
#[derive(Debug, Clone, PartialEq)]
pub enum CliNonceError {
InvalidAccountOwner,
InvalidAccountData,
InvalidHash,
InvalidAuthority,
InvalidState,
}
pub const NONCE_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce",
long: "nonce",
help: "Provide the nonce account to use when creating a nonced \n\
transaction. Nonced transactions are useful when a transaction \n\
requires a lengthy signing process. Learn more about nonced \n\
transactions at https://docs.solana.com/offline-signing/durable-nonce",
};
pub const NONCE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce_authority",
long: "nonce-authority",
help: "Provide the nonce authority keypair to use when signing a nonced transaction",
};
pub trait NonceSubCommands {
fn nonce_subcommands(self) -> Self;
}
@ -183,20 +210,15 @@ impl NonceSubCommands for App<'_, '_> {
}
}
fn resolve_nonce_authority(matches: &ArgMatches<'_>) -> Keypair {
keypair_of(matches, "nonce_authority")
.unwrap_or_else(|| keypair_of(matches, "nonce_account_keypair").unwrap())
}
pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let new_authority = pubkey_of(matches, "new_authority").unwrap();
let nonce_authority = resolve_nonce_authority(matches);
let nonce_authority = keypair_of(matches, "nonce_authority").map(|kp| kp.into());
Ok(CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount {
nonce_account,
nonce_authority: nonce_authority.into(),
nonce_authority,
new_authority,
},
require_keypair: true,
@ -206,8 +228,7 @@ pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliComm
pub fn parse_nonce_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = keypair_of(matches, "nonce_account_keypair").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?;
let nonce_authority =
pubkey_of(matches, "nonce_authority").unwrap_or_else(|| nonce_account.pubkey());
let nonce_authority = pubkey_of(matches, "nonce_authority");
Ok(CliCommandInfo {
command: CliCommand::CreateNonceAccount {
@ -230,12 +251,12 @@ pub fn parse_get_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliEr
pub fn parse_new_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let nonce_authority = resolve_nonce_authority(matches);
let nonce_authority = keypair_of(matches, "nonce_authority").map(|kp| kp.into());
Ok(CliCommandInfo {
command: CliCommand::NewNonce {
nonce_account,
nonce_authority: nonce_authority.into(),
nonce_authority,
},
require_keypair: true,
})
@ -260,12 +281,12 @@ pub fn parse_withdraw_from_nonce_account(
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?;
let nonce_authority = resolve_nonce_authority(matches);
let nonce_authority = keypair_of(matches, "nonce_authority").map(|kp| kp.into());
Ok(CliCommandInfo {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: nonce_authority.into(),
nonce_authority,
destination_account_pubkey,
lamports,
},
@ -273,16 +294,45 @@ pub fn parse_withdraw_from_nonce_account(
})
}
/// Check if a nonce account is initialized with the given authority and hash
pub fn check_nonce_account(
nonce_account: &Account,
nonce_authority: &Pubkey,
nonce_hash: &Hash,
) -> Result<(), Box<CliError>> {
if nonce_account.owner != system_program::ID {
return Err(CliError::InvalidNonce(CliNonceError::InvalidAccountOwner).into());
}
let nonce_state: NonceState = nonce_account
.state()
.map_err(|_| Box::new(CliError::InvalidNonce(CliNonceError::InvalidAccountData)))?;
match nonce_state {
NonceState::Initialized(meta, hash) => {
if &hash != nonce_hash {
Err(CliError::InvalidNonce(CliNonceError::InvalidHash).into())
} else if nonce_authority != &meta.nonce_authority {
Err(CliError::InvalidNonce(CliNonceError::InvalidAuthority).into())
} else {
Ok(())
}
}
NonceState::Uninitialized => {
Err(CliError::InvalidNonce(CliNonceError::InvalidState).into())
}
}
}
pub fn process_authorize_nonce_account(
rpc_client: &RpcClient,
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: &Keypair,
nonce_authority: Option<&Keypair>,
new_authority: &Pubkey,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ix = authorize(nonce_account, &nonce_authority.pubkey(), new_authority);
let nonce_authority = nonce_authority.unwrap_or(&config.keypair);
let ix = nonce_authorize(nonce_account, &nonce_authority.pubkey(), new_authority);
let mut tx = Transaction::new_signed_with_payer(
vec![ix],
Some(&config.keypair.pubkey()),
@ -304,7 +354,7 @@ pub fn process_create_nonce_account(
rpc_client: &RpcClient,
config: &CliConfig,
nonce_account: &Keypair,
nonce_authority: &Pubkey,
nonce_authority: Option<Pubkey>,
lamports: u64,
) -> ProcessResult {
let nonce_account_pubkey = nonce_account.pubkey();
@ -330,10 +380,11 @@ pub fn process_create_nonce_account(
.into());
}
let nonce_authority = nonce_authority.unwrap_or_else(|| config.keypair.pubkey());
let ixs = create_nonce_account(
&config.keypair.pubkey(),
&nonce_account_pubkey,
nonce_authority,
&nonce_authority,
lamports,
);
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
@ -356,7 +407,7 @@ pub fn process_create_nonce_account(
pub fn process_get_nonce(rpc_client: &RpcClient, nonce_account_pubkey: &Pubkey) -> ProcessResult {
let nonce_account = rpc_client.get_account(nonce_account_pubkey)?;
if nonce_account.owner != nonce_program::id() {
if nonce_account.owner != system_program::id() {
return Err(CliError::RpcRequestError(format!(
"{:?} is not a nonce account",
nonce_account_pubkey
@ -378,7 +429,7 @@ pub fn process_new_nonce(
rpc_client: &RpcClient,
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: &Keypair,
nonce_authority: Option<&Keypair>,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
@ -392,7 +443,8 @@ pub fn process_new_nonce(
.into());
}
let ix = nonce(&nonce_account, &nonce_authority.pubkey());
let nonce_authority = nonce_authority.unwrap_or(&config.keypair);
let ix = nonce_advance(&nonce_account, &nonce_authority.pubkey());
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let mut tx = Transaction::new_signed_with_payer(
vec![ix],
@ -417,7 +469,7 @@ pub fn process_show_nonce_account(
use_lamports_unit: bool,
) -> ProcessResult {
let nonce_account = rpc_client.get_account(nonce_account_pubkey)?;
if nonce_account.owner != nonce_program::id() {
if nonce_account.owner != system_program::id() {
return Err(CliError::RpcRequestError(format!(
"{:?} is not a nonce account",
nonce_account_pubkey
@ -458,13 +510,14 @@ pub fn process_withdraw_from_nonce_account(
rpc_client: &RpcClient,
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: &Keypair,
nonce_authority: Option<&Keypair>,
destination_account_pubkey: &Pubkey,
lamports: u64,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ix = withdraw(
let nonce_authority = nonce_authority.unwrap_or(&config.keypair);
let ix = nonce_withdraw(
nonce_account,
&nonce_authority.pubkey(),
destination_account_pubkey,
@ -491,7 +544,13 @@ pub fn process_withdraw_from_nonce_account(
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use solana_sdk::signature::{read_keypair_file, write_keypair};
use solana_sdk::{
account::Account,
hash::hash,
nonce_state::{Meta as NonceMeta, NonceState},
signature::{read_keypair_file, write_keypair},
system_program,
};
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
@ -524,7 +583,7 @@ mod tests {
CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: nonce_account_pubkey,
nonce_authority: read_keypair_file(&keypair_file).unwrap().into(),
nonce_authority: None,
new_authority: Pubkey::default(),
},
require_keypair: true,
@ -545,7 +604,9 @@ mod tests {
CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: Some(
read_keypair_file(&authority_keypair_file).unwrap().into()
),
new_authority: Pubkey::default(),
},
require_keypair: true,
@ -565,7 +626,7 @@ mod tests {
CliCommandInfo {
command: CliCommand::CreateNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().into(),
nonce_authority: nonce_account_pubkey,
nonce_authority: None,
lamports: 50,
},
require_keypair: true
@ -587,7 +648,9 @@ mod tests {
CliCommandInfo {
command: CliCommand::CreateNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().into(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().pubkey(),
nonce_authority: Some(
read_keypair_file(&authority_keypair_file).unwrap().pubkey()
),
lamports: 50,
},
require_keypair: true
@ -619,7 +682,7 @@ mod tests {
CliCommandInfo {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
nonce_authority: nonce_account.into(),
nonce_authority: None,
},
require_keypair: true
}
@ -639,7 +702,9 @@ mod tests {
CliCommandInfo {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: Some(
read_keypair_file(&authority_keypair_file).unwrap().into()
),
},
require_keypair: true
}
@ -676,7 +741,7 @@ mod tests {
CliCommandInfo {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&keypair_file).unwrap().into(),
nonce_authority: None,
destination_account_pubkey: nonce_account_pubkey,
lamports: 42
},
@ -697,7 +762,7 @@ mod tests {
CliCommandInfo {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&keypair_file).unwrap().into(),
nonce_authority: None,
destination_account_pubkey: nonce_account_pubkey,
lamports: 42000000000
},
@ -721,7 +786,9 @@ mod tests {
CliCommandInfo {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: Some(
read_keypair_file(&authority_keypair_file).unwrap().into()
),
destination_account_pubkey: nonce_account_pubkey,
lamports: 42
},
@ -729,4 +796,66 @@ mod tests {
}
);
}
#[test]
fn test_check_nonce_account() {
let blockhash = Hash::default();
let nonce_pubkey = Pubkey::new_rand();
let valid = Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&nonce_pubkey), blockhash),
&system_program::ID,
);
assert!(check_nonce_account(&valid.unwrap(), &nonce_pubkey, &blockhash).is_ok());
let invalid_owner = Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&nonce_pubkey), blockhash),
&Pubkey::new(&[1u8; 32]),
);
assert_eq!(
check_nonce_account(&invalid_owner.unwrap(), &nonce_pubkey, &blockhash),
Err(Box::new(CliError::InvalidNonce(
CliNonceError::InvalidAccountOwner
))),
);
let invalid_data = Account::new_data(1, &"invalid", &system_program::ID);
assert_eq!(
check_nonce_account(&invalid_data.unwrap(), &nonce_pubkey, &blockhash),
Err(Box::new(CliError::InvalidNonce(
CliNonceError::InvalidAccountData
))),
);
let invalid_hash = Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&nonce_pubkey), hash(b"invalid")),
&system_program::ID,
);
assert_eq!(
check_nonce_account(&invalid_hash.unwrap(), &nonce_pubkey, &blockhash),
Err(Box::new(CliError::InvalidNonce(CliNonceError::InvalidHash))),
);
let invalid_authority = Account::new_data(
1,
&NonceState::Initialized(NonceMeta::new(&Pubkey::new_rand()), blockhash),
&system_program::ID,
);
assert_eq!(
check_nonce_account(&invalid_authority.unwrap(), &nonce_pubkey, &blockhash),
Err(Box::new(CliError::InvalidNonce(
CliNonceError::InvalidAuthority
))),
);
let invalid_state = Account::new_data(1, &NonceState::Uninitialized, &system_program::ID);
assert_eq!(
check_nonce_account(&invalid_state.unwrap(), &nonce_pubkey, &blockhash),
Err(Box::new(CliError::InvalidNonce(
CliNonceError::InvalidState
))),
);
}
}

View File

@ -1,8 +1,11 @@
use crate::cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
get_blockhash_fee_calculator, log_instruction_custom_error, replace_signatures,
required_lamports_from, return_signers, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
use crate::{
cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
get_blockhash_fee_calculator, log_instruction_custom_error, replace_signatures,
required_lamports_from, return_signers, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
nonce::{check_nonce_account, NONCE_ARG, NONCE_AUTHORITY_ARG},
};
use clap::{App, Arg, ArgMatches, SubCommand};
use console::style;
@ -83,6 +86,7 @@ impl StakeSubCommands for App<'_, '_> {
Arg::with_name("lockup_date")
.long("lockup-date")
.value_name("RFC3339 DATE TIME")
.validator(is_rfc3339_datetime)
.takes_value(true)
.help("The date and time at which this account will be available for withdrawal")
)
@ -153,6 +157,23 @@ impl StakeSubCommands for App<'_, '_> {
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(
Arg::with_name(NONCE_ARG.name)
.long(NONCE_ARG.long)
.takes_value(true)
.value_name("PUBKEY")
.requires("blockhash")
.validator(is_pubkey)
.help(NONCE_ARG.help)
)
.arg(
Arg::with_name(NONCE_AUTHORITY_ARG.name)
.long(NONCE_AUTHORITY_ARG.long)
.takes_value(true)
.requires(NONCE_ARG.name)
.validator(is_keypair_or_ask_keyword)
.help(NONCE_AUTHORITY_ARG.help)
),
)
.subcommand(
@ -232,6 +253,23 @@ impl StakeSubCommands for App<'_, '_> {
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(
Arg::with_name(NONCE_ARG.name)
.long(NONCE_ARG.long)
.takes_value(true)
.value_name("PUBKEY")
.requires("blockhash")
.validator(is_pubkey)
.help(NONCE_ARG.help)
)
.arg(
Arg::with_name(NONCE_AUTHORITY_ARG.name)
.long(NONCE_AUTHORITY_ARG.long)
.takes_value(true)
.requires(NONCE_ARG.name)
.validator(is_keypair_or_ask_keyword)
.help(NONCE_AUTHORITY_ARG.help)
),
)
.subcommand(
@ -330,7 +368,7 @@ impl StakeSubCommands for App<'_, '_> {
pub fn parse_stake_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let stake_account = keypair_of(matches, "stake_account").unwrap();
let epoch = value_of(&matches, "lockup_epoch").unwrap_or(0);
let unix_timestamp = unix_timestamp_of(&matches, "lockup_date").unwrap_or(0);
let unix_timestamp = unix_timestamp_from_rfc3339_datetime(&matches, "lockup_date").unwrap_or(0);
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
let staker = pubkey_of(matches, "authorized_staker");
let withdrawer = pubkey_of(matches, "authorized_withdrawer");
@ -360,6 +398,14 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
let signers = pubkeys_sigs_of(&matches, "signer");
let blockhash = value_of(matches, "blockhash");
let require_keypair = signers.is_none();
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
let authority = keypair_of(&matches, NONCE_AUTHORITY_ARG.name)
.ok_or_else(|| CliError::BadParameter("Invalid keypair for nonce-authority".into()))?;
Some(authority.into())
} else {
None
};
Ok(CliCommandInfo {
command: CliCommand::DelegateStake {
@ -369,6 +415,8 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
sign_only,
signers,
blockhash,
nonce_account,
nonce_authority,
},
require_keypair,
})
@ -407,6 +455,14 @@ pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliComma
let signers = pubkeys_sigs_of(&matches, "signer");
let blockhash = value_of(matches, "blockhash");
let require_keypair = signers.is_none();
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
let authority = keypair_of(&matches, NONCE_AUTHORITY_ARG.name)
.ok_or_else(|| CliError::BadParameter("Invalid keypair for nonce-authority".into()))?;
Some(authority.into())
} else {
None
};
Ok(CliCommandInfo {
command: CliCommand::DeactivateStake {
@ -414,6 +470,8 @@ pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliComma
sign_only,
signers,
blockhash,
nonce_account,
nonce_authority,
},
require_keypair,
})
@ -492,7 +550,6 @@ pub fn process_create_stake_account(
staker: staker.unwrap_or(config.keypair.pubkey()),
withdrawer: withdrawer.unwrap_or(config.keypair.pubkey()),
};
println!("{:?}", authorized);
let ixs = stake_instruction::create_account(
&config.keypair.pubkey(),
@ -561,6 +618,8 @@ pub fn process_deactivate_stake_account(
sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
nonce_account: Option<Pubkey>,
nonce_authority: Option<&Keypair>,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) =
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
@ -568,18 +627,35 @@ pub fn process_deactivate_stake_account(
stake_account_pubkey,
&config.keypair.pubkey(),
)];
let mut tx = Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair],
recent_blockhash,
);
let mut tx = if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
Transaction::new_signed_with_nonce(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair, nonce_authority],
nonce_account,
&nonce_authority.pubkey(),
recent_blockhash,
)
} else {
Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair],
recent_blockhash,
)
};
if let Some(signers) = signers {
replace_signatures(&mut tx, &signers)?;
}
if sign_only {
return_signers(&tx)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
let nonce_account = rpc_client.get_account(nonce_account)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee(
rpc_client,
&tx.message.account_keys[0],
@ -760,6 +836,7 @@ pub fn process_show_stake_history(
Ok("".to_string())
}
#[allow(clippy::too_many_arguments)]
pub fn process_delegate_stake(
rpc_client: &RpcClient,
config: &CliConfig,
@ -769,6 +846,8 @@ pub fn process_delegate_stake(
sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>,
nonce_account: Option<Pubkey>,
nonce_authority: Option<&Keypair>,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
@ -823,19 +902,35 @@ pub fn process_delegate_stake(
&config.keypair.pubkey(),
vote_account_pubkey,
)];
let mut tx = Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair],
recent_blockhash,
);
let mut tx = if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
Transaction::new_signed_with_nonce(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair, nonce_authority],
nonce_account,
&nonce_authority.pubkey(),
recent_blockhash,
)
} else {
Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair],
recent_blockhash,
)
};
if let Some(signers) = signers {
replace_signatures(&mut tx, &signers)?;
}
if sign_only {
return_signers(&tx)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_authority: &Keypair = nonce_authority.unwrap_or(&config.keypair);
let nonce_account = rpc_client.get_account(nonce_account)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee(
rpc_client,
&tx.message.account_keys[0],
@ -987,7 +1082,9 @@ mod tests {
force: false,
sign_only: false,
signers: None,
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1009,7 +1106,9 @@ mod tests {
force: true,
sign_only: false,
signers: None,
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1035,7 +1134,9 @@ mod tests {
force: false,
sign_only: false,
signers: None,
blockhash: Some(blockhash)
blockhash: Some(blockhash),
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1057,7 +1158,9 @@ mod tests {
force: false,
sign_only: true,
signers: None,
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1084,7 +1187,9 @@ mod tests {
force: false,
sign_only: false,
signers: Some(vec![(key1, sig1)]),
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: false
}
@ -1113,7 +1218,9 @@ mod tests {
force: false,
sign_only: false,
signers: Some(vec![(key1, sig1), (key2, sig2)]),
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: false
}
@ -1150,7 +1257,9 @@ mod tests {
stake_account_pubkey,
sign_only: false,
signers: None,
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1173,7 +1282,9 @@ mod tests {
stake_account_pubkey,
sign_only: false,
signers: None,
blockhash: Some(blockhash)
blockhash: Some(blockhash),
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1192,7 +1303,9 @@ mod tests {
stake_account_pubkey,
sign_only: true,
signers: None,
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: true
}
@ -1216,7 +1329,9 @@ mod tests {
stake_account_pubkey,
sign_only: false,
signers: Some(vec![(key1, sig1)]),
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: false
}
@ -1242,7 +1357,9 @@ mod tests {
stake_account_pubkey,
sign_only: false,
signers: Some(vec![(key1, sig1), (key2, sig2)]),
blockhash: None
blockhash: None,
nonce_account: None,
nonce_authority: None,
},
require_keypair: false
}

View File

@ -312,10 +312,12 @@ pub fn process_set_validator_info(
"Publishing info for Validator {:?}",
config.keypair.pubkey()
);
let lamports = rpc_client
.get_minimum_balance_for_rent_exemption(ValidatorInfo::max_space() as usize)?;
let mut instructions = config_instruction::create_account::<ValidatorInfo>(
&config.keypair.pubkey(),
&info_keypair.pubkey(),
1,
lamports,
keys.clone(),
);
instructions.extend_from_slice(&[config_instruction::store(

View File

@ -51,7 +51,8 @@ impl VoteSubCommands for App<'_, '_> {
.long("commission")
.value_name("NUM")
.takes_value(true)
.help("The commission taken on reward redemption (0-100), default: 0"),
.default_value("100")
.help("The commission taken on reward redemption (0-100)"),
)
.arg(
Arg::with_name("authorized_voter")
@ -195,7 +196,7 @@ impl VoteSubCommands for App<'_, '_> {
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let vote_account = keypair_of(matches, "vote_account").unwrap();
let identity_pubkey = pubkey_of(matches, "identity_pubkey").unwrap();
let commission = value_of(&matches, "commission").unwrap_or(0);
let commission = value_t_or_exit!(matches, "commission", u8);
let authorized_voter = pubkey_of(matches, "authorized_voter");
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer");
@ -609,7 +610,7 @@ mod tests {
node_pubkey,
authorized_voter: None,
authorized_withdrawer: None,
commission: 0,
commission: 100,
},
require_keypair: true
}
@ -637,7 +638,7 @@ mod tests {
node_pubkey,
authorized_voter: Some(authed),
authorized_withdrawer: None,
commission: 0
commission: 100
},
require_keypair: true
}
@ -663,7 +664,7 @@ mod tests {
node_pubkey,
authorized_voter: None,
authorized_withdrawer: Some(authed),
commission: 0
commission: 100
},
require_keypair: true
}

View File

@ -1,4 +1,6 @@
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig};
use solana_cli::cli::{
process_command, request_and_confirm_airdrop, CliCommand, CliConfig, KeypairEq,
};
use solana_client::rpc_client::RpcClient;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
@ -59,7 +61,7 @@ fn test_nonce() {
&mut config_payer,
&mut config_nonce,
&keypair_file,
&keypair_file,
None,
);
server.close().unwrap();
@ -95,20 +97,24 @@ fn test_nonce_with_authority() {
&mut config_payer,
&mut config_nonce,
&nonce_keypair_file,
&authority_keypair_file,
Some(&authority_keypair_file),
);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
fn read_keypair_from_option(keypair_file: &Option<&str>) -> Option<KeypairEq> {
keypair_file.map(|akf| read_keypair_file(&akf).unwrap().into())
}
fn full_battery_tests(
rpc_client: &RpcClient,
faucet_addr: &std::net::SocketAddr,
config_payer: &mut CliConfig,
config_nonce: &mut CliConfig,
nonce_keypair_file: &str,
authority_keypair_file: &str,
authority_keypair_file: Option<&str>,
) {
request_and_confirm_airdrop(
&rpc_client,
@ -122,7 +128,8 @@ fn full_battery_tests(
// Create nonce account
config_payer.command = CliCommand::CreateNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().into(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_from_option(&authority_keypair_file)
.map(|na: KeypairEq| na.pubkey()),
lamports: 1000,
};
process_command(&config_payer).unwrap();
@ -144,7 +151,7 @@ fn full_battery_tests(
// New nonce
config_payer.command = CliCommand::NewNonce {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: read_keypair_from_option(&authority_keypair_file),
};
process_command(&config_payer).unwrap();
@ -159,7 +166,7 @@ fn full_battery_tests(
let payee_pubkey = Pubkey::new_rand();
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: read_keypair_from_option(&authority_keypair_file),
destination_account_pubkey: payee_pubkey,
lamports: 100,
};
@ -181,7 +188,7 @@ fn full_battery_tests(
write_keypair(&new_authority, tmp_file.as_file_mut()).unwrap();
config_payer.command = CliCommand::AuthorizeNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: read_keypair_from_option(&authority_keypair_file),
new_authority: read_keypair_file(&new_authority_keypair_file)
.unwrap()
.pubkey(),
@ -191,25 +198,29 @@ fn full_battery_tests(
// Old authority fails now
config_payer.command = CliCommand::NewNonce {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&authority_keypair_file).unwrap().into(),
nonce_authority: read_keypair_from_option(&authority_keypair_file),
};
process_command(&config_payer).unwrap_err();
// New authority can advance nonce
config_payer.command = CliCommand::NewNonce {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
nonce_authority: Some(
read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
),
};
process_command(&config_payer).unwrap();
// New authority can withdraw from nonce account
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().pubkey(),
nonce_authority: read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
nonce_authority: Some(
read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
),
destination_account_pubkey: payee_pubkey,
lamports: 100,
};

View File

@ -1,9 +1,17 @@
use chrono::prelude::*;
use serde_json::Value;
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig};
use solana_cli::cli::{
process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand,
};
use solana_client::rpc_client::RpcClient;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{hash::Hash, pubkey::Pubkey, signature::KeypairUtil, signature::Signature};
use solana_sdk::{
account_utils::State,
hash::Hash,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature},
};
use std::fs::remove_dir_all;
use std::str::FromStr;
use std::sync::mpsc::channel;
@ -12,6 +20,12 @@ use std::sync::mpsc::channel;
use solana_core::validator::new_validator_for_tests;
use std::thread::sleep;
use std::time::Duration;
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
let tmp_file = NamedTempFile::new().unwrap();
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
}
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
(0..5).for_each(|tries| {
@ -69,17 +83,13 @@ fn test_cli_timestamp_tx() {
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
let date_string = "\"2018-09-19T17:30:59Z\"";
let dt: DateTime<Utc> = serde_json::from_str(&date_string).unwrap();
config_payer.command = CliCommand::Pay {
config_payer.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
witnesses: None,
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
@ -144,17 +154,12 @@ fn test_cli_witness_tx() {
.unwrap();
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
config_payer.command = CliCommand::Pay {
config_payer.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![config_witness.keypair.pubkey()]),
cancelable: false,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
@ -212,17 +217,13 @@ fn test_cli_cancel_tx() {
.unwrap();
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
config_payer.command = CliCommand::Pay {
config_payer.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: Some(vec![config_witness.keypair.pubkey()]),
cancelable: true,
sign_only: false,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let sig_response = process_command(&config_payer).unwrap();
let object: Value = serde_json::from_str(&sig_response).unwrap();
@ -288,17 +289,12 @@ fn test_offline_pay_tx() {
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
config_offline.command = CliCommand::Pay {
config_offline.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: true,
signers: None,
blockhash: None,
};
..PayCommand::default()
});
let sig_response = process_command(&config_offline).unwrap();
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
@ -318,17 +314,13 @@ fn test_offline_pay_tx() {
})
.collect();
config_online.command = CliCommand::Pay {
config_online.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
timestamp: None,
timestamp_pubkey: None,
witnesses: None,
cancelable: false,
sign_only: false,
signers: Some(signers),
blockhash: Some(blockhash_str.parse::<Hash>().unwrap()),
};
..PayCommand::default()
});
process_command(&config_online).unwrap();
check_balance(40, &rpc_client, &config_offline.keypair.pubkey());
@ -338,3 +330,81 @@ fn test_offline_pay_tx() {
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonced_pay_tx() {
solana_logger::setup();
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config.keypair.pubkey(),
50 + minimum_nonce_balance,
)
.unwrap();
check_balance(
50 + minimum_nonce_balance,
&rpc_client,
&config.keypair.pubkey(),
);
// Create nonce account
let nonce_account = Keypair::new();
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
config.command = CliCommand::CreateNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().into(),
nonce_authority: Some(config.keypair.pubkey()),
lamports: minimum_nonce_balance,
};
process_command(&config).unwrap();
check_balance(50, &rpc_client, &config.keypair.pubkey());
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
let bob_pubkey = Pubkey::new_rand();
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
blockhash: Some(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
..PayCommand::default()
});
process_command(&config).expect("failed to process pay command");
check_balance(40, &rpc_client, &config.keypair.pubkey());
check_balance(10, &rpc_client, &bob_pubkey);
// Verify that nonce has been used
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
match nonce_state {
NonceState::Initialized(_meta, hash) => assert_ne!(hash, nonce_hash),
_ => assert!(false, "Nonce is not initialized"),
}
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@ -3,9 +3,11 @@ use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand,
use solana_client::rpc_client::RpcClient;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::State,
hash::Hash,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, KeypairUtil, Signature},
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature},
};
use solana_stake_program::stake_state::Lockup;
use std::fs::remove_dir_all;
@ -101,6 +103,8 @@ fn test_stake_delegation_and_deactivation() {
sign_only: false,
signers: None,
blockhash: None,
nonce_account: None,
nonce_authority: None,
};
process_command(&config_validator).unwrap();
@ -110,6 +114,8 @@ fn test_stake_delegation_and_deactivation() {
sign_only: false,
signers: None,
blockhash: None,
nonce_account: None,
nonce_authority: None,
};
process_command(&config_validator).unwrap();
@ -185,6 +191,8 @@ fn test_stake_delegation_and_deactivation_offline() {
sign_only: true,
signers: None,
blockhash: None,
nonce_account: None,
nonce_authority: None,
};
let sig_response = process_command(&config_validator).unwrap();
let object: Value = serde_json::from_str(&sig_response).unwrap();
@ -208,6 +216,8 @@ fn test_stake_delegation_and_deactivation_offline() {
sign_only: false,
signers: Some(signers),
blockhash: Some(blockhash_str.parse::<Hash>().unwrap()),
nonce_account: None,
nonce_authority: None,
};
process_command(&config_payer).unwrap();
@ -217,6 +227,8 @@ fn test_stake_delegation_and_deactivation_offline() {
sign_only: true,
signers: None,
blockhash: None,
nonce_account: None,
nonce_authority: None,
};
let sig_response = process_command(&config_validator).unwrap();
let object: Value = serde_json::from_str(&sig_response).unwrap();
@ -238,9 +250,114 @@ fn test_stake_delegation_and_deactivation_offline() {
sign_only: false,
signers: Some(signers),
blockhash: Some(blockhash_str.parse::<Hash>().unwrap()),
nonce_account: None,
nonce_authority: None,
};
process_command(&config_payer).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonced_stake_delegation_and_deactivation() {
solana_logger::setup();
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
.unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &config.keypair.pubkey(), 100_000)
.unwrap();
// Create vote account
let vote_keypair = Keypair::new();
let (vote_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&vote_keypair, tmp_file.as_file_mut()).unwrap();
config.command = CliCommand::CreateVoteAccount {
vote_account: read_keypair_file(&vote_keypair_file).unwrap().into(),
node_pubkey: config.keypair.pubkey(),
authorized_voter: None,
authorized_withdrawer: None,
commission: 0,
};
process_command(&config).unwrap();
// Create stake account
let stake_keypair = Keypair::new();
let (stake_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&stake_keypair, tmp_file.as_file_mut()).unwrap();
config.command = CliCommand::CreateStakeAccount {
stake_account: read_keypair_file(&stake_keypair_file).unwrap().into(),
staker: None,
withdrawer: None,
lockup: Lockup::default(),
lamports: 50_000,
};
process_command(&config).unwrap();
// Create nonce account
let nonce_account = Keypair::new();
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
config.command = CliCommand::CreateNonceAccount {
nonce_account: read_keypair_file(&nonce_keypair_file).unwrap().into(),
nonce_authority: Some(config.keypair.pubkey()),
lamports: minimum_nonce_balance,
};
process_command(&config).unwrap();
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
// Delegate stake
config.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_keypair.pubkey(),
vote_account_pubkey: vote_keypair.pubkey(),
force: true,
sign_only: false,
signers: None,
blockhash: Some(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None,
};
process_command(&config).unwrap();
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
// Deactivate stake
let config_keypair = Keypair::from_bytes(&config.keypair.to_bytes()).unwrap();
config.command = CliCommand::DeactivateStake {
stake_account_pubkey: stake_keypair.pubkey(),
sign_only: false,
signers: None,
blockhash: Some(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: Some(config_keypair.into()),
};
process_command(&config).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "0.22.0"
version = "0.22.2"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -19,11 +19,11 @@ reqwest = { version = "0.9.24", default-features = false, features = ["rustls-tl
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
[dev-dependencies]
assert_matches = "1.3.0"
jsonrpc-core = "14.0.5"
jsonrpc-http-server = "14.0.5"
solana-logger = { path = "../logger", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.2" }

View File

@ -9,18 +9,28 @@ use solana_sdk::{
instruction::InstructionError,
transaction::{self, TransactionError},
};
use std::{collections::HashMap, sync::RwLock};
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
pub const SIGNATURE: &str =
"43yNSFC6fYTuPgTNFFhF4axw7AfWxB2BPdurme8yrsWEYwm8299xh8n6TAHjGymiSub1XtyxTNyd9GBfY2hxoBw8";
pub type Mocks = HashMap<RpcRequest, Value>;
pub struct MockRpcClientRequest {
mocks: RwLock<Mocks>,
url: String,
}
impl MockRpcClientRequest {
pub fn new(url: String) -> Self {
Self { url }
Self::new_with_mocks(url, Mocks::default())
}
pub fn new_with_mocks(url: String, mocks: Mocks) -> Self {
Self {
url,
mocks: RwLock::new(mocks),
}
}
}
@ -31,6 +41,9 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
params: serde_json::Value,
_retries: usize,
) -> Result<serde_json::Value, ClientError> {
if let Some(value) = self.mocks.write().unwrap().remove(request) {
return Ok(value);
}
if self.url == "fails" {
return Ok(Value::Null);
}

View File

@ -2,7 +2,7 @@ use crate::rpc_request::{Response, RpcResponse};
use crate::{
client_error::ClientError,
generic_rpc_client_request::GenericRpcClientRequest,
mock_rpc_client_request::MockRpcClientRequest,
mock_rpc_client_request::{MockRpcClientRequest, Mocks},
rpc_client_request::RpcClientRequest,
rpc_request::{
RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest,
@ -48,6 +48,12 @@ impl RpcClient {
}
}
pub fn new_mock_with_mocks(url: String, mocks: Mocks) -> Self {
Self {
client: Box::new(MockRpcClientRequest::new_with_mocks(url, mocks)),
}
}
pub fn new_socket(addr: SocketAddr) -> Self {
Self::new(get_rpc_request_str(addr, false))
}

View File

@ -113,7 +113,7 @@ pub struct RpcVoteAccountInfo {
pub root_slot: Slot,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum RpcRequest {
ConfirmTransaction,
DeregisterNode,

View File

@ -1,7 +1,7 @@
[package]
name = "solana-core"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -41,26 +41,26 @@ rayon = "1.2.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-faucet = { path = "../faucet", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-faucet = { path = "../faucet", version = "0.22.2" }
ed25519-dalek = "=1.0.0-pre.1"
solana-ledger = { path = "../ledger", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-measure = { path = "../measure", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-perf = { path = "../perf", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-storage-program = { path = "../programs/storage", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-vote-signer = { path = "../vote-signer", version = "0.22.0" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.22.0" }
solana-ledger = { path = "../ledger", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-measure = { path = "../measure", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-perf = { path = "../perf", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-storage-program = { path = "../programs/storage", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
solana-vote-signer = { path = "../vote-signer", version = "0.22.2" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.22.2" }
symlink = "0.1.0"
sys-info = "0.5.8"
tempfile = "3.1.0"
@ -69,13 +69,9 @@ tokio-codec = "0.1"
tokio-fs = "0.1"
tokio-io = "0.1"
untrusted = "0.7.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.0" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.2" }
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
[target."cfg(unix)".dependencies]
jemallocator = "0.3.2"
jemalloc-ctl = "0.3.2"
[dev-dependencies]
hex-literal = "0.2.1"
matches = "0.1.6"

View File

@ -7,7 +7,6 @@ use crate::{
poh_recorder::{PohRecorder, PohRecorderError, WorkingBankEntry},
poh_service::PohService,
result::{Error, Result},
thread_mem_usage,
};
use crossbeam_channel::{Receiver as CrossbeamReceiver, RecvTimeoutError};
use itertools::Itertools;
@ -17,7 +16,7 @@ use solana_ledger::{
entry::hash_transactions,
leader_schedule_cache::LeaderScheduleCache,
};
use solana_measure::measure::Measure;
use solana_measure::{measure::Measure, thread_mem_usage};
use solana_metrics::{inc_new_counter_debug, inc_new_counter_info, inc_new_counter_warn};
use solana_perf::{cuda_runtime::PinnedVec, perf_libs};
use solana_runtime::{

View File

@ -24,7 +24,6 @@ use crate::{
repair_service::RepairType,
result::{Error, Result},
sendmmsg::{multicast, send_mmsg},
thread_mem_usage,
weighted_shuffle::{weighted_best, weighted_shuffle},
};
use bincode::{serialize, serialized_size};
@ -32,6 +31,7 @@ use core::cmp;
use itertools::Itertools;
use rand::{thread_rng, Rng};
use solana_ledger::{bank_forks::BankForks, blocktree::Blocktree, staking_utils};
use solana_measure::thread_mem_usage;
use solana_metrics::{datapoint_debug, inc_new_counter_debug, inc_new_counter_error};
use solana_net_utils::{
bind_common, bind_common_in_range, bind_in_range, find_available_port_in_range,

View File

@ -432,7 +432,7 @@ impl Tower {
fn maybe_timestamp(&mut self, current_slot: Slot) -> Option<UnixTimestamp> {
if self.last_timestamp.slot == 0
|| self.last_timestamp.slot + TIMESTAMP_SLOT_INTERVAL <= current_slot
|| self.last_timestamp.slot < (current_slot - (current_slot % TIMESTAMP_SLOT_INTERVAL))
{
let timestamp = Utc::now().timestamp();
self.last_timestamp = BlockTimestamp {

View File

@ -5,7 +5,7 @@ use crate::packet::PacketsRecycler;
use crate::poh_recorder::PohRecorder;
use crate::result::{Error, Result};
use crate::streamer::{self, PacketReceiver, PacketSender};
use crate::thread_mem_usage;
use solana_measure::thread_mem_usage;
use solana_metrics::{inc_new_counter_debug, inc_new_counter_info};
use solana_perf::recycler::Recycler;
use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;

View File

@ -12,7 +12,6 @@ pub mod chacha_cuda;
pub mod cluster_info_vote_listener;
pub mod commitment;
pub mod shred_fetch_stage;
pub mod thread_mem_usage;
#[macro_use]
pub mod contact_info;
pub mod archiver;
@ -84,10 +83,3 @@ extern crate solana_metrics;
#[cfg(test)]
#[macro_use]
extern crate matches;
#[cfg(unix)]
extern crate jemallocator;
#[cfg(unix)]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

View File

@ -7,7 +7,6 @@ use crate::{
poh_recorder::PohRecorder,
result::{Error, Result},
rpc_subscriptions::RpcSubscriptions,
thread_mem_usage,
};
use solana_ledger::{
bank_forks::BankForks,
@ -18,7 +17,7 @@ use solana_ledger::{
leader_schedule_cache::LeaderScheduleCache,
snapshot_package::SnapshotPackageSender,
};
use solana_measure::measure::Measure;
use solana_measure::{measure::Measure, thread_mem_usage};
use solana_metrics::inc_new_counter_info;
use solana_runtime::bank::Bank;
use solana_sdk::{

View File

@ -4,7 +4,7 @@
use crate::packet::{self, send_to, Packets, PacketsRecycler, PACKETS_PER_BATCH};
use crate::recvmmsg::NUM_RCVMMSGS;
use crate::result::{Error, Result};
use crate::thread_mem_usage;
use solana_measure::thread_mem_usage;
use solana_sdk::timing::duration_as_ms;
use std::net::UdpSocket;
use std::sync::atomic::{AtomicBool, Ordering};

View File

@ -1,6 +1,6 @@
[package]
name = "solana-crate-features"
version = "0.22.0"
version = "0.22.2"
description = "Solana Crate Features"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-faucet"
version = "0.22.0"
version = "0.22.2"
description = "Solana Faucet"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -19,10 +19,10 @@ clap = "2.33"
log = "0.4.8"
serde = "1.0.104"
serde_derive = "1.0.103"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-fixed-buf"
version = "0.22.0"
version = "0.22.2"
description = "A fixed-size byte array that supports bincode serde"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-genesis-programs"
version = "0.22.0"
version = "0.22.2"
description = "Solana genesis programs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,16 +10,16 @@ edition = "2018"
[dependencies]
log = { version = "0.4.8" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-config-program = { path = "../programs/config", version = "0.22.0" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-storage-program = { path = "../programs/storage", version = "0.22.0" }
solana-vest-program = { path = "../programs/vest", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.22.2" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
solana-config-program = { path = "../programs/config", version = "0.22.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-storage-program = { path = "../programs/storage", version = "0.22.2" }
solana-vest-program = { path = "../programs/vest", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
[lib]
crate-type = ["lib"]

View File

@ -1,7 +1,6 @@
use solana_sdk::{
clock::Epoch, genesis_config::OperatingMode, inflation::Inflation,
move_loader::solana_move_loader_program, nonce_program::solana_nonce_program, pubkey::Pubkey,
system_program::solana_system_program,
move_loader::solana_move_loader_program, pubkey::Pubkey, system_program::solana_system_program,
};
#[macro_use]
@ -59,7 +58,6 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
solana_system_program(),
solana_bpf_loader_program!(),
solana_config_program!(),
solana_nonce_program(),
solana_stake_program!(),
solana_storage_program!(),
solana_vest_program!(),
@ -77,7 +75,6 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
if epoch == 0 {
// Nonce, Voting, Staking and System Program only at epoch 0
Some(vec![
solana_nonce_program(),
solana_stake_program!(),
solana_system_program(),
solana_vote_program!(),
@ -127,7 +124,6 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::nonce_program::solana_nonce_program;
use std::collections::HashSet;
#[test]
@ -150,7 +146,7 @@ mod tests {
fn test_development_programs() {
assert_eq!(
get_programs(OperatingMode::Development, 0).unwrap().len(),
11
10
);
assert_eq!(get_programs(OperatingMode::Development, 1), None);
}
@ -173,7 +169,6 @@ mod tests {
assert_eq!(
get_programs(OperatingMode::SoftLaunch, 0),
Some(vec![
solana_nonce_program(),
solana_stake_program!(),
solana_system_program(),
solana_vote_program!(),

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-genesis"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,18 +11,19 @@ homepage = "https://solana.com/"
[dependencies]
base64 = "0.11.0"
clap = "2.33.0"
chrono = "0.4"
hex = "0.4.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.0" }
solana-ledger = { path = "../ledger", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-storage-program = { path = "../programs/storage", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.2" }
solana-ledger = { path = "../ledger", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-storage-program = { path = "../programs/storage", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
tempfile = "3.1.0"
[[bin]]

View File

@ -3,10 +3,7 @@ use crate::{
unlocks::UnlockInfo,
validators::{create_and_add_validator, ValidatorInfo},
};
use solana_sdk::{
genesis_config::GenesisConfig,
native_token::{lamports_to_sol, sol_to_lamports},
};
use solana_sdk::{genesis_config::GenesisConfig, native_token::SOL_LAMPORTS};
// 30 month schedule is 1/5th every 6 months for 30 months
const UNLOCKS_BY_FIFTHS_FOR_30_MONTHS: UnlockInfo = UnlockInfo {
@ -39,108 +36,107 @@ pub const BATCH_FOUR_STAKER_INFOS: &[StakerInfo] = &[
StakerInfo {
name: "impossible pizza",
staker: "CDtJpwRSiPRDGeKrvymWQKM7JY9M3hU7iimEKBDxZyoP",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "wretched texture",
staker: "HbENu65qjWLEB5TrMouSSWLq9mbtGx2bvfhPjk2FpYek",
sol: 225_000.0,
lamports: 225_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "nutritious examination",
staker: "C9CfFpmLDsQsz6wt7MrrZquNB5oS4QkpJkmDAiboVEZZ",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "tidy impression",
staker: "6ne6Rbag4FAnop1KNgVdM1SEHnJEysHSWyqvRpFrzaig",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "unbecoming silver",
// TODO: staker: "42yapY7Vrs5jqht9TCKsPoyb4vDFYcPfRkqAP85NSAQ", WrongSize
staker: "GS7RFm4nrxzYGcPTmu1otzHzZbURWDKuxo2L4AQDvTg2",
sol: 28_800.0,
staker: "42yapY7Vrs5jqht9TCKZsPoyb4vDFYcPfRkqAP85NSAQ",
lamports: 28_800 * SOL_LAMPORTS,
},
StakerInfo {
name: "dramatic treatment",
staker: "GTyawCMwt3kMb51AgDtfdp97mDot7jNwc8ifuS9qqANg",
sol: 1_205_602.0,
lamports: 1_205_602 * SOL_LAMPORTS,
},
StakerInfo {
name: "angry noise",
staker: "Fqxs9MhqjKuMq6YwjBG4ktEapuZQ3kj19mpuHLZKtkg9",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "hard cousin",
staker: "9MYDzj7QuAX9QAK7da1GhzPB4gA3qbPNWsW3MMSZobru",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "inexpensive uncle",
staker: "E4DLNkmdL34ejA48ApfPDoFVuD9XWAFqi8bXzBGRhKst",
sol: 300_000.0,
lamports: 300_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "lopsided skill",
staker: "8cV7zCTF5UMrZakZXiL2Jw5uY3ms2Wz4twzFXEY9Kge2",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "red snake",
staker: "JBGnGdLyo7V2z9hz51mnnbyDp9sBACtw5WYH9YRG8n7e",
sol: 3_655_292.0,
lamports: 3_655_292 * SOL_LAMPORTS,
},
StakerInfo {
name: "hellish money",
staker: "CqKdQ57mBj2mKcAbpjWc28Ls7yXzBXboxSTCRWocmUVj",
sol: 200_000.0,
lamports: 200_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "full grape",
staker: "2SCJKvh7wWo32PtfUZdVZQ84WnMWoUpF4WTm6ZxcCJ15",
sol: 450_000.0,
lamports: 450_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "nice ghost",
staker: "FeumxB3gfzrVQzABBiha8AacKPY3Rf4BTFSh2aZWHqR8",
sol: 650_000.0,
lamports: 650_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "jolly year",
staker: "HBwFWNGPVZgkf3yqUKxuAds5aANGWX62LzUFvZVCWLdJ",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "typical initiative",
staker: "3JMz3kaDUZEVK2JVjRqwERGMp7LbWbgUjAFBb42qxoHb",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "deserted window",
staker: "XTeBBZextvHkoRqDF8yb4hihjcraKQDwTEXhzjd8fip",
sol: 3_655_292.0,
lamports: 3_655_292 * SOL_LAMPORTS,
},
StakerInfo {
name: "eight nation",
staker: "E5bSU5ywqPiz3ije89ef5gaEC7jy81BAc72Zeb9MqeHY",
sol: 103_519.0,
lamports: 103_519 * SOL_LAMPORTS,
},
StakerInfo {
name: "earsplitting meaning",
staker: "4ZemkSoE75RFE1SVLnnmHcaNWT4qN8KFrKP2wAYfv8CB",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "alike cheese",
staker: "72BGEwYee5txFonmpEarTEKCZVN2UxcSUgdphdhcx3V",
sol: 3_880_295.0,
lamports: 3_880_295 * SOL_LAMPORTS,
},
StakerInfo {
name: "noisy honey",
staker: "DRp1Scyn4yJZQfMAdQew2x8RtvRmsNELN37JTK5Xvzgn",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
];
@ -148,12 +144,12 @@ pub const FOUNDATION_STAKER_INFOS: &[StakerInfo] = &[
StakerInfo {
name: "lyrical supermarket",
staker: "GRZwoJGisLTszcxtWpeREJ98EGg8pZewhbtcrikoU7b3",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "frequent description",
staker: "J51tinoLdmEdUR27LUVymrb2LB3xQo1aSHSgmbSGdj58",
sol: 57_500_000.0,
lamports: 57_500_000 * SOL_LAMPORTS,
},
];
@ -161,12 +157,12 @@ pub const GRANTS_STAKER_INFOS: &[StakerInfo] = &[
StakerInfo {
name: "rightful agreement",
staker: "DNaKiBwwbbqk1wVoC5AQxWQbuDhvaDVbAtXzsVos9mrc",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "tasty location",
staker: "HvXQPXAijjG1vnQs6HXVtUUtFVzi5HNgXV9LGnHvYF85",
sol: 15_000_000.0,
lamports: 15_000_000 * SOL_LAMPORTS,
},
];
@ -174,17 +170,17 @@ pub const COMMUNITY_STAKER_INFOS: &[StakerInfo] = &[
StakerInfo {
name: "shrill charity",
staker: "BzuqQFnu7oNUeok9ZoJezpqu2vZJU7XR1PxVLkk6wwUD",
sol: 5_000_000.0,
lamports: 5_000_000 * SOL_LAMPORTS,
},
StakerInfo {
name: "legal gate",
staker: "FwMbkDZUb78aiMWhZY4BEroAcqmnrXZV77nwrg71C57d",
sol: 16_086_641.0,
lamports: 16_086_641 * SOL_LAMPORTS,
},
StakerInfo {
name: "cluttered complaint",
staker: "4h1rt2ic4AXwG7p3Qqhw57EMDD4c3tLYb5J3QstGA2p5",
sol: 153_333_633.41,
lamports: 153_333_633 * SOL_LAMPORTS + 41 * SOL_LAMPORTS / 100,
},
];
@ -207,70 +203,70 @@ pub const VALIDATOR_INFOS: &[ValidatorInfo] = &[
name: "01Node",
node: "5n8KCdzqtvTnhkvCrFR7errH6ZUp11kL97r2awXkfzFe",
vote: "4uYMbY5Ae5ZSRNxQ3RWVyXS9rzW7E3AMZYHuUEotxu6K",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "Bison Trails",
node: "7suRNpX7bJsXphHJtBv4ZsLjJZ1dTGeX256pLqJZdEAm",
vote: "DfirEZ9Up1xbE7sQji9UwtcRGe5uCcRqQtnaGpha5KNY",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "ChainFlow",
node: "2te46rxywMdCNdkvjumiBBPQoVczJFxhxEaxFavQNqe3",
vote: "8bRCnytB7bySmqxodNGbZuUAtncKkB8T733DD1Dm9WMb",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "ChorusOne",
node: "ChorusXqjLC2NbiStKR6k9WoD7wu6TVTtFG8qCL5XBVa",
vote: "ChorusvBuPwukqgDvYfWtEg8j4T1NcMgSTQ4b1UbAwgQ",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "Dokia Capital",
node: "GeZ5PrJi9muVCJiJAaFBNGoCEdxGEqTp7L2BmT2WTTy1",
vote: "7ZdRx2EBYoRuPfyeoNbuHodMUXcAQRcC37MUw3kP6akn",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "Forbole",
node: "Fe5sLQAAT7RBT8mcH1AAGCbExJQcYxcwXvp1GjrGbvxs",
vote: "Dr8MkZZuvZVQJFKtjShZYEfg6n93sc1GxevqLnGss7FW",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "P2P.ORG - Secure Non-custodial Staking",
node: "44e8VyWoyZSE2oYHxMHMedAiHkGJqJgPd3tdt6iKoAFL",
vote: "BwwpzEpo1wzgV9N1987ntgNG6jLt3C9532C68pswT7Gp",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "RockX",
node: "Ez4iUU87ViJLCnmSy1t1Ti3DLoysFXiBseNfnRfoehyY",
vote: "GUdGALCHQBeqkNc2ZAht3tBXab1N5u9qJC3PAzpL54r7",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "Stake Capital",
node: "HavuVVDXXsJqMzPwQ4KcF5kFm2xqjbChhyi1bgGeCQif",
vote: "HswPkKj1xoLLmpM8t1vy5Pbi8zYYUs9ZawswvofKsFo1",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
ValidatorInfo {
name: "Staking Facilities",
node: "pbAxyqHHPMwgEjv8kmjGxysk9rhNtN7q22eAjReq6Hj",
vote: "4VZ3pJX19PpuGjoSB1qeN9sVQfrqgLVNg16is37adiFp",
node_sol: 500.0,
node_lamports: 500 * SOL_LAMPORTS,
commission: 0,
},
];
@ -290,22 +286,22 @@ pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig, mut issued_lampo
genesis_config,
&BATCH_FOUR_STAKER_INFOS,
&UNLOCKS_BY_FIFTHS_FOR_30_MONTHS,
sol_to_lamports(1_000_000.0),
1_000_000 * SOL_LAMPORTS,
) + add_stakes(
genesis_config,
&FOUNDATION_STAKER_INFOS,
&UNLOCKS_BY_TENTHS_FOR_60_MONTHS,
sol_to_lamports(1_000_000.0),
1_000_000 * SOL_LAMPORTS,
) + add_stakes(
genesis_config,
&GRANTS_STAKER_INFOS,
&UNLOCKS_BY_TENTHS_FOR_60_MONTHS,
sol_to_lamports(1_000_000.0),
1_000_000 * SOL_LAMPORTS,
) + add_stakes(
genesis_config,
&COMMUNITY_STAKER_INFOS,
&UNLOCKS_ALL_DAY_ZERO,
sol_to_lamports(1_000_000.0),
1_000_000 * SOL_LAMPORTS,
) + add_validators(genesis_config, &VALIDATOR_INFOS);
// "one thanks" (community pool) gets 500_000_000SOL (total) - above distributions
@ -314,10 +310,10 @@ pub fn add_genesis_accounts(genesis_config: &mut GenesisConfig, mut issued_lampo
&StakerInfo {
name: "one thanks",
staker: "3b7akieYUyCgz3Cwt5sTSErMWjg8NEygD6mbGjhGkduB",
sol: 500_000_000.0 - lamports_to_sol(issued_lamports),
lamports: 500_000_000 * SOL_LAMPORTS - issued_lamports,
},
&UNLOCKS_ALL_DAY_ZERO,
sol_to_lamports(1_000_000.0),
1_000_000 * SOL_LAMPORTS,
);
}
@ -337,6 +333,6 @@ mod tests {
.map(|(_, account)| account.lamports)
.sum::<u64>();
assert_eq!(500_000_000.0, lamports_to_sol(lamports));
assert_eq!(500_000_000 * SOL_LAMPORTS, lamports);
}
}

View File

@ -1,9 +1,10 @@
//! A command-line executable for generating the chain's genesis config.
use chrono::{TimeZone, Utc};
use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches};
use solana_clap_utils::{
input_parsers::{pubkey_of, unix_timestamp_of},
input_validators::is_valid_percentage,
input_parsers::{pubkey_of, unix_timestamp_from_rfc3339_datetime},
input_validators::{is_rfc3339_datetime, is_valid_percentage},
};
use solana_genesis::{genesis_accounts::add_genesis_accounts, Base64Account};
use solana_ledger::{blocktree::create_new_ledger, poh::compute_hashes_per_tick};
@ -140,8 +141,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
Arg::with_name("creation_time")
.long("creation-time")
.value_name("RFC3339 DATE TIME")
.validator(is_rfc3339_datetime)
.takes_value(true)
.help("Time when the bootrap leader will start, defaults to current system time"),
.help("Time when the bootstrap leader will start the cluster [default: current system time]"),
)
.arg(
Arg::with_name("bootstrap_leader_pubkey_file")
@ -246,7 +248,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.default_value(default_lamports_per_byte_year)
.help(
"The cost in lamports that the cluster will charge per byte per year \
for accounts with data.",
for accounts with data",
),
)
.arg(
@ -257,7 +259,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.default_value(default_rent_exemption_threshold)
.help(
"amount of time (in years) the balance has to include rent for \
to qualify as rent exempted account.",
to qualify as rent exempted account",
),
)
.arg(
@ -486,7 +488,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
..GenesisConfig::default()
};
if let Some(creation_time) = unix_timestamp_of(&matches, "creation_time") {
if let Some(creation_time) = unix_timestamp_from_rfc3339_datetime(&matches, "creation_time") {
genesis_config.creation_time = creation_time;
}
@ -518,8 +520,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
create_new_ledger(&ledger_path, &genesis_config)?;
println!(
"Genesis hash: {}\nOperating mode: {:?}\nHashes per tick: {:?}\nSlots per epoch: {}\nCapitalization: {} SOL in {} accounts",
"Genesis hash: {}\nCreation time: {}\nOperating mode: {:?}\nHashes per tick: {:?}\nSlots per epoch: {}\nCapitalization: {} SOL in {} accounts",
genesis_config.hash(),
Utc.timestamp(genesis_config.creation_time, 0).to_rfc3339(),
operating_mode,
genesis_config.poh_config.hashes_per_tick,
slots_per_epoch,

View File

@ -4,8 +4,8 @@ use crate::{
unlocks::{UnlockInfo, Unlocks},
};
use solana_sdk::{
account::Account, clock::Slot, genesis_config::GenesisConfig, native_token::sol_to_lamports,
pubkey::Pubkey, system_program, timing::years_as_slots,
account::Account, clock::Slot, genesis_config::GenesisConfig, pubkey::Pubkey, system_program,
timing::years_as_slots,
};
use solana_stake_program::{
self,
@ -16,7 +16,7 @@ use solana_stake_program::{
pub struct StakerInfo {
pub name: &'static str,
pub staker: &'static str,
pub sol: f64,
pub lamports: u64,
}
// lamports required to run staking operations for one year
@ -54,7 +54,7 @@ pub fn create_and_add_stakes(
.parse::<Pubkey>()
.expect("invalid custodian");
let total_lamports = sol_to_lamports(staker_info.sol);
let total_lamports = staker_info.lamports;
// staker is a system account
let staker_rent_reserve = genesis_config.rent.minimum_balance(0).max(1);
@ -154,7 +154,7 @@ pub fn create_and_add_stakes(
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::{native_token::lamports_to_sol, rent::Rent};
use solana_sdk::rent::Rent;
fn create_and_check_stakes(
genesis_config: &mut GenesisConfig,
@ -241,7 +241,7 @@ mod tests {
&StakerInfo {
name: "fun",
staker: "P1aceHo1derPubkey11111111111111111111111111",
sol: lamports_to_sol(total_lamports),
lamports: total_lamports,
},
&UnlockInfo {
cliff_fraction: 0.5,
@ -266,7 +266,7 @@ mod tests {
&StakerInfo {
name: "fun",
staker: "P1aceHo1derPubkey11111111111111111111111111",
sol: lamports_to_sol(total_lamports),
lamports: total_lamports,
},
&UnlockInfo {
cliff_fraction: 0.5,
@ -291,7 +291,7 @@ mod tests {
&StakerInfo {
name: "fun",
staker: "P1aceHo1derPubkey11111111111111111111111111",
sol: lamports_to_sol(total_lamports),
lamports: total_lamports,
},
&UnlockInfo {
cliff_fraction: 0.5,
@ -315,7 +315,7 @@ mod tests {
&StakerInfo {
name: "fun",
staker: "P1aceHo1derPubkey11111111111111111111111111",
sol: lamports_to_sol(total_lamports),
lamports: total_lamports,
},
&UnlockInfo {
cliff_fraction: 0.5,

View File

@ -1,7 +1,7 @@
//! validators generator
use solana_sdk::{
account::Account, genesis_config::GenesisConfig, native_token::sol_to_lamports, pubkey::Pubkey,
system_program, timing::years_as_slots,
account::Account, genesis_config::GenesisConfig, pubkey::Pubkey, system_program,
timing::years_as_slots,
};
use solana_vote_program::vote_state::{self, VoteState};
@ -9,7 +9,7 @@ use solana_vote_program::vote_state::{self, VoteState};
pub struct ValidatorInfo {
pub name: &'static str,
pub node: &'static str,
pub node_sol: f64,
pub node_lamports: u64,
pub vote: &'static str,
pub commission: u8,
}
@ -34,7 +34,6 @@ pub fn create_and_add_validator(
) -> u64 {
let node: Pubkey = validator_info.node.parse().expect("invalid node");
let vote: Pubkey = validator_info.vote.parse().expect("invalid vote");
let node_lamports = sol_to_lamports(validator_info.node_sol);
// node is the system account from which votes will be issued
let node_rent_reserve = genesis_config.rent.minimum_balance(0).max(1);
@ -42,7 +41,7 @@ pub fn create_and_add_validator(
let vote_rent_reserve = VoteState::get_rent_exempt_reserve(&genesis_config.rent).max(1);
let mut total_lamports = node_voting_fees + vote_rent_reserve + node_lamports;
let mut total_lamports = node_voting_fees + vote_rent_reserve + validator_info.node_lamports;
genesis_config
.accounts
@ -51,7 +50,7 @@ pub fn create_and_add_validator(
total_lamports += node_rent_reserve;
Account::new(node_rent_reserve, 0, &system_program::id())
})
.lamports += node_voting_fees + node_lamports;
.lamports += node_voting_fees + validator_info.node_lamports;
assert!(
genesis_config.accounts.get(&vote).is_none(),
@ -70,7 +69,7 @@ pub fn create_and_add_validator(
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::rent::Rent;
use solana_sdk::{native_token::SOL_LAMPORTS, rent::Rent};
fn create_and_check_validators(
genesis_config: &mut GenesisConfig,
@ -122,7 +121,7 @@ mod tests {
&[ValidatorInfo {
name: "fun",
node: "AiTDdNHW2vNtHt7PqWMHx3B8cMPRDNgc7kMiLPJM25QC", // random pubkeys
node_sol: 0.0,
node_lamports: 0,
vote: "77TQYZTHodhnxJcSuVjUvx8GYRCkykPyHtmFTFLjj1Rc",
commission: 50,
}],
@ -145,7 +144,7 @@ mod tests {
let total_lamports = VoteState::get_rent_exempt_reserve(&rent) * 2
+ calculate_voting_fees(&genesis_config, 1.0) * 2 // two vote accounts
+ rent.minimum_balance(0) // one node account
+ sol_to_lamports(1.0); // 2nd vote account ask has SOL
+ 1 * SOL_LAMPORTS; // 2nd vote account ask has SOL
// weird case, just wanted to verify that the duplicated node account gets double fees
create_and_check_validators(
@ -154,14 +153,14 @@ mod tests {
ValidatorInfo {
name: "fun",
node: "3VTm54dw8w6jTTsPH4BfoV5vo6mF985JAMtNDRYcaGFc", // random pubkeys
node_sol: 0.0,
node_lamports: 0,
vote: "GTKWbUoLw3Bv7Ld92crhyXcEk9zUu3VEKfzeuWJZdnfW",
commission: 50,
},
ValidatorInfo {
name: "unfun",
node: "3VTm54dw8w6jTTsPH4BfoV5vo6mF985JAMtNDRYcaGFc", // random pubkeys, same node
node_sol: 1.0,
node_lamports: 1 * SOL_LAMPORTS,
vote: "8XrFPRULg98kSm535kFaLV4GMnK5JQSuAymyrCHXsUcy",
commission: 50,
},
@ -190,14 +189,14 @@ mod tests {
ValidatorInfo {
name: "fun",
node: "3VTm54dw8w6jTTsPH4BfoV5vo6mF985JAMtNDRYcaGFc", // random pubkeys
node_sol: 0.0,
node_lamports: 0,
vote: "GTKWbUoLw3Bv7Ld92crhyXcEk9zUu3VEKfzeuWJZdnfW",
commission: 50,
},
ValidatorInfo {
name: "unfun",
node: "3VTm54dw8w6jTTsPH4BfoV5vo6mF985JAMtNDRYcaGFc", // random pubkeys, same node
node_sol: 0.0,
node_lamports: 0,
vote: "GTKWbUoLw3Bv7Ld92crhyXcEk9zUu3VEKfzeuWJZdnfW", // duplicate vote, bad juju
commission: 50,
},

View File

@ -3,19 +3,19 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-gossip"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-net-utils = { path = "../net-utils", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-net-utils = { path = "../net-utils", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }

View File

@ -9,7 +9,7 @@ use solana_client::rpc_client::RpcClient;
use solana_core::{contact_info::ContactInfo, gossip_service::discover};
use solana_sdk::pubkey::Pubkey;
use std::error;
use std::net::SocketAddr;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::process::exit;
fn main() -> Result<(), Box<dyn error::Error>> {
@ -38,6 +38,13 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.takes_value(false)
.help("Return all RPC URLs"),
)
.arg(
Arg::with_name("any")
.long("any")
.takes_value(false)
.conflicts_with("all")
.help("Return any RPC URL"),
)
.arg(
Arg::with_name("timeout")
.long("timeout")
@ -74,9 +81,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.long("gossip-host")
.value_name("HOST")
.takes_value(true)
.conflicts_with("entrypoint")
.validator(solana_net_utils::is_host)
.help("Gossip DNS name or IP address for the node when --entrypoint is not provided [default: 127.0.0.1]"),
.help("Gossip DNS name or IP address for the node [default: ask --entrypoint, or 127.0.0.1 when --entrypoint is not provided]"),
)
.arg(
Arg::with_name("num_nodes")
@ -164,21 +170,29 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let entrypoint_addr = parse_entrypoint(&matches);
let gossip_host = if let Some(entrypoint_addr) = entrypoint_addr {
solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(|err| {
eprintln!(
"Failed to contact cluster entrypoint {}: {}",
entrypoint_addr, err
);
exit(1);
})
} else {
solana_net_utils::parse_host(matches.value_of("gossip_host").unwrap_or("127.0.0.1"))
.unwrap_or_else(|err| {
eprintln!("Error: {}", err);
let gossip_host = matches
.value_of("gossip_host")
.map(|gossip_host| {
solana_net_utils::parse_host(gossip_host).unwrap_or_else(|e| {
eprintln!("failed to parse gossip-host: {}", e);
exit(1);
})
};
})
.unwrap_or_else(|| {
if let Some(entrypoint_addr) = entrypoint_addr {
solana_net_utils::get_public_ip_addr(&entrypoint_addr).unwrap_or_else(
|err| {
eprintln!(
"Failed to contact cluster entrypoint {}: {}",
entrypoint_addr, err
);
exit(1);
},
)
} else {
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))
}
});
let gossip_addr = SocketAddr::new(
gossip_host,
@ -230,6 +244,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
}
}
("get-rpc-url", Some(matches)) => {
let any = matches.is_present("any");
let all = matches.is_present("all");
let entrypoint_addr = parse_entrypoint(&matches);
let timeout = value_t_or_exit!(matches, "timeout", u64);
let (nodes, _archivers) = discover(
@ -244,7 +260,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let rpc_addrs: Vec<_> = nodes
.iter()
.filter_map(|contact_info| {
if (matches.is_present("all") || Some(contact_info.gossip) == entrypoint_addr)
if (any || all || Some(contact_info.gossip) == entrypoint_addr)
&& ContactInfo::is_valid_address(&contact_info.rpc)
{
return Some(contact_info.rpc);
@ -260,6 +276,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
for rpc_addr in rpc_addrs {
println!("http://{}", rpc_addr);
if any {
break;
}
}
}
("stop", Some(matches)) => {

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.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -26,11 +26,11 @@ reqwest = { version = "0.9.24", default-features = false, features = ["rustls-tl
serde = "1.0.104"
serde_derive = "1.0.103"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-config-program = { path = "../programs/config", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-config-program = { path = "../programs/config", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
tar = "0.4.26"
tempdir = "0.3.7"
url = "2.1.0"

View File

@ -7,7 +7,7 @@ use chrono::{Local, TimeZone};
use console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle};
use solana_client::rpc_client::RpcClient;
use solana_config_program::{config_instruction, get_config_data};
use solana_config_program::{config_instruction, get_config_data, ConfigState};
use solana_sdk::{
hash::{Hash, Hasher},
message::Message,
@ -202,10 +202,13 @@ fn new_update_manifest(
{
let (recent_blockhash, _fee_calculator) = rpc_client.get_recent_blockhash()?;
let lamports = rpc_client
.get_minimum_balance_for_rent_exemption(SignedUpdateManifest::max_space() as usize)?;
let new_account = config_instruction::create_account::<SignedUpdateManifest>(
&from_keypair.pubkey(),
&update_manifest_keypair.pubkey(),
1, // lamports
lamports,
vec![], // additional keys
);
let mut transaction = Transaction::new_unsigned_instructions(new_account);

View File

@ -1,6 +1,6 @@
[package]
name = "solana-keygen"
version = "0.22.0"
version = "0.22.2"
description = "Solana key generation utility"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,8 +14,8 @@ clap = "2.33"
dirs = "2.0.2"
num_cpus = "1.11.1"
rpassword = "4.0"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
tiny-bip39 = "0.6.2"
[[bin]]

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.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,12 +16,12 @@ serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-ledger = { path = "../ledger", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-ledger = { path = "../ledger", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
[dev-dependencies]
assert_cmd = "0.12"

View File

@ -560,7 +560,14 @@ fn main() {
)
.subcommand(
SubCommand::with_name("bounds")
.about("Print lowest and highest non-empty slots. Note: This ignores gaps in slots")
.about("Print lowest and highest non-empty slots. Note that there may be empty slots within the bounds")
.arg(
Arg::with_name("all")
.long("all")
.takes_value(false)
.required(false)
.help("Additionally print all the non-empty slots within the bounds"),
)
)
.subcommand(
SubCommand::with_name("json")
@ -845,30 +852,34 @@ fn main() {
}
});
}
("bounds", _) => match open_blocktree(&ledger_path).slot_meta_iterator(0) {
Ok(metas) => {
println!("Collecting Ledger information...");
let slots: Vec<_> = metas.map(|(slot, _)| slot).collect();
if slots.is_empty() {
println!("Ledger is empty. No slots found.");
} else {
let first = slots.first().unwrap();
let last = slots.last().unwrap_or_else(|| first);
if first != last {
println!(
"Ledger contains some data for slots {:?} to {:?}",
first, last
);
("bounds", Some(args_matches)) => {
match open_blocktree(&ledger_path).slot_meta_iterator(0) {
Ok(metas) => {
let all = args_matches.is_present("all");
println!("Collecting Ledger information...");
let slots: Vec<_> = metas.map(|(slot, _)| slot).collect();
if slots.is_empty() {
println!("Ledger is empty. No slots found.");
} else {
println!("Ledger only contains some data for slot {:?}", first);
let first = slots.first().unwrap();
let last = slots.last().unwrap_or_else(|| first);
if first != last {
println!("Ledger contains data from slots {:?} to {:?}", first, last);
if all {
println!("Non-empty slots: {:?}", slots);
}
} else {
println!("Ledger only contains some data for slot {:?}", first);
}
}
}
Err(err) => {
eprintln!("Unable to read the Ledger: {:?}", err);
exit(1);
}
}
Err(err) => {
eprintln!("Unable to read the Ledger: {:?}", err);
exit(1);
}
},
}
("analyze-storage", _) => match analyze_storage(&open_database(&ledger_path)) {
Ok(()) => {
println!("Ok.");

View File

@ -1,6 +1,6 @@
[package]
name = "solana-ledger"
version = "0.22.0"
version = "0.22.2"
description = "Solana ledger"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -29,19 +29,19 @@ rayon = "1.2.0"
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
serde = "1.0.104"
serde_derive = "1.0.103"
solana-client = { path = "../client", version = "0.22.0" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-measure = { path = "../measure", version = "0.22.0" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-perf = { path = "../perf", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-measure = { path = "../measure", version = "0.22.2" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
solana-perf = { path = "../perf", version = "0.22.2" }
ed25519-dalek = "1.0.0-pre.1"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
sys-info = "0.5.8"
tar = "0.4.26"
thiserror = "1.0"
@ -57,7 +57,7 @@ features = ["lz4"]
[dev-dependencies]
assert_matches = "1.3.0"
matches = "0.1.6"
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
[lib]
crate-type = ["lib"]

View File

@ -61,7 +61,7 @@ thread_local!(static PAR_THREAD_POOL: RefCell<ThreadPool> = RefCell::new(rayon::
pub const MAX_COMPLETED_SLOTS_IN_CHANNEL: usize = 100_000;
pub const MAX_TURBINE_PROPAGATION_IN_MS: u64 = 100;
pub const MAX_TURBINE_DELAY_IN_TICKS: u64 = MAX_TURBINE_PROPAGATION_IN_MS / MS_PER_TICK;
const TIMESTAMP_SLOT_RANGE: usize = 5;
const TIMESTAMP_SLOT_RANGE: usize = 50;
pub type CompletedSlotsReceiver = Receiver<Vec<u64>>;
@ -1242,47 +1242,49 @@ impl Blocktree {
slot_duration: Duration,
stakes: &HashMap<Pubkey, (u64, Account)>,
) -> Option<UnixTimestamp> {
let mut total_stake = 0;
let stake_weighted_timestamps_sum: u64 = self
.get_timestamp_slots(slot, TIMESTAMP_SLOT_INTERVAL)
.iter()
.flat_map(|timestamp_slot| {
let unique_timestamps: HashMap<Pubkey, (Slot, UnixTimestamp)> = self
.get_timestamp_slots(slot, TIMESTAMP_SLOT_INTERVAL, TIMESTAMP_SLOT_RANGE)
.into_iter()
.flat_map(|query_slot| self.get_block_timestamps(query_slot).unwrap_or_default())
.collect();
let (stake_weighted_timestamps_sum, total_stake) = unique_timestamps
.into_iter()
.filter_map(|(vote_pubkey, (timestamp_slot, timestamp))| {
let offset = (slot - timestamp_slot) as u32 * slot_duration;
if let Ok(timestamps) = self.get_block_timestamps(*timestamp_slot) {
timestamps
.iter()
.filter_map(|(vote_pubkey, timestamp)| {
stakes.get(vote_pubkey).map(|(stake, _account)| {
total_stake += stake;
(*timestamp as u64 + offset.as_secs()) * stake
})
})
.collect()
} else {
vec![]
}
stakes
.get(&vote_pubkey)
.map(|(stake, _account)| ((timestamp as u64 + offset.as_secs()) * stake, stake))
})
.sum();
.fold((0, 0), |(timestamps, stakes), (timestamp, stake)| {
(timestamps + timestamp, stakes + stake)
});
if total_stake > 0 {
let mean_timestamp: u64 = stake_weighted_timestamps_sum / total_stake;
Some(mean_timestamp as i64)
Some((stake_weighted_timestamps_sum / total_stake) as i64)
} else {
None
}
}
fn get_timestamp_slots(&self, slot: Slot, timestamp_interval: u64) -> Vec<Slot> {
let rooted_slots = RootedSlotIterator::new(0, &self);
if !self.is_root(slot) || rooted_slots.is_err() {
fn get_timestamp_slots(
&self,
slot: Slot,
timestamp_interval: u64,
timestamp_sample_range: usize,
) -> Vec<Slot> {
let root_iterator = self.db.iter::<cf::Root>(IteratorMode::Start);
if !self.is_root(slot) || root_iterator.is_err() {
return vec![];
}
let lowest_nonzero_root = root_iterator.unwrap().map(|(slot, _)| slot).nth(1).unwrap();
let rooted_slots = RootedSlotIterator::new(lowest_nonzero_root, &self);
let slots: Vec<Slot> = rooted_slots
.unwrap()
.map(|(iter_slot, _)| iter_slot)
.filter(|&iter_slot| iter_slot <= slot)
.collect();
if slots.len() < TIMESTAMP_SLOT_RANGE {
if slots.len() < timestamp_sample_range {
return slots;
}
@ -1291,17 +1293,20 @@ impl Blocktree {
.position(|&x| x >= slot - (slot % timestamp_interval))
.unwrap();
let filtered_iter = if slots.len() - TIMESTAMP_SLOT_RANGE >= recent_timestamp_slot_position
{
slots.iter().skip(recent_timestamp_slot_position)
} else {
let earlier_timestamp_slot_position = slots
.iter()
.position(|&x| x >= slot - (slot % timestamp_interval) - timestamp_interval)
.unwrap();
slots.iter().skip(earlier_timestamp_slot_position)
};
filtered_iter.take(TIMESTAMP_SLOT_RANGE).cloned().collect()
let filtered_iter =
if slots.len() - timestamp_sample_range >= recent_timestamp_slot_position {
slots.iter().skip(recent_timestamp_slot_position)
} else {
let earlier_timestamp_slot_position = slots
.iter()
.position(|&x| x >= slot - (slot % timestamp_interval) - timestamp_interval)
.unwrap();
slots.iter().skip(earlier_timestamp_slot_position)
};
filtered_iter
.take(timestamp_sample_range)
.cloned()
.collect()
}
pub fn get_confirmed_block(&self, slot: Slot) -> Result<RpcConfirmedBlock> {
@ -1364,14 +1369,14 @@ impl Blocktree {
self.transaction_status_cf.put(index, status)
}
fn get_block_timestamps(&self, slot: Slot) -> Result<Vec<(Pubkey, UnixTimestamp)>> {
fn get_block_timestamps(&self, slot: Slot) -> Result<Vec<(Pubkey, (Slot, UnixTimestamp))>> {
let slot_entries = self.get_slot_entries(slot, 0, None)?;
Ok(slot_entries
.iter()
.cloned()
.flat_map(|entry| entry.transactions)
.flat_map(|transaction| {
let mut timestamps: Vec<(Pubkey, UnixTimestamp)> = Vec::new();
let mut timestamps: Vec<(Pubkey, (Slot, UnixTimestamp))> = Vec::new();
for instruction in transaction.message.instructions {
let program_id = instruction.program_id(&transaction.message.account_keys);
if program_id == &solana_vote_program::id() {
@ -1379,9 +1384,12 @@ impl Blocktree {
limited_deserialize(&instruction.data)
{
if let Some(timestamp) = vote.timestamp {
let vote_pubkey = transaction.message.account_keys
[instruction.accounts[0] as usize];
timestamps.push((vote_pubkey, timestamp));
let timestamp_slot = vote.slots.iter().max();
if let Some(timestamp_slot) = timestamp_slot {
let vote_pubkey = transaction.message.account_keys
[instruction.accounts[0] as usize];
timestamps.push((vote_pubkey, (*timestamp_slot, timestamp)));
}
}
}
}
@ -4448,6 +4456,7 @@ pub mod tests {
#[test]
fn test_get_timestamp_slots() {
let timestamp_sample_range = 5;
let ticks_per_slot = 5;
// Smaller interval than TIMESTAMP_SLOT_INTERVAL for convenience of building blocktree
let timestamp_interval = 7;
@ -4477,12 +4486,12 @@ pub mod tests {
blocktree.set_roots(&[1, 2, 3]).unwrap();
assert_eq!(
blocktree.get_timestamp_slots(2, timestamp_interval),
vec![0, 1, 2]
blocktree.get_timestamp_slots(2, timestamp_interval, timestamp_sample_range),
vec![1, 2]
);
assert_eq!(
blocktree.get_timestamp_slots(3, timestamp_interval),
vec![0, 1, 2, 3]
blocktree.get_timestamp_slots(3, timestamp_interval, timestamp_sample_range),
vec![1, 2, 3]
);
drop(blocktree);
@ -4517,23 +4526,23 @@ pub mod tests {
blocktree.set_roots(&desired_roots).unwrap();
assert_eq!(
blocktree.get_timestamp_slots(2, timestamp_interval),
vec![0, 1, 2]
blocktree.get_timestamp_slots(2, timestamp_interval, timestamp_sample_range),
vec![1, 2]
);
assert_eq!(
blocktree.get_timestamp_slots(8, timestamp_interval),
vec![0, 1, 2, 3, 4]
blocktree.get_timestamp_slots(8, timestamp_interval, timestamp_sample_range),
vec![1, 2, 3, 4, 5]
);
assert_eq!(
blocktree.get_timestamp_slots(13, timestamp_interval),
blocktree.get_timestamp_slots(13, timestamp_interval, timestamp_sample_range),
vec![8, 9, 10, 11, 12]
);
assert_eq!(
blocktree.get_timestamp_slots(18, timestamp_interval),
blocktree.get_timestamp_slots(18, timestamp_interval, timestamp_sample_range),
vec![8, 9, 10, 11, 12]
);
assert_eq!(
blocktree.get_timestamp_slots(19, timestamp_interval),
blocktree.get_timestamp_slots(19, timestamp_interval, timestamp_sample_range),
vec![14, 16, 17, 18, 19]
);
}
@ -4642,14 +4651,14 @@ pub mod tests {
fn test_get_block_timestamps() {
let vote_keypairs: Vec<Keypair> = (0..6).map(|_| Keypair::new()).collect();
let base_timestamp = 1576183541;
let mut expected_timestamps: Vec<(Pubkey, UnixTimestamp)> = Vec::new();
let mut expected_timestamps: Vec<(Pubkey, (Slot, UnixTimestamp))> = Vec::new();
// Populate slot 1 with vote transactions, some of which have timestamps
let mut vote_entries: Vec<Entry> = Vec::new();
for (i, keypair) in vote_keypairs.iter().enumerate() {
let timestamp = if i % 2 == 0 {
let unique_timestamp = base_timestamp + i as i64;
expected_timestamps.push((keypair.pubkey(), unique_timestamp));
expected_timestamps.push((keypair.pubkey(), (1, unique_timestamp)));
Some(unique_timestamp)
} else {
None

View File

@ -11,6 +11,7 @@ use itertools::Itertools;
use log::*;
use rand::{seq::SliceRandom, thread_rng};
use rayon::{prelude::*, ThreadPool};
use solana_measure::thread_mem_usage;
use solana_metrics::{datapoint, datapoint_error, inc_new_counter_debug};
use solana_rayon_threadlimit::get_thread_count;
use solana_runtime::{
@ -279,7 +280,7 @@ pub fn process_blocktree(
// Setup bank for slot 0
let bank0 = Arc::new(Bank::new_with_paths(&genesis_config, account_paths));
info!("processing ledger for bank 0...");
info!("processing ledger for slot 0...");
process_bank_0(&bank0, blocktree, &opts)?;
process_blocktree_from_root(genesis_config, blocktree, bank0, &opts)
}
@ -291,7 +292,10 @@ pub fn process_blocktree_from_root(
bank: Arc<Bank>,
opts: &ProcessOptions,
) -> result::Result<(BankForks, Vec<BankForksInfo>, LeaderScheduleCache), BlocktreeProcessorError> {
info!("processing ledger from root: {}...", bank.slot());
info!("processing ledger from root slot {}...", bank.slot());
let allocated = thread_mem_usage::Allocatedp::default();
let initial_allocation = allocated.get();
// Starting slot must be a root, and thus has no parents
assert!(bank.parent().is_none());
let start_slot = bank.slot();
@ -304,7 +308,7 @@ pub fn process_blocktree_from_root(
blocktree
.set_roots(&[start_slot])
.expect("Couldn't set root on startup");
.expect("Couldn't set root slot on startup");
let meta = blocktree.meta(start_slot).unwrap();
@ -344,8 +348,9 @@ pub fn process_blocktree_from_root(
};
info!(
"ledger processed in {}ms. {} fork{} at {}",
"ledger processed in {}ms. {} MB allocated. {} fork{} at {}",
duration_as_ms(&now.elapsed()),
allocated.since(initial_allocation) / 1_000_000,
bank_forks_info.len(),
if bank_forks_info.len() > 1 { "s" } else { "" },
bank_forks_info
@ -461,6 +466,9 @@ fn process_next_slots(
// Only process full slots in blocktree_processor, replay_stage
// handles any partials
if next_meta.is_full() {
let allocated = thread_mem_usage::Allocatedp::default();
let initial_allocation = allocated.get();
let next_bank = Arc::new(Bank::new_from_parent(
&bank,
&leader_schedule_cache
@ -468,7 +476,12 @@ fn process_next_slots(
.unwrap(),
*next_slot,
));
trace!("Add child bank {} of slot={}", next_slot, bank.slot());
trace!(
"New bank for slot {}, parent slot is {}. {} bytes allocated",
next_slot,
bank.slot(),
allocated.since(initial_allocation)
);
pending_slots.push((*next_slot, next_meta, next_bank, bank.last_blockhash()));
} else {
let bfi = BankForksInfo {
@ -496,6 +509,7 @@ fn process_pending_slots(
let mut fork_info = vec![];
let mut last_status_report = Instant::now();
let mut pending_slots = vec![];
let mut last_root_slot = root_bank.slot();
process_next_slots(
root_bank,
root_meta,
@ -510,7 +524,10 @@ fn process_pending_slots(
let (slot, meta, bank, last_entry_hash) = pending_slots.pop().unwrap();
if last_status_report.elapsed() > Duration::from_secs(2) {
info!("processing ledger...block {}", slot);
info!(
"processing ledger: slot={}, last root slot={}",
slot, last_root_slot
);
last_status_report = Instant::now();
}
@ -519,6 +536,9 @@ fn process_pending_slots(
continue;
}
let allocated = thread_mem_usage::Allocatedp::default();
let initial_allocation = allocated.get();
// Fetch all entries for this slot
let entries = blocktree.get_slot_entries(slot, 0, None).map_err(|err| {
warn!("Failed to load entries for slot {}: {:?}", slot, err);
@ -541,8 +561,16 @@ fn process_pending_slots(
bank.squash();
pending_slots.clear();
fork_info.clear();
last_root_slot = slot;
}
trace!(
"Bank for {}slot {} is complete. {} bytes allocated",
if last_root_slot == slot { "root " } else { "" },
slot,
allocated.since(initial_allocation)
);
if slot >= dev_halt_at_slot {
let bfi = BankForksInfo { bank_slot: slot };
fork_info.push((bank, bfi));

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-local-cluster"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -12,23 +12,23 @@ homepage = "https://solana.com/"
itertools = "0.8.1"
log = "0.4.8"
rand = "0.6.5"
solana-config-program = { path = "../programs/config", version = "0.22.0" }
solana-core = { path = "../core", version = "0.22.0" }
solana-client = { path = "../client", version = "0.22.0" }
solana-faucet = { path = "../faucet", version = "0.22.0" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.0" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.0" }
solana-ledger = { path = "../ledger", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-runtime = { path = "../runtime", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-stake-program = { path = "../programs/stake", version = "0.22.0" }
solana-storage-program = { path = "../programs/storage", version = "0.22.0" }
solana-vest-program = { path = "../programs/vest", version = "0.22.0" }
solana-vote-program = { path = "../programs/vote", version = "0.22.0" }
solana-config-program = { path = "../programs/config", version = "0.22.2" }
solana-core = { path = "../core", version = "0.22.2" }
solana-client = { path = "../client", version = "0.22.2" }
solana-faucet = { path = "../faucet", version = "0.22.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.22.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.22.2" }
solana-ledger = { path = "../ledger", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-runtime = { path = "../runtime", version = "0.22.2" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-stake-program = { path = "../programs/stake", version = "0.22.2" }
solana-storage-program = { path = "../programs/storage", version = "0.22.2" }
solana-vest-program = { path = "../programs/vest", version = "0.22.2" }
solana-vote-program = { path = "../programs/vote", version = "0.22.2" }
symlink = "0.1.0"
tempfile = "3.1.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.0" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.2" }
[dev-dependencies]
assert_matches = "1.3.0"

View File

@ -733,6 +733,7 @@ mod test {
cluster_lamports: 100,
ticks_per_slot: 8,
slots_per_epoch: MINIMUM_SLOTS_PER_EPOCH as u64,
stakers_slot_offset: MINIMUM_SLOTS_PER_EPOCH as u64,
..ClusterConfig::default()
};
let cluster = LocalCluster::new(&config);

View File

@ -449,6 +449,7 @@ fn test_two_unbalanced_stakes() {
validator_configs: vec![validator_config.clone(); 2],
ticks_per_slot: num_ticks_per_slot,
slots_per_epoch: num_slots_per_epoch,
stakers_slot_offset: num_slots_per_epoch,
poh_config: PohConfig::new_sleep(Duration::from_millis(1000 / num_ticks_per_second)),
..ClusterConfig::default()
});
@ -497,15 +498,16 @@ fn test_forwarding() {
fn test_restart_node() {
solana_logger::setup();
error!("test_restart_node");
let slots_per_epoch = MINIMUM_SLOTS_PER_EPOCH as u64;
let slots_per_epoch = MINIMUM_SLOTS_PER_EPOCH * 2 as u64;
let ticks_per_slot = 16;
let validator_config = ValidatorConfig::default();
let mut cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![3],
node_stakes: vec![100; 1],
cluster_lamports: 100,
validator_configs: vec![validator_config.clone()],
ticks_per_slot,
slots_per_epoch,
stakers_slot_offset: slots_per_epoch,
..ClusterConfig::default()
});
let nodes = cluster.get_node_pubkeys();

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-log-analyzer"
description = "The solana cluster network analysis tool"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -17,8 +17,8 @@ semver = "0.9.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
[[bin]]
name = "solana-log-analyzer"

View File

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

View File

@ -1,7 +1,7 @@
[package]
name = "solana-measure"
description = "Blockchain, Rebuilt for Scale"
version = "0.22.0"
version = "0.22.2"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -11,4 +11,10 @@ license = "Apache-2.0"
edition = "2018"
[dependencies]
solana-sdk = { path = "../sdk", version = "0.22.0" }
log = "0.4.8"
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
[target."cfg(unix)".dependencies]
jemallocator = "0.3.2"
jemalloc-ctl = "0.3.2"

View File

@ -1 +1,9 @@
pub mod measure;
pub mod thread_mem_usage;
#[cfg(unix)]
extern crate jemallocator;
#[cfg(unix)]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

View File

@ -28,6 +28,7 @@ impl Allocatedp {
Self {}
}
/// Return current thread heap usage
pub fn get(&self) -> u64 {
#[cfg(unix)]
{
@ -36,4 +37,9 @@ impl Allocatedp {
#[cfg(not(unix))]
0
}
/// Return the difference in thread heap usage since a previous `get()`
pub fn since(&self, previous: u64) -> i64 {
self.get() as i64 - previous as i64
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-merkle-tree"
version = "0.22.0"
version = "0.22.2"
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.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
[dev-dependencies]
hex = "0.4.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-metrics"
version = "0.22.0"
version = "0.22.2"
description = "Solana Metrics"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,7 +13,7 @@ env_logger = "0.7.1"
lazy_static = "1.4.0"
log = "0.4.8"
reqwest = { version = "0.9.24", default-features = false, features = ["rustls-tls"] }
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
sys-info = "0.5.8"
[dev-dependencies]

View File

@ -273,7 +273,7 @@ setup_validator_accounts() {
return 0
}
rpc_url=$($solana_gossip get-rpc-url --entrypoint "$gossip_entrypoint")
rpc_url=$($solana_gossip get-rpc-url --entrypoint "$gossip_entrypoint" --any)
[[ -r "$identity_keypair_path" ]] || $solana_keygen new --no-passphrase -so "$identity_keypair_path"
[[ -r "$voting_keypair_path" ]] || $solana_keygen new --no-passphrase -so "$voting_keypair_path"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-net-shaper"
description = "The solana cluster network shaping tool"
version = "0.22.0"
version = "0.22.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,8 +16,8 @@ semver = "0.9.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
rand = "0.6.5"
[[bin]]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-net-utils"
version = "0.22.0"
version = "0.22.2"
description = "Solana Network Utilities"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,8 +18,8 @@ rand = "0.6.1"
serde = "1.0.104"
serde_derive = "1.0.103"
socket2 = "0.3.11"
solana-clap-utils = { path = "../clap-utils", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-clap-utils = { path = "../clap-utils", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -41,11 +41,17 @@ pub fn ip_echo_server(tcp: std::net::TcpListener) -> IpEchoServer {
let server = tcp
.incoming()
.map_err(|err| warn!("accept failed: {:?}", err))
.for_each(move |socket| {
let peer_addr = socket.peer_addr().expect("Expect peer_addr()");
info!("connection from {:?}", peer_addr);
let framed = BytesCodec::new().framed(socket);
.filter_map(|socket| match socket.peer_addr() {
Ok(peer_addr) => {
info!("connection from {:?}", peer_addr);
Some((peer_addr, BytesCodec::new().framed(socket)))
}
Err(err) => {
info!("peer_addr failed for {:?}: {:?}", socket, err);
None
}
})
.for_each(move |(peer_addr, framed)| {
let (writer, reader) = framed.split();
let processor = reader

View File

@ -456,10 +456,16 @@ startCommon() {
"
fi
[[ -z "$externalNodeSshKey" ]] || ssh-copy-id -f -i "$externalNodeSshKey" "${sshOptions[@]}" "solana@$ipAddress"
syncScripts "$ipAddress"
}
syncScripts() {
echo "rsyncing scripts... to $ipAddress"
declare ipAddress=$1
rsync -vPrc -e "ssh ${sshOptions[*]}" \
--exclude 'net/log*' \
"$SOLANA_ROOT"/{fetch-perf-libs.sh,scripts,net,multinode-demo} \
"$ipAddress":~/solana/
"$ipAddress":~/solana/ > /dev/null
}
startBootstrapLeader() {
@ -870,33 +876,14 @@ stopNode() {
echo "--- Stopping node: $ipAddress"
echo "stop log: $logFile"
syncScripts "$ipAddress"
(
# Since cleanup.sh does a pkill, we cannot pass the command directly,
# otherwise the process which is doing the killing will be killed because
# the script itself will match the pkill pattern
set -x
# shellcheck disable=SC2029 # It's desired that PS4 be expanded on the client side
ssh "${sshOptions[@]}" "$ipAddress" "
PS4=\"$PS4\"
set -x
! tmux list-sessions || tmux kill-session
declare sudo=
if sudo true; then
sudo=\"sudo -n\"
fi
for pid in solana/*.pid; do
pgid=\$(ps opgid= \$(cat \$pid) | tr -d '[:space:]')
if [[ -n \$pgid ]]; then
\$sudo kill -- -\$pgid
fi
done
if [[ -f solana/netem.cfg ]]; then
solana/scripts/netem.sh delete < solana/netem.cfg
rm -f solana/netem.cfg
fi
solana/scripts/net-shaper.sh force_cleanup
for pattern in solana- remote- iftop validator client node; do
pkill -9 -f \$pattern
done
"
ssh "${sshOptions[@]}" "$ipAddress" "PS4=\"$PS4\" ./solana/net/remote/cleanup.sh"
) >> "$logFile" 2>&1 &
declare pid=$!

25
net/remote/cleanup.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -x
! tmux list-sessions || tmux kill-session
declare sudo=
if sudo true; then
sudo="sudo -n"
fi
echo "pwd: $(pwd)"
for pid in solana/*.pid; do
pgid=$(ps opgid= "$(cat "$pid")" | tr -d '[:space:]')
if [[ -n $pgid ]]; then
$sudo kill -- -"$pgid"
fi
done
if [[ -f solana/netem.cfg ]]; then
solana/scripts/netem.sh delete < solana/netem.cfg
rm -f solana/netem.cfg
fi
solana/scripts/net-shaper.sh force_cleanup
for pattern in validator.sh boostrap-leader.sh solana- remote- iftop validator client node; do
echo "killing $pattern"
pkill -f $pattern
done

View File

@ -1,6 +1,6 @@
[package]
name = "solana-perf"
version = "0.22.0"
version = "0.22.2"
description = "Solana Performance APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,11 +18,11 @@ serde_derive = "1.0.103"
dlopen_derive = "0.1.4"
lazy_static = "1.4.0"
log = "0.4.8"
solana-sdk = { path = "../sdk", version = "0.22.0" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.0" }
solana-budget-program = { path = "../programs/budget", version = "0.22.0" }
solana-logger = { path = "../logger", version = "0.22.0" }
solana-metrics = { path = "../metrics", version = "0.22.0" }
solana-sdk = { path = "../sdk", version = "0.22.2" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.22.2" }
solana-budget-program = { path = "../programs/budget", version = "0.22.2" }
solana-logger = { path = "../logger", version = "0.22.2" }
solana-metrics = { path = "../metrics", version = "0.22.2" }
[lib]
name = "solana_perf"

View File

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

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-128bit"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,11 +12,11 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.22.0" }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.22.2" }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-128bit-dep"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-alloc"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

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

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-external-spend"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-iter"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-many-args"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,11 +12,11 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.22.0" }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.22.2" }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-many-args-dep"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-noop"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-panic"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-param-passing"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,11 +12,11 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.22.0" }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.22.2" }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-param-passing-dep"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package]
name = "solana-bpf-rust-sysval"
version = "0.22.0"
version = "0.22.2"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../../../sdk/", version = "0.22.0", default-features = false }
solana-sdk = { path = "../../../../sdk/", version = "0.22.2", default-features = false }
[dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.0" }
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.22.2" }
[features]
program = ["solana-sdk/program"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-bpf-loader-program"
version = "0.22.0"
version = "0.22.2"
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.66"
log = "0.4.8"
serde = "1.0.104"
solana-logger = { path = "../../logger", version = "0.22.0" }
solana-sdk = { path = "../../sdk", version = "0.22.0" }
solana-logger = { path = "../../logger", version = "0.22.2" }
solana-sdk = { path = "../../sdk", version = "0.22.2" }
solana_rbpf = "=0.1.19"
[lib]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-btc-spv-program"
version = "0.22.0"
version = "0.22.2"
description = "Solana Bitcoin spv parsing program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,7 +16,7 @@ num-derive = "0.3"
num-traits = "0.2"
serde = "1.0.104"
serde_derive = "1.0.103"
solana-sdk = { path = "../../sdk", version = "0.22.0"}
solana-sdk = { path = "../../sdk", version = "0.22.2"}
hex = "0.3.2"
[lib]

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