Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
d6d3a3c3d8 | |||
3e229b248f | |||
0470072436 | |||
f74fa60c8b | |||
c189767090 | |||
c82c18353d | |||
da58a272dd | |||
001f5fbb6b | |||
63cd452ab5 | |||
6ee77e9754 | |||
cee22262fc | |||
0d13352916 | |||
78a9832f13 | |||
795cf14650 | |||
8c112e8bc4 | |||
8e6d213459 | |||
b33df42640 | |||
e0462e6933 | |||
1f5e30a366 | |||
633eeb1586 | |||
c1148a6da3 | |||
713e86670d | |||
c004c726e7 | |||
5ffb8631e0 | |||
fd32a0280e | |||
e76f202eb3 | |||
ba4558cb92 | |||
74e5577dd4 | |||
b878002cf5 | |||
f111250e3b | |||
3d91f650db | |||
91a88cda6a | |||
2128c17ed0 | |||
7b819c9b74 | |||
eec5c661af | |||
0398f6b87a |
589
Cargo.lock
generated
589
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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" }
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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" }
|
||||
|
@ -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" }
|
||||
|
@ -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"]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
289
book/src/offline-signing/durable-nonce.md
Normal file
289
book/src/offline-signing/durable-nonce.md
Normal 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
|
||||
```
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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"`
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
;;
|
||||
*)
|
||||
|
@ -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 \
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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]]
|
||||
|
420
cli/src/cli.rs
420
cli/src/cli.rs
@ -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);
|
||||
|
@ -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 {})",
|
||||
|
203
cli/src/nonce.rs
203
cli/src/nonce.rs
@ -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
|
||||
))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
179
cli/src/stake.rs
179
cli/src/stake.rs
@ -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
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
148
cli/tests/pay.rs
148
cli/tests/pay.rs
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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" }
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ pub struct RpcVoteAccountInfo {
|
||||
pub root_slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RpcRequest {
|
||||
ConfirmTransaction,
|
||||
DeregisterNode,
|
||||
|
@ -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"
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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::{
|
||||
|
@ -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};
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"]
|
||||
|
@ -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!(),
|
||||
|
@ -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]]
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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" }
|
||||
|
||||
|
||||
|
||||
|
@ -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)) => {
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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]]
|
||||
|
@ -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"
|
||||
|
@ -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.");
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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]
|
||||
|
@ -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"
|
||||
|
@ -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]]
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
37
net/net.sh
37
net/net.sh
@ -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
25
net/remote/cleanup.sh
Executable 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
|
@ -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"
|
||||
|
@ -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]]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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]
|
||||
|
@ -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
Reference in New Issue
Block a user