Compare commits
55 Commits
Author | SHA1 | Date | |
---|---|---|---|
235158d2bc | |||
521238f7d7 | |||
384f52a607 | |||
49f2d912ab | |||
8652fe30ce | |||
899a14ba51 | |||
466c7dafb3 | |||
293bb63ed8 | |||
8f8fb720af | |||
19f414d843 | |||
eaca1c3170 | |||
9fc75925f9 | |||
b5098ac87c | |||
e23aec9728 | |||
57d490c84f | |||
aa8c9f6a98 | |||
57772dc73d | |||
21706108e8 | |||
50d0caf00f | |||
2739332306 | |||
c85c4699aa | |||
81add4d6bf | |||
8e31eeb696 | |||
e1ce8b37ff | |||
3f831c05f5 | |||
f0d7ce6bb6 | |||
6ba95b2545 | |||
6818e68542 | |||
43659d7deb | |||
f24d8e7d2d | |||
e10fe5e125 | |||
0f8c9ab1c4 | |||
8a9a9cb991 | |||
44208ffa67 | |||
5df0478fa3 | |||
d52567933e | |||
a32cdb9f4d | |||
eacd8d986c | |||
1d32603b49 | |||
8c6f7ee5a4 | |||
be482eed3f | |||
6e1c53cb0f | |||
af92f205cf | |||
87047b08c8 | |||
e282161872 | |||
01b1e287ed | |||
d7fd1fa467 | |||
bfa34cd494 | |||
915835e224 | |||
659332e7ac | |||
272986c6ac | |||
4d8ab45c56 | |||
932ae86d47 | |||
756e6334b0 | |||
4e6eca9748 |
666
Cargo.lock
generated
666
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@ members = [
|
||||
"chacha",
|
||||
"chacha-cuda",
|
||||
"chacha-sys",
|
||||
"cli-config",
|
||||
"client",
|
||||
"core",
|
||||
"faucet",
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-archiver-lib"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Archiver Library"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -15,22 +15,22 @@ ed25519-dalek = "=1.0.0-pre.1"
|
||||
log = "0.4.8"
|
||||
rand = "0.6.5"
|
||||
rand_chacha = "0.1.1"
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
thiserror = "1.0"
|
||||
serde = "1.0.104"
|
||||
serde_json = "1.0.44"
|
||||
serde_derive = "1.0.103"
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-chacha = { path = "../chacha", version = "0.23.0" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-chacha = { path = "../chacha", version = "0.23.2" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4.0"
|
||||
|
@ -522,6 +522,8 @@ impl Archiver {
|
||||
let mut contact_info = node_info.clone();
|
||||
contact_info.tvu = "0.0.0.0:0".parse().unwrap();
|
||||
contact_info.wallclock = timestamp();
|
||||
// copy over the adopted shred_version from the entrypoint
|
||||
contact_info.shred_version = cluster_info.read().unwrap().my_data().shred_version;
|
||||
{
|
||||
let mut cluster_info_w = cluster_info.write().unwrap();
|
||||
cluster_info_w.insert_self(contact_info);
|
||||
@ -701,7 +703,7 @@ impl Archiver {
|
||||
) -> Result<u64> {
|
||||
let rpc_peers = {
|
||||
let cluster_info = cluster_info.read().unwrap();
|
||||
cluster_info.rpc_peers()
|
||||
cluster_info.all_rpc_peers()
|
||||
};
|
||||
debug!("rpc peers: {:?}", rpc_peers);
|
||||
if !rpc_peers.is_empty() {
|
||||
@ -757,7 +759,7 @@ impl Archiver {
|
||||
loop {
|
||||
let rpc_peers = {
|
||||
let cluster_info = cluster_info.read().unwrap();
|
||||
cluster_info.rpc_peers()
|
||||
cluster_info.all_rpc_peers()
|
||||
};
|
||||
debug!("rpc peers: {:?}", rpc_peers);
|
||||
if !rpc_peers.is_empty() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-archiver-utils"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Archiver Utils"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -12,12 +12,12 @@ edition = "2018"
|
||||
log = "0.4.8"
|
||||
rand = "0.6.5"
|
||||
rand_chacha = "0.1.1"
|
||||
solana-chacha = { path = "../chacha", version = "0.23.0" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-chacha = { path = "../chacha", version = "0.23.2" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4.0"
|
||||
|
@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-archiver"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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]
|
||||
clap = "2.33.0"
|
||||
console = "0.9.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-measure = { path = "../measure", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-measure = { path = "../measure", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.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.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-genesis = { path = "../genesis", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.0" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-genesis = { path = "../genesis", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.2" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
untrusted = "0.7.0"
|
||||
ws = "0.9.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "0.23.0" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "0.23.2" }
|
||||
|
@ -2,14 +2,14 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
|
@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-genesis = { path = "../genesis", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.0" }
|
||||
solana-librapay = { path = "../programs/librapay", version = "0.23.0", optional = true }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-measure = { path = "../measure", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-move-loader-program = { path = "../programs/move_loader", version = "0.23.0", optional = true }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-genesis = { path = "../genesis", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.2" }
|
||||
solana-librapay = { path = "../programs/librapay", version = "0.23.2", optional = true }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-measure = { path = "../measure", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-move-loader-program = { path = "../programs/move_loader", version = "0.23.2", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.3.2"
|
||||
serial_test_derive = "0.3.1"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "0.23.0" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
move = ["solana-librapay", "solana-move-loader-program"]
|
||||
|
@ -827,7 +827,7 @@ The result field will be a JSON object with the following fields:
|
||||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"solana-core": "0.23.0"},"id":1}
|
||||
{"jsonrpc":"2.0","result":{"solana-core": "0.23.2"},"id":1}
|
||||
```
|
||||
|
||||
### getVoteAccounts
|
||||
|
@ -177,7 +177,7 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
|
||||
## Usage
|
||||
### solana-cli
|
||||
```text
|
||||
solana-cli 0.23.0 [channel=unknown commit=unknown]
|
||||
solana-cli 0.23.2 [channel=unknown commit=unknown]
|
||||
Blockchain, Rebuilt for Scale
|
||||
|
||||
USAGE:
|
||||
@ -241,7 +241,6 @@ SUBCOMMANDS:
|
||||
stakes Show stake account information
|
||||
storage-account Show the contents of a storage account
|
||||
transaction-count Get current transaction count
|
||||
uptime Show the uptime of a validator, based on epoch voting history
|
||||
validator-info Publish/get Validator info on Solana
|
||||
validators Show summary information about the current validators
|
||||
vote-account Show the contents of a vote account
|
||||
@ -254,7 +253,7 @@ SUBCOMMANDS:
|
||||
|
||||
#### solana-account
|
||||
```text
|
||||
solana-account
|
||||
solana-account
|
||||
Show the contents of an account
|
||||
|
||||
USAGE:
|
||||
@ -283,7 +282,7 @@ ARGS:
|
||||
|
||||
#### solana-address
|
||||
```text
|
||||
solana-address
|
||||
solana-address
|
||||
Get your public key
|
||||
|
||||
USAGE:
|
||||
@ -307,7 +306,7 @@ OPTIONS:
|
||||
|
||||
#### solana-airdrop
|
||||
```text
|
||||
solana-airdrop
|
||||
solana-airdrop
|
||||
Request lamports
|
||||
|
||||
USAGE:
|
||||
@ -337,7 +336,7 @@ ARGS:
|
||||
|
||||
#### solana-authorize-nonce-account
|
||||
```text
|
||||
solana-authorize-nonce-account
|
||||
solana-authorize-nonce-account
|
||||
Assign account authority to a new entity
|
||||
|
||||
USAGE:
|
||||
@ -373,7 +372,7 @@ ARGS:
|
||||
|
||||
#### solana-balance
|
||||
```text
|
||||
solana-balance
|
||||
solana-balance
|
||||
Get your balance
|
||||
|
||||
USAGE:
|
||||
@ -401,7 +400,7 @@ ARGS:
|
||||
|
||||
#### solana-block-production
|
||||
```text
|
||||
solana-block-production
|
||||
solana-block-production
|
||||
Show information about block production
|
||||
|
||||
USAGE:
|
||||
@ -428,7 +427,7 @@ OPTIONS:
|
||||
|
||||
#### solana-block-time
|
||||
```text
|
||||
solana-block-time
|
||||
solana-block-time
|
||||
Get estimated production time of a block
|
||||
|
||||
USAGE:
|
||||
@ -455,7 +454,7 @@ ARGS:
|
||||
|
||||
#### solana-cancel
|
||||
```text
|
||||
solana-cancel
|
||||
solana-cancel
|
||||
Cancel a transfer
|
||||
|
||||
USAGE:
|
||||
@ -482,7 +481,7 @@ ARGS:
|
||||
|
||||
#### solana-catchup
|
||||
```text
|
||||
solana-catchup
|
||||
solana-catchup
|
||||
Wait for a validator to catch up to the cluster
|
||||
|
||||
USAGE:
|
||||
@ -509,7 +508,7 @@ ARGS:
|
||||
|
||||
#### solana-claim-storage-reward
|
||||
```text
|
||||
solana-claim-storage-reward
|
||||
solana-claim-storage-reward
|
||||
Redeem storage reward credits
|
||||
|
||||
USAGE:
|
||||
@ -537,7 +536,7 @@ ARGS:
|
||||
|
||||
#### solana-cluster-version
|
||||
```text
|
||||
solana-cluster-version
|
||||
solana-cluster-version
|
||||
Get the version of the cluster entrypoint
|
||||
|
||||
USAGE:
|
||||
@ -561,7 +560,7 @@ OPTIONS:
|
||||
|
||||
#### solana-config
|
||||
```text
|
||||
solana-config
|
||||
solana-config
|
||||
Solana command-line tool configuration settings
|
||||
|
||||
USAGE:
|
||||
@ -590,7 +589,7 @@ SUBCOMMANDS:
|
||||
|
||||
#### solana-confirm
|
||||
```text
|
||||
solana-confirm
|
||||
solana-confirm
|
||||
Confirm transaction by signature
|
||||
|
||||
USAGE:
|
||||
@ -617,7 +616,7 @@ ARGS:
|
||||
|
||||
#### solana-create-address-with-seed
|
||||
```text
|
||||
solana-create-address-with-seed
|
||||
solana-create-address-with-seed
|
||||
Generate a derived account address with a seed
|
||||
|
||||
USAGE:
|
||||
@ -641,13 +640,13 @@ OPTIONS:
|
||||
|
||||
ARGS:
|
||||
<SEED_STRING> The seed. Must not take more than 32 bytes to encode as utf-8
|
||||
<PROGRAM_ID> The program_id that the address will ultimately be used for,
|
||||
<PROGRAM_ID> The program_id that the address will ultimately be used for,
|
||||
or one of STAKE, VOTE, and STORAGE keywords
|
||||
```
|
||||
|
||||
#### solana-create-archiver-storage-account
|
||||
```text
|
||||
solana-create-archiver-storage-account
|
||||
solana-create-archiver-storage-account
|
||||
Create an archiver storage account
|
||||
|
||||
USAGE:
|
||||
@ -669,13 +668,13 @@ OPTIONS:
|
||||
-k, --keypair <PATH> /path/to/id.json
|
||||
|
||||
ARGS:
|
||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||
<STORAGE ACCOUNT>
|
||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||
<STORAGE ACCOUNT>
|
||||
```
|
||||
|
||||
#### solana-create-nonce-account
|
||||
```text
|
||||
solana-create-nonce-account
|
||||
solana-create-nonce-account
|
||||
Create a nonce account
|
||||
|
||||
USAGE:
|
||||
@ -705,7 +704,7 @@ ARGS:
|
||||
|
||||
#### solana-create-stake-account
|
||||
```text
|
||||
solana-create-stake-account
|
||||
solana-create-stake-account
|
||||
Create a stake account
|
||||
|
||||
USAGE:
|
||||
@ -741,7 +740,7 @@ ARGS:
|
||||
|
||||
#### solana-create-validator-storage-account
|
||||
```text
|
||||
solana-create-validator-storage-account
|
||||
solana-create-validator-storage-account
|
||||
Create a validator storage account
|
||||
|
||||
USAGE:
|
||||
@ -763,13 +762,13 @@ OPTIONS:
|
||||
-k, --keypair <PATH> /path/to/id.json
|
||||
|
||||
ARGS:
|
||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||
<STORAGE ACCOUNT>
|
||||
<STORAGE ACCOUNT OWNER PUBKEY>
|
||||
<STORAGE ACCOUNT>
|
||||
```
|
||||
|
||||
#### solana-create-vote-account
|
||||
```text
|
||||
solana-create-vote-account
|
||||
solana-create-vote-account
|
||||
Create a vote account
|
||||
|
||||
USAGE:
|
||||
@ -802,7 +801,7 @@ ARGS:
|
||||
|
||||
#### solana-deactivate-stake
|
||||
```text
|
||||
solana-deactivate-stake
|
||||
solana-deactivate-stake
|
||||
Deactivate the delegated stake from the stake account
|
||||
|
||||
USAGE:
|
||||
@ -827,9 +826,9 @@ OPTIONS:
|
||||
-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
|
||||
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 <KEYPAIR or PUBKEY>
|
||||
Provide the nonce authority keypair to use when signing a nonced transaction
|
||||
@ -843,7 +842,7 @@ ARGS:
|
||||
|
||||
#### solana-delegate-stake
|
||||
```text
|
||||
solana-delegate-stake
|
||||
solana-delegate-stake
|
||||
Delegate stake to a vote account
|
||||
|
||||
USAGE:
|
||||
@ -868,9 +867,9 @@ OPTIONS:
|
||||
-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
|
||||
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 <KEYPAIR or PUBKEY>
|
||||
Provide the nonce authority keypair to use when signing a nonced transaction
|
||||
@ -885,7 +884,7 @@ ARGS:
|
||||
|
||||
#### solana-deploy
|
||||
```text
|
||||
solana-deploy
|
||||
solana-deploy
|
||||
Deploy a program
|
||||
|
||||
USAGE:
|
||||
@ -912,7 +911,7 @@ ARGS:
|
||||
|
||||
#### solana-epoch-info
|
||||
```text
|
||||
solana-epoch-info
|
||||
solana-epoch-info
|
||||
Get information about the current epoch
|
||||
|
||||
USAGE:
|
||||
@ -937,7 +936,7 @@ OPTIONS:
|
||||
|
||||
#### solana-fees
|
||||
```text
|
||||
solana-fees
|
||||
solana-fees
|
||||
Display current cluster fees
|
||||
|
||||
USAGE:
|
||||
@ -961,7 +960,7 @@ OPTIONS:
|
||||
|
||||
#### solana-genesis-hash
|
||||
```text
|
||||
solana-genesis-hash
|
||||
solana-genesis-hash
|
||||
Get the genesis hash
|
||||
|
||||
USAGE:
|
||||
@ -985,7 +984,7 @@ OPTIONS:
|
||||
|
||||
#### solana-gossip
|
||||
```text
|
||||
solana-gossip
|
||||
solana-gossip
|
||||
Show the current gossip network nodes
|
||||
|
||||
USAGE:
|
||||
@ -1009,7 +1008,7 @@ OPTIONS:
|
||||
|
||||
#### solana-help
|
||||
```text
|
||||
solana-help
|
||||
solana-help
|
||||
Prints this message or the help of the given subcommand(s)
|
||||
|
||||
USAGE:
|
||||
@ -1021,7 +1020,7 @@ ARGS:
|
||||
|
||||
#### solana-new-nonce
|
||||
```text
|
||||
solana-new-nonce
|
||||
solana-new-nonce
|
||||
Generate a new nonce, rendering the existing nonce useless
|
||||
|
||||
USAGE:
|
||||
@ -1053,7 +1052,7 @@ ARGS:
|
||||
|
||||
#### solana-nonce
|
||||
```text
|
||||
solana-nonce
|
||||
solana-nonce
|
||||
Get the current nonce value
|
||||
|
||||
USAGE:
|
||||
@ -1080,7 +1079,7 @@ ARGS:
|
||||
|
||||
#### solana-nonce-account
|
||||
```text
|
||||
solana-nonce-account
|
||||
solana-nonce-account
|
||||
Show the contents of a nonce account
|
||||
|
||||
USAGE:
|
||||
@ -1108,14 +1107,14 @@ ARGS:
|
||||
|
||||
#### solana-pay
|
||||
```text
|
||||
solana-pay
|
||||
solana-pay
|
||||
Send a payment
|
||||
|
||||
USAGE:
|
||||
solana pay [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT> [--] [UNIT]
|
||||
|
||||
FLAGS:
|
||||
--cancelable
|
||||
--cancelable
|
||||
-h, --help Prints help information
|
||||
--sign-only Sign the transaction offline
|
||||
--skip-seed-phrase-validation Skip validation of seed phrases. Use this if your phrase does not use the BIP39
|
||||
@ -1134,9 +1133,9 @@ OPTIONS:
|
||||
-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
|
||||
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 <KEYPAIR or PUBKEY>
|
||||
Provide the nonce authority keypair to use when signing a nonced transaction
|
||||
@ -1154,7 +1153,7 @@ ARGS:
|
||||
|
||||
#### solana-ping
|
||||
```text
|
||||
solana-ping
|
||||
solana-ping
|
||||
Submit transactions sequentially
|
||||
|
||||
USAGE:
|
||||
@ -1183,7 +1182,7 @@ OPTIONS:
|
||||
|
||||
#### solana-send-signature
|
||||
```text
|
||||
solana-send-signature
|
||||
solana-send-signature
|
||||
Send a signature to authorize a transfer
|
||||
|
||||
USAGE:
|
||||
@ -1211,7 +1210,7 @@ ARGS:
|
||||
|
||||
#### solana-send-timestamp
|
||||
```text
|
||||
solana-send-timestamp
|
||||
solana-send-timestamp
|
||||
Send a timestamp to unlock a transfer
|
||||
|
||||
USAGE:
|
||||
@ -1240,7 +1239,7 @@ ARGS:
|
||||
|
||||
#### solana-show-stake-account
|
||||
```text
|
||||
solana-show-stake-account
|
||||
solana-show-stake-account
|
||||
Show the contents of a stake account
|
||||
|
||||
USAGE:
|
||||
@ -1268,7 +1267,7 @@ ARGS:
|
||||
|
||||
#### solana-slot
|
||||
```text
|
||||
solana-slot
|
||||
solana-slot
|
||||
Get current slot
|
||||
|
||||
USAGE:
|
||||
@ -1293,7 +1292,7 @@ OPTIONS:
|
||||
|
||||
#### solana-stake-authorize-staker
|
||||
```text
|
||||
solana-stake-authorize-staker
|
||||
solana-stake-authorize-staker
|
||||
Authorize a new stake signing keypair for the given stake account
|
||||
|
||||
USAGE:
|
||||
@ -1318,9 +1317,9 @@ OPTIONS:
|
||||
-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
|
||||
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 <KEYPAIR or PUBKEY>
|
||||
Provide the nonce authority keypair to use when signing a nonced transaction
|
||||
@ -1335,7 +1334,7 @@ ARGS:
|
||||
|
||||
#### solana-stake-authorize-withdrawer
|
||||
```text
|
||||
solana-stake-authorize-withdrawer
|
||||
solana-stake-authorize-withdrawer
|
||||
Authorize a new withdraw signing keypair for the given stake account
|
||||
|
||||
USAGE:
|
||||
@ -1360,9 +1359,9 @@ OPTIONS:
|
||||
-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
|
||||
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 <KEYPAIR or PUBKEY>
|
||||
Provide the nonce authority keypair to use when signing a nonced transaction
|
||||
@ -1377,7 +1376,7 @@ ARGS:
|
||||
|
||||
#### solana-stake-history
|
||||
```text
|
||||
solana-stake-history
|
||||
solana-stake-history
|
||||
Show the stake history
|
||||
|
||||
USAGE:
|
||||
@ -1402,7 +1401,7 @@ OPTIONS:
|
||||
|
||||
#### solana-stakes
|
||||
```text
|
||||
solana-stakes
|
||||
solana-stakes
|
||||
Show stake account information
|
||||
|
||||
USAGE:
|
||||
@ -1430,7 +1429,7 @@ ARGS:
|
||||
|
||||
#### solana-storage-account
|
||||
```text
|
||||
solana-storage-account
|
||||
solana-storage-account
|
||||
Show the contents of a storage account
|
||||
|
||||
USAGE:
|
||||
@ -1457,7 +1456,7 @@ ARGS:
|
||||
|
||||
#### solana-transaction-count
|
||||
```text
|
||||
solana-transaction-count
|
||||
solana-transaction-count
|
||||
Get current transaction count
|
||||
|
||||
USAGE:
|
||||
@ -1480,38 +1479,9 @@ OPTIONS:
|
||||
-k, --keypair <PATH> /path/to/id.json
|
||||
```
|
||||
|
||||
#### solana-uptime
|
||||
```text
|
||||
solana-uptime
|
||||
Show the uptime of a validator, based on epoch voting history
|
||||
|
||||
USAGE:
|
||||
solana uptime [FLAGS] [OPTIONS] <VOTE ACCOUNT PUBKEY>
|
||||
|
||||
FLAGS:
|
||||
--aggregate Aggregate uptime data across span
|
||||
-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> 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
|
||||
--span <NUM OF EPOCHS> Number of recent epochs to examine
|
||||
|
||||
ARGS:
|
||||
<VOTE ACCOUNT PUBKEY> Vote account pubkey
|
||||
```
|
||||
|
||||
#### solana-validator-info
|
||||
```text
|
||||
solana-validator-info
|
||||
solana-validator-info
|
||||
Publish/get Validator info on Solana
|
||||
|
||||
USAGE:
|
||||
@ -1540,7 +1510,7 @@ SUBCOMMANDS:
|
||||
|
||||
#### solana-validators
|
||||
```text
|
||||
solana-validators
|
||||
solana-validators
|
||||
Show summary information about the current validators
|
||||
|
||||
USAGE:
|
||||
@ -1565,7 +1535,7 @@ OPTIONS:
|
||||
|
||||
#### solana-vote-account
|
||||
```text
|
||||
solana-vote-account
|
||||
solana-vote-account
|
||||
Show the contents of a vote account
|
||||
|
||||
USAGE:
|
||||
@ -1593,7 +1563,7 @@ ARGS:
|
||||
|
||||
#### solana-vote-authorize-voter
|
||||
```text
|
||||
solana-vote-authorize-voter
|
||||
solana-vote-authorize-voter
|
||||
Authorize a new vote signing keypair for the given vote account
|
||||
|
||||
USAGE:
|
||||
@ -1621,7 +1591,7 @@ ARGS:
|
||||
|
||||
#### solana-vote-authorize-withdrawer
|
||||
```text
|
||||
solana-vote-authorize-withdrawer
|
||||
solana-vote-authorize-withdrawer
|
||||
Authorize a new withdraw signing keypair for the given vote account
|
||||
|
||||
USAGE:
|
||||
@ -1649,7 +1619,7 @@ ARGS:
|
||||
|
||||
#### solana-vote-update-validator
|
||||
```text
|
||||
solana-vote-update-validator
|
||||
solana-vote-update-validator
|
||||
Update the vote account's validator identity
|
||||
|
||||
USAGE:
|
||||
@ -1678,7 +1648,7 @@ ARGS:
|
||||
|
||||
#### solana-withdraw-from-nonce-account
|
||||
```text
|
||||
solana-withdraw-from-nonce-account
|
||||
solana-withdraw-from-nonce-account
|
||||
Withdraw lamports from the nonce account
|
||||
|
||||
USAGE:
|
||||
@ -1713,7 +1683,7 @@ ARGS:
|
||||
|
||||
#### solana-withdraw-stake
|
||||
```text
|
||||
solana-withdraw-stake
|
||||
solana-withdraw-stake
|
||||
Withdraw the unstaked lamports from the stake account
|
||||
|
||||
USAGE:
|
||||
|
@ -94,12 +94,13 @@ The Stakes and the RewardsPool are accounts that are owned by the same `Stake` p
|
||||
|
||||
### StakeInstruction::DelegateStake
|
||||
|
||||
The Stake account is moved from Ininitialized to StakeState::Stake form. This is how stakers choose their initial delegate validator node and activate their stake account lamports. The transaction must be signed by the stake's `authorized_staker`. If the stake account is already StakeState::Stake \(i.e. already activated\), the stake is re-delegated. Stakes may be re-delegated at any time, and updated stakes are reflected immediately, but only one re-delegation is permitted per epoch.
|
||||
The Stake account is moved from Initialized to StakeState::Stake form, or from a deactivated (i.e. fully cooled-down) StakeState::Stake to activated StakeState::Stake. This is how stakers choose the vote account and validator node to which their stake account lamports are delegated. The transaction must be signed by the stake's `authorized_staker`.
|
||||
|
||||
* `account[0]` - RW - The StakeState::Stake instance. `StakeState::Stake::credits_observed` is initialized to `VoteState::credits`, `StakeState::Stake::voter_pubkey` is initialized to `account[1]`. If this is the initial delegation of stake, `StakeState::Stake::stake` is initialized to the account's balance in lamports, `StakeState::Stake::activated` is initialized to the current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX
|
||||
* `account[1]` - R - The VoteState instance.
|
||||
* `account[2]` - R - sysvar::clock account, carries information about current Bank epoch
|
||||
* `account[3]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration
|
||||
* `account[3]` - R - sysvar::stakehistory account, carries information about stake history
|
||||
* `account[4]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration
|
||||
|
||||
### StakeInstruction::Authorize\(Pubkey, StakeAuthorize\)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
Follow this guide to setup Solana's key generation tool called `solana-keygen`
|
||||
|
||||
{% hint style="warn" %}
|
||||
After installation, ensure your version is `0.21.1` or higher by running `solana-keygen -V`
|
||||
After installation, ensure your version is `0.23.1` or higher by running `solana-keygen -V`
|
||||
{% endhint %}
|
||||
|
||||
## Download
|
||||
|
@ -1,14 +1,14 @@
|
||||
# Installing the Validator Software
|
||||
|
||||
Install the Solana release
|
||||
[v0.21.0](https://github.com/solana-labs/solana/releases/tag/v0.21.0) on your
|
||||
[v0.23.1](https://github.com/solana-labs/solana/releases/tag/v0.23.1) on your
|
||||
machine by running:
|
||||
|
||||
```bash
|
||||
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.21.0/install/solana-install-init.sh | sh -s - 0.21.0
|
||||
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.23.1/install/solana-install-init.sh | sh -s - 0.23.1
|
||||
```
|
||||
|
||||
If you are connecting to a different testnet, you can replace `0.21.0` with the
|
||||
If you are connecting to a different testnet, you can replace `0.23.1` with the
|
||||
release tag matching the software version of your desired testnet, or replace it
|
||||
with the named channel `stable`, `beta`, or `edge`.
|
||||
|
||||
@ -16,11 +16,11 @@ The following output indicates a successful update:
|
||||
|
||||
```text
|
||||
looking for latest release
|
||||
downloading v0.21.0 installer
|
||||
downloading v0.23.1 installer
|
||||
Configuration: /home/solana/.config/solana/install/config.yml
|
||||
Active release directory: /home/solana/.local/share/solana/install/active_release
|
||||
* Release version: 0.21.0
|
||||
* Release URL: https://github.com/solana-labs/solana/releases/download/v0.21.0/solana-release-x86_64-unknown-linux-gnu.tar.bz2
|
||||
* Release version: 0.23.1
|
||||
* Release URL: https://github.com/solana-labs/solana/releases/download/v0.23.1/solana-release-x86_64-unknown-linux-gnu.tar.bz2
|
||||
Update successful
|
||||
```
|
||||
|
||||
|
@ -83,7 +83,6 @@ To monitor your validator during its warmup period:
|
||||
|
||||
* View your vote account:`solana vote-account ~/validator-vote-keypair.json` This displays the current state of all the votes the validator has submitted to the network.
|
||||
* View your stake account, the delegation preference and details of your stake:`solana 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 validators` displays the current active stake of all validators, including yours
|
||||
* `solana 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 ####`
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-chacha-cuda"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Chacha Cuda APIs"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -10,12 +10,12 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.8"
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.0" }
|
||||
solana-chacha = { path = "../chacha", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.2" }
|
||||
solana-chacha = { path = "../chacha", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-chacha-sys"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana chacha-sys"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-chacha"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Chacha APIs"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -12,11 +12,11 @@ edition = "2018"
|
||||
log = "0.4.8"
|
||||
rand = "0.6.5"
|
||||
rand_chacha = "0.1.1"
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2.1"
|
||||
|
@ -378,7 +378,7 @@ deploy() {
|
||||
(
|
||||
set -x
|
||||
ci/testnet-deploy.sh -p testnet-solana-com -C gce -z us-west1-b \
|
||||
-t "$CHANNEL_OR_TAG" -n 1 -c 0 -u -P \
|
||||
-t "$CHANNEL_OR_TAG" -n 0 -c 0 -u -P \
|
||||
-a testnet-solana-com --letsencrypt testnet.solana.com \
|
||||
--limit-ledger-size \
|
||||
${skipCreate:+-e} \
|
||||
@ -389,7 +389,7 @@ deploy() {
|
||||
(
|
||||
echo "--- net.sh update"
|
||||
set -x
|
||||
time net/net.sh update -t "$CHANNEL_OR_TAG" --platform linux --platform osx --platform windows
|
||||
time net/net.sh update -t "$CHANNEL_OR_TAG" --platform linux --platform osx #--platform windows
|
||||
)
|
||||
;;
|
||||
testnet-perf)
|
||||
@ -455,6 +455,10 @@ deploy() {
|
||||
TDS_CLIENT_COUNT="1"
|
||||
fi
|
||||
|
||||
if [[ -n $TDS_SLOTS_PER_EPOCH ]]; then
|
||||
maybeSlotsPerEpoch=(--slots-per-epoch "$TDS_SLOTS_PER_EPOCH")
|
||||
fi
|
||||
|
||||
if [[ -z $ENABLE_GPU ]]; then
|
||||
maybeGpu=(-G "--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100")
|
||||
elif [[ $ENABLE_GPU == skip ]]; then
|
||||
@ -540,7 +544,7 @@ deploy() {
|
||||
${maybeInternalNodesLamports} \
|
||||
${maybeExternalAccountsFile} \
|
||||
--target-lamports-per-signature 0 \
|
||||
--slots-per-epoch 4096 \
|
||||
"${maybeSlotsPerEpoch[@]}" \
|
||||
${maybeAdditionalDisk}
|
||||
)
|
||||
;;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.0"
|
||||
chrono = "0.4"
|
||||
|
16
cli-config/Cargo.toml
Normal file
16
cli-config/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.2"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
||||
[dependencies]
|
||||
dirs = "2.0.2"
|
||||
lazy_static = "1.4.0"
|
||||
serde = "1.0.104"
|
||||
serde_derive = "1.0.103"
|
||||
serde_yaml = "0.8.11"
|
@ -1,8 +1,10 @@
|
||||
// Wallet settings that can be configured for long-term use
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use std::{
|
||||
fs::{create_dir_all, File},
|
||||
io::{self, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CONFIG_FILE: Option<String> = {
|
4
cli-config/src/lib.rs
Normal file
4
cli-config/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod config;
|
@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@ -17,7 +17,6 @@ criterion-stats = "0.3.0"
|
||||
ctrlc = { version = "3.1.3", features = ["termination"] }
|
||||
console = "0.9.1"
|
||||
dirs = "2.0.2"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.8"
|
||||
indicatif = "0.13.0"
|
||||
humantime = "2.0.0"
|
||||
@ -28,24 +27,25 @@ 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.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.0" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-cli-config = { path = "../cli-config", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.2" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "0.23.2" }
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
175
cli/src/cli.rs
175
cli/src/cli.rs
@ -86,21 +86,26 @@ impl SigningAuthority {
|
||||
matches: &ArgMatches<'_>,
|
||||
name: &str,
|
||||
signers: Option<&[(Pubkey, Signature)]>,
|
||||
) -> Result<Self, CliError> {
|
||||
keypair_of(matches, name)
|
||||
.map(|keypair| keypair.into())
|
||||
.or_else(|| {
|
||||
pubkey_of(matches, name)
|
||||
.filter(|pubkey| {
|
||||
signers
|
||||
.and_then(|signers| {
|
||||
signers.iter().find(|(signer, _sig)| *signer == *pubkey)
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.map(|pubkey| pubkey.into())
|
||||
})
|
||||
.ok_or_else(|| CliError::BadParameter("Invalid authority".to_string()))
|
||||
) -> Result<Option<Self>, CliError> {
|
||||
if matches.is_present(name) {
|
||||
keypair_of(matches, name)
|
||||
.map(|keypair| keypair.into())
|
||||
.or_else(|| {
|
||||
pubkey_of(matches, name)
|
||||
.filter(|pubkey| {
|
||||
signers
|
||||
.and_then(|signers| {
|
||||
signers.iter().find(|(signer, _sig)| *signer == *pubkey)
|
||||
})
|
||||
.is_some()
|
||||
})
|
||||
.map(|pubkey| pubkey.into())
|
||||
})
|
||||
.ok_or_else(|| CliError::BadParameter("Invalid authority".to_string()))
|
||||
.map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keypair(&self) -> &Keypair {
|
||||
@ -161,7 +166,7 @@ pub struct PayCommand {
|
||||
pub cancelable: bool,
|
||||
pub sign_only: bool,
|
||||
pub signers: Option<Vec<(Pubkey, Signature)>>,
|
||||
pub blockhash: Option<Hash>,
|
||||
pub blockhash_query: BlockhashQuery,
|
||||
pub nonce_account: Option<Pubkey>,
|
||||
pub nonce_authority: Option<SigningAuthority>,
|
||||
}
|
||||
@ -193,6 +198,7 @@ pub enum CliCommand {
|
||||
GetTransactionCount {
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
LeaderSchedule,
|
||||
Ping {
|
||||
lamports: u64,
|
||||
interval: Duration,
|
||||
@ -255,7 +261,7 @@ pub enum CliCommand {
|
||||
stake_authority: Option<SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<SigningAuthority>,
|
||||
},
|
||||
@ -266,10 +272,22 @@ pub enum CliCommand {
|
||||
force: bool,
|
||||
sign_only: bool,
|
||||
signers: Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<SigningAuthority>,
|
||||
},
|
||||
SplitStake {
|
||||
stake_account_pubkey: Pubkey,
|
||||
stake_authority: Option<SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash_query: BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<SigningAuthority>,
|
||||
split_stake_account: KeypairEq,
|
||||
seed: Option<String>,
|
||||
lamports: u64,
|
||||
},
|
||||
ShowStakeHistory {
|
||||
use_lamports_unit: bool,
|
||||
},
|
||||
@ -284,7 +302,7 @@ pub enum CliCommand {
|
||||
authority: Option<SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<SigningAuthority>,
|
||||
},
|
||||
@ -325,11 +343,6 @@ pub enum CliCommand {
|
||||
pubkey: Pubkey,
|
||||
use_lamports_unit: bool,
|
||||
},
|
||||
Uptime {
|
||||
pubkey: Pubkey,
|
||||
aggregate: bool,
|
||||
span: Option<u64>,
|
||||
},
|
||||
VoteAuthorize {
|
||||
vote_account_pubkey: Pubkey,
|
||||
new_authorized_pubkey: Pubkey,
|
||||
@ -456,6 +469,10 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
||||
}),
|
||||
("slot", Some(matches)) => parse_get_slot(matches),
|
||||
("transaction-count", Some(matches)) => parse_get_transaction_count(matches),
|
||||
("leader-schedule", Some(_matches)) => Ok(CliCommandInfo {
|
||||
command: CliCommand::LeaderSchedule,
|
||||
require_keypair: false,
|
||||
}),
|
||||
("ping", Some(matches)) => parse_cluster_ping(matches),
|
||||
("block-production", Some(matches)) => parse_show_block_production(matches),
|
||||
("gossip", Some(_matches)) => Ok(CliCommandInfo {
|
||||
@ -483,6 +500,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
||||
("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches),
|
||||
("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches),
|
||||
("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches),
|
||||
("split-stake", Some(matches)) => parse_split_stake(matches),
|
||||
("stake-authorize-staker", Some(matches)) => {
|
||||
parse_stake_authorize(matches, StakeAuthorize::Staker)
|
||||
}
|
||||
@ -516,7 +534,6 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
||||
parse_vote_authorize(matches, VoteAuthorize::Withdrawer)
|
||||
}
|
||||
("vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
||||
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
||||
// Wallet Commands
|
||||
("address", Some(_matches)) => Ok(CliCommandInfo {
|
||||
command: CliCommand::Address,
|
||||
@ -602,17 +619,13 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
||||
let cancelable = matches.is_present("cancelable");
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
|
||||
let blockhash = value_of(&matches, BLOCKHASH_ARG.name);
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(&matches);
|
||||
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
|
||||
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority = SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
@ -624,7 +637,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
||||
cancelable,
|
||||
sign_only,
|
||||
signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
}),
|
||||
@ -1003,7 +1016,7 @@ fn process_pay(
|
||||
cancelable: bool,
|
||||
sign_only: bool,
|
||||
signers: &Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<&SigningAuthority>,
|
||||
) -> ProcessResult {
|
||||
@ -1012,8 +1025,7 @@ fn process_pay(
|
||||
(to, "to".to_string()),
|
||||
)?;
|
||||
|
||||
let (blockhash, fee_calculator) =
|
||||
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
|
||||
let (blockhash, fee_calculator) = blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
|
||||
|
||||
let cancelable = if cancelable {
|
||||
Some(config.keypair.pubkey())
|
||||
@ -1261,6 +1273,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
CliCommand::GetTransactionCount { commitment_config } => {
|
||||
process_get_transaction_count(&rpc_client, commitment_config)
|
||||
}
|
||||
CliCommand::LeaderSchedule => process_leader_schedule(&rpc_client),
|
||||
CliCommand::Ping {
|
||||
lamports,
|
||||
interval,
|
||||
@ -1376,13 +1389,12 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
lockup,
|
||||
*lamports,
|
||||
),
|
||||
// Deactivate stake account
|
||||
CliCommand::DeactivateStake {
|
||||
stake_account_pubkey,
|
||||
ref stake_authority,
|
||||
sign_only,
|
||||
ref signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
ref nonce_authority,
|
||||
} => process_deactivate_stake_account(
|
||||
@ -1392,7 +1404,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
stake_authority.as_ref(),
|
||||
*sign_only,
|
||||
signers,
|
||||
*blockhash,
|
||||
blockhash_query,
|
||||
*nonce_account,
|
||||
nonce_authority.as_ref(),
|
||||
),
|
||||
@ -1403,7 +1415,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
force,
|
||||
sign_only,
|
||||
ref signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
ref nonce_authority,
|
||||
} => process_delegate_stake(
|
||||
@ -1415,10 +1427,35 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
*force,
|
||||
*sign_only,
|
||||
signers,
|
||||
*blockhash,
|
||||
blockhash_query,
|
||||
*nonce_account,
|
||||
nonce_authority.as_ref(),
|
||||
),
|
||||
CliCommand::SplitStake {
|
||||
stake_account_pubkey,
|
||||
ref stake_authority,
|
||||
sign_only,
|
||||
ref signers,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
ref nonce_authority,
|
||||
split_stake_account,
|
||||
seed,
|
||||
lamports,
|
||||
} => process_split_stake(
|
||||
&rpc_client,
|
||||
config,
|
||||
&stake_account_pubkey,
|
||||
stake_authority.as_ref(),
|
||||
*sign_only,
|
||||
signers,
|
||||
blockhash_query,
|
||||
*nonce_account,
|
||||
nonce_authority.as_ref(),
|
||||
split_stake_account,
|
||||
seed,
|
||||
*lamports,
|
||||
),
|
||||
CliCommand::ShowStakeAccount {
|
||||
pubkey: stake_account_pubkey,
|
||||
use_lamports_unit,
|
||||
@ -1438,7 +1475,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
ref authority,
|
||||
sign_only,
|
||||
ref signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
ref nonce_authority,
|
||||
} => process_stake_authorize(
|
||||
@ -1450,7 +1487,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
authority.as_ref(),
|
||||
*sign_only,
|
||||
signers,
|
||||
*blockhash,
|
||||
blockhash_query,
|
||||
*nonce_account,
|
||||
nonce_authority.as_ref(),
|
||||
),
|
||||
@ -1566,11 +1603,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
&new_identity_pubkey,
|
||||
authorized_voter,
|
||||
),
|
||||
CliCommand::Uptime {
|
||||
pubkey: vote_account_pubkey,
|
||||
aggregate,
|
||||
span,
|
||||
} => process_uptime(&rpc_client, config, &vote_account_pubkey, *aggregate, *span),
|
||||
|
||||
// Wallet Commands
|
||||
|
||||
@ -1622,7 +1654,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
cancelable,
|
||||
sign_only,
|
||||
ref signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
ref nonce_authority,
|
||||
}) => process_pay(
|
||||
@ -1636,7 +1668,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
*cancelable,
|
||||
*sign_only,
|
||||
signers,
|
||||
*blockhash,
|
||||
blockhash_query,
|
||||
*nonce_account,
|
||||
nonce_authority.as_ref(),
|
||||
),
|
||||
@ -2380,7 +2412,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
sign_only: true,
|
||||
..PayCommand::default()
|
||||
}),
|
||||
@ -2409,7 +2441,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
signers: Some(vec![(key1, sig1)]),
|
||||
..PayCommand::default()
|
||||
}),
|
||||
@ -2440,7 +2472,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
signers: Some(vec![(key1, sig1), (key2, sig2)]),
|
||||
..PayCommand::default()
|
||||
}),
|
||||
@ -2464,7 +2496,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
..PayCommand::default()
|
||||
}),
|
||||
require_keypair: true
|
||||
@ -2491,7 +2523,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(pubkey),
|
||||
..PayCommand::default()
|
||||
}),
|
||||
@ -2522,7 +2554,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(pubkey),
|
||||
nonce_authority: Some(keypair.into()),
|
||||
..PayCommand::default()
|
||||
@ -2558,7 +2590,7 @@ mod tests {
|
||||
command: CliCommand::Pay(PayCommand {
|
||||
lamports: 50,
|
||||
to: pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(pubkey),
|
||||
nonce_authority: Some(authority_pubkey.into()),
|
||||
signers: Some(vec![(authority_pubkey, sig)]),
|
||||
@ -2762,13 +2794,30 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
let signature = process_command(&config);
|
||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||
|
||||
let stake_pubkey = Pubkey::new_rand();
|
||||
let split_stake_account = Keypair::new();
|
||||
config.command = CliCommand::SplitStake {
|
||||
stake_account_pubkey: stake_pubkey,
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
split_stake_account: split_stake_account.into(),
|
||||
seed: None,
|
||||
lamports: 1234,
|
||||
};
|
||||
let signature = process_command(&config);
|
||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||
|
||||
config.command = CliCommand::GetSlot {
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
};
|
||||
@ -2848,7 +2897,7 @@ mod tests {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
nonce_account: Some(bob_pubkey),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let signature = process_command(&config);
|
||||
@ -2875,7 +2924,7 @@ mod tests {
|
||||
config.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(bob_pubkey),
|
||||
nonce_authority: Some(bob_keypair.into()),
|
||||
..PayCommand::default()
|
||||
|
@ -14,7 +14,7 @@ use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
clock::{self, Slot},
|
||||
commitment_config::CommitmentConfig,
|
||||
epoch_schedule::{Epoch, EpochSchedule},
|
||||
epoch_schedule::Epoch,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, KeypairUtil},
|
||||
@ -67,6 +67,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||
.help("Slot number of the block to query")
|
||||
)
|
||||
)
|
||||
.subcommand(SubCommand::with_name("leader-schedule").about("Display leader schedule"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("epoch-info")
|
||||
.about("Get information about the current epoch")
|
||||
@ -320,20 +321,6 @@ fn new_spinner_progress_bar() -> ProgressBar {
|
||||
progress_bar
|
||||
}
|
||||
|
||||
/// Aggregate epoch credit stats and return (total credits, total slots, total epochs)
|
||||
pub fn aggregate_epoch_credits(
|
||||
epoch_credits: &[(Epoch, u64, u64)],
|
||||
epoch_schedule: &EpochSchedule,
|
||||
) -> (u64, u64, u64) {
|
||||
epoch_credits
|
||||
.iter()
|
||||
.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
|
||||
let credits_earned = credits - prev_credits;
|
||||
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
|
||||
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult {
|
||||
let cluster_nodes = rpc_client.get_cluster_nodes()?;
|
||||
|
||||
@ -406,6 +393,41 @@ pub fn process_fees(rpc_client: &RpcClient) -> ProcessResult {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
|
||||
let epoch_info = rpc_client.get_epoch_info()?;
|
||||
let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index;
|
||||
|
||||
let leader_schedule = rpc_client.get_leader_schedule(Some(first_slot_in_epoch))?;
|
||||
if leader_schedule.is_none() {
|
||||
return Err(format!(
|
||||
"Unable to fetch leader schedule for slot {}",
|
||||
first_slot_in_epoch
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let leader_schedule = leader_schedule.unwrap();
|
||||
|
||||
let mut leader_per_slot_index = Vec::new();
|
||||
for (pubkey, leader_slots) in leader_schedule.iter() {
|
||||
for slot_index in leader_slots.iter() {
|
||||
if *slot_index >= leader_per_slot_index.len() {
|
||||
leader_per_slot_index.resize(*slot_index + 1, "?");
|
||||
}
|
||||
leader_per_slot_index[*slot_index] = pubkey;
|
||||
}
|
||||
}
|
||||
|
||||
for (slot_index, leader) in leader_per_slot_index.iter().enumerate() {
|
||||
println!(
|
||||
" {:<15} {:<44}",
|
||||
first_slot_in_epoch + slot_index as u64,
|
||||
leader
|
||||
);
|
||||
}
|
||||
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
pub fn process_get_block_time(rpc_client: &RpcClient, slot: Slot) -> ProcessResult {
|
||||
let timestamp = rpc_client.get_block_time(slot)?;
|
||||
Ok(timestamp.to_string())
|
||||
@ -864,7 +886,7 @@ pub fn process_show_stakes(
|
||||
}
|
||||
|
||||
pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult {
|
||||
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
||||
let epoch_info = rpc_client.get_epoch_info()?;
|
||||
let vote_accounts = rpc_client.get_vote_accounts()?;
|
||||
let total_active_stake = vote_accounts
|
||||
.current
|
||||
@ -913,7 +935,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
"Commission",
|
||||
"Last Vote",
|
||||
"Root Block",
|
||||
"Uptime",
|
||||
"Credits",
|
||||
"Active Stake",
|
||||
))
|
||||
.bold()
|
||||
@ -921,7 +943,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
|
||||
fn print_vote_account(
|
||||
vote_account: RpcVoteAccountInfo,
|
||||
epoch_schedule: &EpochSchedule,
|
||||
current_epoch: Epoch,
|
||||
total_active_stake: f64,
|
||||
use_lamports_unit: bool,
|
||||
delinquent: bool,
|
||||
@ -934,17 +956,6 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
}
|
||||
}
|
||||
|
||||
fn uptime(epoch_credits: Vec<(Epoch, u64, u64)>, epoch_schedule: &EpochSchedule) -> String {
|
||||
let (total_credits, total_slots, _) =
|
||||
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
|
||||
if total_slots > 0 {
|
||||
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
|
||||
format!("{:.2}%", total_uptime)
|
||||
} else {
|
||||
"-".into()
|
||||
}
|
||||
}
|
||||
|
||||
println!(
|
||||
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}",
|
||||
if delinquent {
|
||||
@ -957,7 +968,15 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
vote_account.commission,
|
||||
non_zero_or_dash(vote_account.last_vote),
|
||||
non_zero_or_dash(vote_account.root_slot),
|
||||
uptime(vote_account.epoch_credits, epoch_schedule),
|
||||
vote_account
|
||||
.epoch_credits
|
||||
.iter()
|
||||
.find_map(|(epoch, credits, _)| if *epoch == current_epoch {
|
||||
Some(*credits)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.unwrap_or(0),
|
||||
if vote_account.activated_stake > 0 {
|
||||
format!(
|
||||
"{} ({:.2}%)",
|
||||
@ -973,7 +992,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
for vote_account in vote_accounts.current.into_iter() {
|
||||
print_vote_account(
|
||||
vote_account,
|
||||
&epoch_schedule,
|
||||
epoch_info.epoch,
|
||||
total_active_stake,
|
||||
use_lamports_unit,
|
||||
false,
|
||||
@ -982,7 +1001,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
for vote_account in vote_accounts.delinquent.into_iter() {
|
||||
print_vote_account(
|
||||
vote_account,
|
||||
&epoch_schedule,
|
||||
epoch_info.epoch,
|
||||
total_active_stake,
|
||||
use_lamports_unit,
|
||||
true,
|
||||
|
@ -1,9 +1,5 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
pub mod cli;
|
||||
pub mod cluster_query;
|
||||
pub mod config;
|
||||
pub mod display;
|
||||
pub mod nonce;
|
||||
pub mod offline;
|
||||
|
@ -10,9 +10,9 @@ use solana_clap_utils::{
|
||||
};
|
||||
use solana_cli::{
|
||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
|
||||
config::{self, Config},
|
||||
display::{println_name_value, println_name_value_or},
|
||||
};
|
||||
use solana_cli_config::config::{Config, CONFIG_FILE};
|
||||
use solana_sdk::signature::read_keypair_file;
|
||||
|
||||
use std::error;
|
||||
@ -162,7 +162,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.help("Configuration file to use");
|
||||
if let Some(ref config_file) = *config::CONFIG_FILE {
|
||||
if let Some(ref config_file) = *CONFIG_FILE {
|
||||
arg.default_value(&config_file)
|
||||
} else {
|
||||
arg
|
||||
|
@ -234,15 +234,8 @@ impl NonceSubCommands for App<'_, '_> {
|
||||
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 = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
None,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::AuthorizeNonceAccount {
|
||||
@ -282,15 +275,8 @@ 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 = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
None,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::NewNonce {
|
||||
@ -320,15 +306,8 @@ 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 = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
None,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::WithdrawFromNonceAccount {
|
||||
|
@ -1,8 +1,13 @@
|
||||
use clap::{App, Arg};
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use serde_json::Value;
|
||||
use solana_clap_utils::{
|
||||
input_parsers::value_of,
|
||||
input_validators::{is_hash, is_pubkey_sig},
|
||||
ArgConstant,
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
|
||||
name: "blockhash",
|
||||
@ -22,6 +27,53 @@ pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
|
||||
help: "Provid a public-key/signature pair for the transaction",
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BlockhashQuery {
|
||||
None(Hash, FeeCalculator),
|
||||
FeeCalculator(Hash),
|
||||
All,
|
||||
}
|
||||
|
||||
impl BlockhashQuery {
|
||||
pub fn new(blockhash: Option<Hash>, sign_only: bool) -> Self {
|
||||
match blockhash {
|
||||
Some(hash) if sign_only => Self::None(hash, FeeCalculator::default()),
|
||||
Some(hash) if !sign_only => Self::FeeCalculator(hash),
|
||||
None if !sign_only => Self::All,
|
||||
_ => panic!("Cannot resolve blockhash"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
|
||||
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
BlockhashQuery::new(blockhash, sign_only)
|
||||
}
|
||||
|
||||
pub fn get_blockhash_fee_calculator(
|
||||
&self,
|
||||
rpc_client: &RpcClient,
|
||||
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
|
||||
let (hash, fee_calc) = match self {
|
||||
BlockhashQuery::None(hash, fee_calc) => (Some(hash), Some(fee_calc)),
|
||||
BlockhashQuery::FeeCalculator(hash) => (Some(hash), None),
|
||||
BlockhashQuery::All => (None, None),
|
||||
};
|
||||
if None == fee_calc {
|
||||
let (cluster_hash, fee_calc) = rpc_client.get_recent_blockhash()?;
|
||||
Ok((*hash.unwrap_or(&cluster_hash), fee_calc))
|
||||
} else {
|
||||
Ok((*hash.unwrap(), fee_calc.unwrap().clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BlockhashQuery {
|
||||
fn default() -> Self {
|
||||
BlockhashQuery::All
|
||||
}
|
||||
}
|
||||
|
||||
fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
Arg::with_name(BLOCKHASH_ARG.name)
|
||||
.long(BLOCKHASH_ARG.long)
|
||||
@ -61,3 +113,159 @@ impl OfflineArgs for App<'_, '_> {
|
||||
.arg(signer_arg())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) {
|
||||
let object: Value = serde_json::from_str(&reply).unwrap();
|
||||
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
|
||||
let blockhash = blockhash_str.parse::<Hash>().unwrap();
|
||||
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
|
||||
let signers = signer_strings
|
||||
.iter()
|
||||
.map(|signer_string| {
|
||||
let mut signer = signer_string.as_str().unwrap().split('=');
|
||||
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
|
||||
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
|
||||
(key, sig)
|
||||
})
|
||||
.collect();
|
||||
(blockhash, signers)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::App;
|
||||
use serde_json::{self, json, Value};
|
||||
use solana_client::{
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcResponseContext},
|
||||
};
|
||||
use solana_sdk::{fee_calculator::FeeCalculator, hash::hash};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn test_blockhashspec_new_ok() {
|
||||
let blockhash = hash(&[1u8]);
|
||||
|
||||
assert_eq!(
|
||||
BlockhashQuery::new(Some(blockhash), true),
|
||||
BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
);
|
||||
assert_eq!(
|
||||
BlockhashQuery::new(Some(blockhash), false),
|
||||
BlockhashQuery::FeeCalculator(blockhash),
|
||||
);
|
||||
assert_eq!(BlockhashQuery::new(None, false), BlockhashQuery::All,);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_blockhashspec_new_fail() {
|
||||
BlockhashQuery::new(None, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blockhashspec_new_from_matches_ok() {
|
||||
let test_commands = App::new("blockhashspec_test").offline_args();
|
||||
let blockhash = hash(&[1u8]);
|
||||
let blockhash_string = blockhash.to_string();
|
||||
|
||||
let matches = test_commands.clone().get_matches_from(vec![
|
||||
"blockhashspec_test",
|
||||
"--blockhash",
|
||||
&blockhash_string,
|
||||
"--sign-only",
|
||||
]);
|
||||
assert_eq!(
|
||||
BlockhashQuery::new_from_matches(&matches),
|
||||
BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
);
|
||||
|
||||
let matches = test_commands.clone().get_matches_from(vec![
|
||||
"blockhashspec_test",
|
||||
"--blockhash",
|
||||
&blockhash_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
BlockhashQuery::new_from_matches(&matches),
|
||||
BlockhashQuery::FeeCalculator(blockhash),
|
||||
);
|
||||
|
||||
let matches = test_commands
|
||||
.clone()
|
||||
.get_matches_from(vec!["blockhashspec_test"]);
|
||||
assert_eq!(
|
||||
BlockhashQuery::new_from_matches(&matches),
|
||||
BlockhashQuery::All,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_blockhashspec_new_from_matches_fail() {
|
||||
let test_commands = App::new("blockhashspec_test")
|
||||
.arg(blockhash_arg())
|
||||
// We can really only hit this case unless the arg requirements
|
||||
// are broken, so unset the requires() to recreate that condition
|
||||
.arg(sign_only_arg().requires(""));
|
||||
|
||||
let matches = test_commands
|
||||
.clone()
|
||||
.get_matches_from(vec!["blockhashspec_test", "--sign-only"]);
|
||||
BlockhashQuery::new_from_matches(&matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_blockhashspec_get_blockhash_fee_calc() {
|
||||
let test_blockhash = hash(&[0u8]);
|
||||
let rpc_blockhash = hash(&[1u8]);
|
||||
let rpc_fee_calc = FeeCalculator::new(42, 42);
|
||||
let get_recent_blockhash_response = json!(Response {
|
||||
context: RpcResponseContext { slot: 1 },
|
||||
value: json!((
|
||||
Value::String(rpc_blockhash.to_string()),
|
||||
serde_json::to_value(rpc_fee_calc.clone()).unwrap()
|
||||
)),
|
||||
});
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response.clone(),
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
assert_eq!(
|
||||
BlockhashQuery::All
|
||||
.get_blockhash_fee_calculator(&rpc_client)
|
||||
.unwrap(),
|
||||
(rpc_blockhash, rpc_fee_calc.clone()),
|
||||
);
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response.clone(),
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
assert_eq!(
|
||||
BlockhashQuery::FeeCalculator(test_blockhash)
|
||||
.get_blockhash_fee_calculator(&rpc_client)
|
||||
.unwrap(),
|
||||
(test_blockhash, rpc_fee_calc.clone()),
|
||||
);
|
||||
let mut mocks = HashMap::new();
|
||||
mocks.insert(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
get_recent_blockhash_response.clone(),
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
|
||||
assert_eq!(
|
||||
BlockhashQuery::None(test_blockhash, FeeCalculator::default())
|
||||
.get_blockhash_fee_calculator(&rpc_client)
|
||||
.unwrap(),
|
||||
(test_blockhash, FeeCalculator::default()),
|
||||
);
|
||||
let rpc_client = RpcClient::new_mock("fails".to_string());
|
||||
assert!(BlockhashQuery::All
|
||||
.get_blockhash_fee_calculator(&rpc_client)
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
419
cli/src/stake.rs
419
cli/src/stake.rs
@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
get_blockhash_fee_calculator, log_instruction_custom_error, nonce_authority_arg,
|
||||
replace_signatures, required_lamports_from, return_signers, CliCommand, CliCommandInfo,
|
||||
CliConfig, CliError, ProcessResult, SigningAuthority,
|
||||
log_instruction_custom_error, nonce_authority_arg, replace_signatures,
|
||||
required_lamports_from, return_signers, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult, SigningAuthority,
|
||||
},
|
||||
nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
|
||||
offline::*,
|
||||
@ -15,7 +15,6 @@ use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::signature::{Keypair, Signature};
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::KeypairUtil,
|
||||
system_instruction::{create_address_with_seed, SystemError},
|
||||
@ -245,6 +244,55 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.arg(nonce_arg())
|
||||
.arg(nonce_authority_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("split-stake")
|
||||
.about("Split a stake account")
|
||||
.arg(
|
||||
Arg::with_name("stake_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("STAKE ACCOUNT")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("Stake account to be split")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("split_stake_account")
|
||||
.index(2)
|
||||
.value_name("SPLIT STAKE ACCOUNT")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_keypair_or_ask_keyword)
|
||||
.help("Keypair of the new stake account to split funds into")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("amount")
|
||||
.index(3)
|
||||
.value_name("AMOUNT")
|
||||
.takes_value(true)
|
||||
.validator(is_amount)
|
||||
.required(true)
|
||||
.help("The amount to move into the new stake account (default unit SOL)")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("unit")
|
||||
.index(4)
|
||||
.value_name("UNIT")
|
||||
.takes_value(true)
|
||||
.possible_values(&["SOL", "lamports"])
|
||||
.help("Specify unit to use for request")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("seed")
|
||||
.long("seed")
|
||||
.value_name("SEED STRING")
|
||||
.takes_value(true)
|
||||
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT STAKE ACCOUNT pubkey")
|
||||
)
|
||||
.arg(stake_authority_arg())
|
||||
.offline_args()
|
||||
.arg(nonce_arg())
|
||||
.arg(nonce_authority_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("withdraw-stake")
|
||||
.about("Withdraw the unstaked lamports from the stake account")
|
||||
@ -286,7 +334,7 @@ impl StakeSubCommands for App<'_, '_> {
|
||||
.arg(withdraw_authority_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-stake-account")
|
||||
SubCommand::with_name("stake-account")
|
||||
.about("Show the contents of a stake account")
|
||||
.alias("show-stake-account")
|
||||
.arg(
|
||||
@ -352,27 +400,13 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
|
||||
let force = matches.is_present("force");
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
|
||||
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||
let require_keypair = signers.is_none();
|
||||
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
|
||||
let stake_authority = if matches.is_present(STAKE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
STAKE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let stake_authority =
|
||||
SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::DelegateStake {
|
||||
@ -382,7 +416,7 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
|
||||
force,
|
||||
sign_only,
|
||||
signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
},
|
||||
@ -402,26 +436,12 @@ pub fn parse_stake_authorize(
|
||||
};
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
|
||||
let authority = if matches.is_present(authority_flag) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
authority_flag,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
||||
let authority =
|
||||
SigningAuthority::new_from_matches(&matches, authority_flag, signers.as_deref())?;
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
|
||||
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::StakeAuthorize {
|
||||
@ -431,7 +451,7 @@ pub fn parse_stake_authorize(
|
||||
authority,
|
||||
sign_only,
|
||||
signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
},
|
||||
@ -439,31 +459,50 @@ pub fn parse_stake_authorize(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_split_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||
let split_stake_account = keypair_of(matches, "split_stake_account").unwrap();
|
||||
let lamports = required_lamports_from(matches, "amount", "unit")?;
|
||||
let seed = matches.value_of("seed").map(|s| s.to_string());
|
||||
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||
let require_keypair = signers.is_none();
|
||||
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
|
||||
let stake_authority =
|
||||
SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::SplitStake {
|
||||
stake_account_pubkey,
|
||||
stake_authority,
|
||||
sign_only,
|
||||
signers,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
split_stake_account: split_stake_account.into(),
|
||||
seed,
|
||||
lamports,
|
||||
},
|
||||
require_keypair,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
|
||||
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||
let require_keypair = signers.is_none();
|
||||
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
|
||||
let stake_authority = if matches.is_present(STAKE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
STAKE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
NONCE_AUTHORITY_ARG.name,
|
||||
signers.as_deref(),
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let stake_authority =
|
||||
SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
let nonce_authority =
|
||||
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::DeactivateStake {
|
||||
@ -471,7 +510,7 @@ pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliComma
|
||||
stake_authority,
|
||||
sign_only,
|
||||
signers,
|
||||
blockhash,
|
||||
blockhash_query,
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
},
|
||||
@ -483,15 +522,8 @@ pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
|
||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
||||
let lamports = required_lamports_from(matches, "amount", "unit")?;
|
||||
let withdraw_authority = if matches.is_present(WITHDRAW_AUTHORITY_ARG.name) {
|
||||
Some(SigningAuthority::new_from_matches(
|
||||
&matches,
|
||||
WITHDRAW_AUTHORITY_ARG.name,
|
||||
None,
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let withdraw_authority =
|
||||
SigningAuthority::new_from_matches(&matches, WITHDRAW_AUTHORITY_ARG.name, None)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::WithdrawStake {
|
||||
@ -562,7 +594,7 @@ pub fn process_create_stake_account(
|
||||
|
||||
if lamports < minimum_balance {
|
||||
return Err(CliError::BadParameter(format!(
|
||||
"need atleast {} lamports for stake account to be rent exempt, provided lamports: {}",
|
||||
"need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
|
||||
minimum_balance, lamports
|
||||
))
|
||||
.into());
|
||||
@ -626,7 +658,7 @@ pub fn process_stake_authorize(
|
||||
authority: Option<&SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: &Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<&SigningAuthority>,
|
||||
) -> ProcessResult {
|
||||
@ -636,7 +668,7 @@ pub fn process_stake_authorize(
|
||||
)?;
|
||||
let authority = authority.map(|a| a.keypair()).unwrap_or(&config.keypair);
|
||||
let (recent_blockhash, fee_calculator) =
|
||||
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
|
||||
blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
|
||||
let ixs = vec![stake_instruction::authorize(
|
||||
stake_account_pubkey, // stake account to update
|
||||
&authority.pubkey(), // currently authorized
|
||||
@ -692,12 +724,12 @@ pub fn process_deactivate_stake_account(
|
||||
stake_authority: Option<&SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: &Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<&SigningAuthority>,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) =
|
||||
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
|
||||
blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
|
||||
let stake_authority = stake_authority
|
||||
.map(|a| a.keypair())
|
||||
.unwrap_or(&config.keypair);
|
||||
@ -782,10 +814,152 @@ pub fn process_withdraw_stake(
|
||||
log_instruction_custom_error::<StakeError>(result)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn process_split_stake(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
stake_account_pubkey: &Pubkey,
|
||||
stake_authority: Option<&SigningAuthority>,
|
||||
sign_only: bool,
|
||||
signers: &Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<&SigningAuthority>,
|
||||
split_stake_account: &Keypair,
|
||||
split_stake_account_seed: &Option<String>,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(
|
||||
&split_stake_account.pubkey(),
|
||||
"split_stake_account".to_string(),
|
||||
),
|
||||
)?;
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(&stake_account_pubkey, "stake_account".to_string()),
|
||||
)?;
|
||||
check_unique_pubkeys(
|
||||
(&stake_account_pubkey, "stake_account".to_string()),
|
||||
(
|
||||
&split_stake_account.pubkey(),
|
||||
"split_stake_account".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let stake_authority = stake_authority
|
||||
.map(|a| a.keypair())
|
||||
.unwrap_or(&config.keypair);
|
||||
|
||||
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
|
||||
create_address_with_seed(
|
||||
&split_stake_account.pubkey(),
|
||||
&seed,
|
||||
&solana_stake_program::id(),
|
||||
)?
|
||||
} else {
|
||||
split_stake_account.pubkey()
|
||||
};
|
||||
|
||||
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
|
||||
let err_msg = if stake_account.owner == solana_stake_program::id() {
|
||||
format!(
|
||||
"Stake account {} already exists",
|
||||
split_stake_account_address
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"Account {} already exists and is not a stake account",
|
||||
split_stake_account_address
|
||||
)
|
||||
};
|
||||
return Err(CliError::BadParameter(err_msg).into());
|
||||
}
|
||||
|
||||
let minimum_balance =
|
||||
rpc_client.get_minimum_balance_for_rent_exemption(std::mem::size_of::<StakeState>())?;
|
||||
|
||||
if lamports < minimum_balance {
|
||||
return Err(CliError::BadParameter(format!(
|
||||
"need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
|
||||
minimum_balance, lamports
|
||||
))
|
||||
.into());
|
||||
}
|
||||
|
||||
let (recent_blockhash, fee_calculator) =
|
||||
blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
|
||||
|
||||
let ixs = if let Some(seed) = split_stake_account_seed {
|
||||
stake_instruction::split_with_seed(
|
||||
&stake_account_pubkey,
|
||||
&stake_authority.pubkey(),
|
||||
lamports,
|
||||
&split_stake_account_address,
|
||||
&split_stake_account.pubkey(),
|
||||
seed,
|
||||
)
|
||||
} else {
|
||||
stake_instruction::split(
|
||||
&stake_account_pubkey,
|
||||
&stake_authority.pubkey(),
|
||||
lamports,
|
||||
&split_stake_account_address,
|
||||
)
|
||||
};
|
||||
|
||||
let (nonce_authority, nonce_authority_pubkey) = nonce_authority
|
||||
.map(|a| (a.keypair(), a.pubkey()))
|
||||
.unwrap_or((&config.keypair, config.keypair.pubkey()));
|
||||
|
||||
let mut tx = if let Some(nonce_account) = &nonce_account {
|
||||
Transaction::new_signed_with_nonce(
|
||||
ixs,
|
||||
Some(&config.keypair.pubkey()),
|
||||
&[
|
||||
&config.keypair,
|
||||
nonce_authority,
|
||||
stake_authority,
|
||||
split_stake_account,
|
||||
],
|
||||
nonce_account,
|
||||
&nonce_authority.pubkey(),
|
||||
recent_blockhash,
|
||||
)
|
||||
} else {
|
||||
Transaction::new_signed_with_payer(
|
||||
ixs,
|
||||
Some(&config.keypair.pubkey()),
|
||||
&[&config.keypair, stake_authority, split_stake_account],
|
||||
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_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],
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
|
||||
log_instruction_custom_error::<StakeError>(result)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_stake_state(stake_lamports: u64, stake_state: &StakeState, use_lamports_unit: bool) {
|
||||
fn show_authorized(authorized: &Authorized) {
|
||||
println!("authorized staker: {}", authorized.staker);
|
||||
println!("authorized withdrawer: {}", authorized.staker);
|
||||
println!("authorized withdrawer: {}", authorized.withdrawer);
|
||||
}
|
||||
fn show_lockup(lockup: &Lockup) {
|
||||
println!("lockup epoch: {}", lockup.epoch);
|
||||
@ -913,7 +1087,7 @@ pub fn process_delegate_stake(
|
||||
force: bool,
|
||||
sign_only: bool,
|
||||
signers: &Option<Vec<(Pubkey, Signature)>>,
|
||||
blockhash: Option<Hash>,
|
||||
blockhash_query: &BlockhashQuery,
|
||||
nonce_account: Option<Pubkey>,
|
||||
nonce_authority: Option<&SigningAuthority>,
|
||||
) -> ProcessResult {
|
||||
@ -966,7 +1140,7 @@ pub fn process_delegate_stake(
|
||||
}
|
||||
|
||||
let (recent_blockhash, fee_calculator) =
|
||||
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
|
||||
blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
|
||||
|
||||
let ixs = vec![stake_instruction::delegate_stake(
|
||||
stake_account_pubkey,
|
||||
@ -1018,7 +1192,11 @@ pub fn process_delegate_stake(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::{read_keypair_file, write_keypair};
|
||||
use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
signature::{read_keypair_file, write_keypair},
|
||||
};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
@ -1056,7 +1234,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1082,7 +1260,7 @@ mod tests {
|
||||
authority: Some(read_keypair_file(&authority_keypair_file).unwrap().into()),
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1111,7 +1289,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1142,7 +1320,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(keypair.pubkey(), sig)]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1175,7 +1353,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(keypair.pubkey(), sig), (keypair2.pubkey(), sig2),]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1201,7 +1379,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1236,7 +1414,7 @@ mod tests {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(nonce_account_pubkey),
|
||||
nonce_authority: Some(nonce_authority_keypair.into()),
|
||||
},
|
||||
@ -1356,7 +1534,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1389,7 +1567,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1415,7 +1593,7 @@ mod tests {
|
||||
force: true,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1444,7 +1622,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1471,7 +1649,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1503,7 +1681,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(key1, sig1)]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1537,7 +1715,7 @@ mod tests {
|
||||
force: false,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(key1, sig1), (key2, sig2)]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1611,7 +1789,7 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1639,7 +1817,7 @@ mod tests {
|
||||
),
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1665,7 +1843,7 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1689,7 +1867,7 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1718,7 +1896,7 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(key1, sig1)]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
@ -1749,12 +1927,47 @@ mod tests {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: Some(vec![(key1, sig1), (key2, sig2)]),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
},
|
||||
require_keypair: false
|
||||
}
|
||||
);
|
||||
|
||||
// Test SplitStake SubCommand
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let stake_account_keypair = Keypair::new();
|
||||
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let (split_stake_account_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let split_stake_account_keypair = Keypair::new();
|
||||
write_keypair(&split_stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let test_split_stake_account = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"split-stake",
|
||||
&keypair_file,
|
||||
&split_stake_account_keypair_file,
|
||||
"50",
|
||||
"lamports",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_split_stake_account).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::SplitStake {
|
||||
stake_account_pubkey: stake_account_keypair.pubkey(),
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
split_stake_account: split_stake_account_keypair.into(),
|
||||
seed: None,
|
||||
lamports: 50
|
||||
},
|
||||
require_keypair: true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
129
cli/src/vote.rs
129
cli/src/vote.rs
@ -1,10 +1,6 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult,
|
||||
},
|
||||
cluster_query::aggregate_epoch_credits,
|
||||
use crate::cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
@ -176,31 +172,6 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
.help("Display balance in lamports instead of SOL"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("uptime")
|
||||
.about("Show the uptime of a validator, based on epoch voting history")
|
||||
.arg(
|
||||
Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE ACCOUNT PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("Vote account pubkey"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("span")
|
||||
.long("span")
|
||||
.value_name("NUM OF EPOCHS")
|
||||
.takes_value(true)
|
||||
.help("Number of recent epochs to examine"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("aggregate")
|
||||
.long("aggregate")
|
||||
.help("Aggregate uptime data across span"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,24 +242,6 @@ pub fn parse_vote_get_account_command(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||
let aggregate = matches.is_present("aggregate");
|
||||
let span = if matches.is_present("span") {
|
||||
Some(value_t_or_exit!(matches, "span", u64))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Uptime {
|
||||
pubkey: vote_account_pubkey,
|
||||
aggregate,
|
||||
span,
|
||||
},
|
||||
require_keypair: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_create_vote_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
@ -517,60 +470,6 @@ pub fn process_show_vote_account(
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
pub fn process_uptime(
|
||||
rpc_client: &RpcClient,
|
||||
_config: &CliConfig,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
aggregate: bool,
|
||||
span: Option<u64>,
|
||||
) -> ProcessResult {
|
||||
let (_vote_account, vote_state) = get_vote_account(rpc_client, vote_account_pubkey)?;
|
||||
|
||||
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
||||
|
||||
println!("validator identity: {}", vote_state.node_pubkey);
|
||||
println!("authorized voter: {}", vote_state.authorized_voter);
|
||||
if !vote_state.votes.is_empty() {
|
||||
println!("uptime:");
|
||||
|
||||
let epoch_credits: Vec<(u64, u64, u64)> = if let Some(x) = span {
|
||||
vote_state
|
||||
.epoch_credits()
|
||||
.iter()
|
||||
.rev()
|
||||
.take(x as usize)
|
||||
.cloned()
|
||||
.collect()
|
||||
} else {
|
||||
vote_state.epoch_credits().iter().rev().cloned().collect()
|
||||
};
|
||||
|
||||
if aggregate {
|
||||
let (total_credits, total_slots, epochs) =
|
||||
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
|
||||
if total_slots > 0 {
|
||||
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
|
||||
println!("{:.2}% over {} epochs", total_uptime, epochs);
|
||||
} else {
|
||||
println!("Insufficient voting history available");
|
||||
}
|
||||
} else {
|
||||
for (epoch, credits, prev_credits) in epoch_credits {
|
||||
let credits_earned = credits - prev_credits;
|
||||
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
|
||||
let uptime = credits_earned as f64 / slots_in_epoch as f64;
|
||||
println!("- epoch: {} {:.2}% uptime", epoch, uptime * 100_f64,);
|
||||
}
|
||||
}
|
||||
if let Some(x) = span {
|
||||
if x > vote_state.epoch_credits().len() as u64 {
|
||||
println!("(span longer than available epochs)");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -741,27 +640,5 @@ mod tests {
|
||||
require_keypair: true
|
||||
}
|
||||
);
|
||||
|
||||
// Test Uptime Subcommand
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let matches = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"uptime",
|
||||
&pubkey.to_string(),
|
||||
"--span",
|
||||
"4",
|
||||
"--aggregate",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&matches).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Uptime {
|
||||
pubkey,
|
||||
aggregate: true,
|
||||
span: Some(4)
|
||||
},
|
||||
require_keypair: false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
use chrono::prelude::*;
|
||||
use serde_json::Value;
|
||||
use solana_cli::cli::{
|
||||
process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand,
|
||||
use solana_cli::{
|
||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
|
||||
offline::{parse_sign_only_reply_string, BlockhashQuery},
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
hash::Hash,
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature},
|
||||
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::str::FromStr;
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -289,9 +289,11 @@ fn test_offline_pay_tx() {
|
||||
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
sign_only: true,
|
||||
..PayCommand::default()
|
||||
});
|
||||
@ -301,24 +303,12 @@ fn test_offline_pay_tx() {
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
check_balance(0, &rpc_client, &bob_pubkey);
|
||||
|
||||
let object: Value = serde_json::from_str(&sig_response).unwrap();
|
||||
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
|
||||
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
|
||||
let signers: Vec<_> = signer_strings
|
||||
.iter()
|
||||
.map(|signer_string| {
|
||||
let mut signer = signer_string.as_str().unwrap().split('=');
|
||||
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
|
||||
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
|
||||
(key, sig)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sig_response);
|
||||
config_online.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
signers: Some(signers),
|
||||
blockhash: Some(blockhash_str.parse::<Hash>().unwrap()),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
..PayCommand::default()
|
||||
});
|
||||
process_command(&config_online).unwrap();
|
||||
@ -389,7 +379,7 @@ fn test_nonced_pay_tx() {
|
||||
config.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
blockhash: Some(nonce_hash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
..PayCommand::default()
|
||||
});
|
||||
|
@ -1,18 +1,19 @@
|
||||
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},
|
||||
offline::{parse_sign_only_reply_string, BlockhashQuery},
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
hash::Hash,
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature},
|
||||
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
|
||||
system_instruction::create_address_with_seed,
|
||||
};
|
||||
use solana_stake_program::stake_state::{Lockup, StakeAuthorize, StakeState};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::str::FromStr;
|
||||
use std::sync::mpsc::channel;
|
||||
|
||||
#[cfg(test)]
|
||||
@ -40,23 +41,6 @@ fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
});
|
||||
}
|
||||
|
||||
fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) {
|
||||
let object: Value = serde_json::from_str(&reply).unwrap();
|
||||
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
|
||||
let blockhash = blockhash_str.parse::<Hash>().unwrap();
|
||||
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
|
||||
let signers = signer_strings
|
||||
.iter()
|
||||
.map(|signer_string| {
|
||||
let mut signer = signer_string.as_str().unwrap().split('=');
|
||||
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
|
||||
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
|
||||
(key, sig)
|
||||
})
|
||||
.collect();
|
||||
(blockhash, signers)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seed_stake_delegation_and_deactivation() {
|
||||
solana_logger::setup();
|
||||
@ -132,7 +116,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
force: true,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -144,7 +128,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -220,7 +204,7 @@ fn test_stake_delegation_and_deactivation() {
|
||||
force: true,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -232,7 +216,7 @@ fn test_stake_delegation_and_deactivation() {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -305,6 +289,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
process_command(&config_validator).unwrap();
|
||||
|
||||
// Delegate stake offline
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_validator.command = CliCommand::DelegateStake {
|
||||
stake_account_pubkey: config_stake.keypair.pubkey(),
|
||||
vote_account_pubkey: config_vote.keypair.pubkey(),
|
||||
@ -312,7 +297,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
force: true,
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -327,19 +312,20 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
force: true,
|
||||
sign_only: false,
|
||||
signers: Some(signers),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// Deactivate stake offline
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_validator.command = CliCommand::DeactivateStake {
|
||||
stake_account_pubkey: config_stake.keypair.pubkey(),
|
||||
stake_authority: None,
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -352,7 +338,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: Some(signers),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -439,7 +425,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
||||
force: true,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(nonce_hash),
|
||||
blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -460,7 +446,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
||||
stake_authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: Some(nonce_hash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: Some(config_keypair.into()),
|
||||
};
|
||||
@ -514,7 +500,7 @@ fn test_stake_authorize() {
|
||||
authority: None,
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -539,7 +525,7 @@ fn test_stake_authorize() {
|
||||
authority: Some(read_keypair_file(&online_authority_file).unwrap().into()),
|
||||
sign_only: false,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::default(),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -557,6 +543,7 @@ fn test_stake_authorize() {
|
||||
let nonced_authority_pubkey = nonced_authority.pubkey();
|
||||
let (nonced_authority_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonced_authority, tmp_file.as_file_mut()).unwrap();
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config.command = CliCommand::StakeAuthorize {
|
||||
stake_account_pubkey,
|
||||
new_authorized_pubkey: nonced_authority_pubkey,
|
||||
@ -564,7 +551,7 @@ fn test_stake_authorize() {
|
||||
authority: Some(read_keypair_file(&offline_authority_file).unwrap().into()),
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: None,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -577,7 +564,7 @@ fn test_stake_authorize() {
|
||||
authority: Some(offline_authority_pubkey.into()),
|
||||
sign_only: false,
|
||||
signers: Some(signers),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -625,7 +612,7 @@ fn test_stake_authorize() {
|
||||
authority: Some(read_keypair_file(&nonced_authority_file).unwrap().into()),
|
||||
sign_only: true,
|
||||
signers: None,
|
||||
blockhash: Some(nonce_hash),
|
||||
blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
};
|
||||
@ -639,7 +626,7 @@ fn test_stake_authorize() {
|
||||
authority: Some(nonced_authority_pubkey.into()),
|
||||
sign_only: false,
|
||||
signers: Some(signers),
|
||||
blockhash: Some(blockhash),
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -19,11 +19,11 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
|
||||
serde = "1.0.104"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.44"
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
|
@ -177,7 +177,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetVoteAccounts parse failure: {}", err),
|
||||
format!("GetVoteAccounts parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -196,7 +196,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetClusterNodes parse failure: {}", err),
|
||||
format!("GetClusterNodes parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -215,7 +215,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetConfirmedBlock parse failure: {}", err),
|
||||
format!("GetConfirmedBlock parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -242,7 +242,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetConfirmedBlocks parse failure: {}", err),
|
||||
format!("GetConfirmedBlocks parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -293,7 +293,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetEpochInfo parse failure: {}", err),
|
||||
format!("GetEpochInfo parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -324,7 +324,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetLeaderSchedule failure: {}", err),
|
||||
format!("GetLeaderSchedule failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -343,7 +343,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetEpochSchedule parse failure: {}", err),
|
||||
format!("GetEpochSchedule parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -381,7 +381,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetVersion parse failure: {}", err),
|
||||
format!("GetVersion parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -400,7 +400,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("MinimumLedgerSlot parse failure: {}", err),
|
||||
format!("MinimumLedgerSlot parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -612,7 +612,7 @@ impl RpcClient {
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("AccountNotFound: pubkey={}: {}", pubkey, err),
|
||||
format!("AccountNotFound: pubkey={}: {:?}", pubkey, err),
|
||||
)
|
||||
})?
|
||||
}
|
||||
@ -698,7 +698,7 @@ impl RpcClient {
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("AccountNotFound: pubkey={}: {}", pubkey, err),
|
||||
format!("AccountNotFound: pubkey={}: {:?}", pubkey, err),
|
||||
)
|
||||
})?;
|
||||
|
||||
@ -749,7 +749,7 @@ impl RpcClient {
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GetTransactionCount parse failure: {}", err),
|
||||
format!("GetTransactionCount parse failure: {:?}", err),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -15,10 +15,7 @@ pub struct RpcClientRequest {
|
||||
|
||||
impl RpcClientRequest {
|
||||
pub fn new(url: String) -> Self {
|
||||
Self {
|
||||
client: reqwest::blocking::Client::new(),
|
||||
url,
|
||||
}
|
||||
Self::new_with_timeout(url, Duration::from_secs(20))
|
||||
}
|
||||
|
||||
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "../README.md"
|
||||
@ -40,26 +40,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.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.2" }
|
||||
ed25519-dalek = "=1.0.0-pre.1"
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-measure = { path = "../measure", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-measure = { path = "../measure", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "0.23.2" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.2" }
|
||||
symlink = "0.1.0"
|
||||
sys-info = "0.5.8"
|
||||
tempfile = "3.1.0"
|
||||
@ -69,7 +69,7 @@ tokio-codec = "0.1"
|
||||
tokio-fs = "0.1"
|
||||
tokio-io = "0.1"
|
||||
untrusted = "0.7.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.2" }
|
||||
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -58,31 +58,35 @@ impl BlockstreamService {
|
||||
let timeout = Duration::new(1, 0);
|
||||
let (slot, slot_leader) = slot_full_receiver.recv_timeout(timeout)?;
|
||||
|
||||
let entries = blockstore.get_slot_entries(slot, 0, None).unwrap();
|
||||
let blockstore_meta = blockstore.meta(slot).unwrap().unwrap();
|
||||
let _parent_slot = if slot == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(blockstore_meta.parent_slot)
|
||||
};
|
||||
let ticks_per_slot = entries.iter().filter(|entry| entry.is_tick()).count() as u64;
|
||||
let mut tick_height = ticks_per_slot * slot;
|
||||
// Slot might not exist due to LedgerCleanupService, check first
|
||||
let blockstore_meta = blockstore.meta(slot).unwrap();
|
||||
if let Some(blockstore_meta) = blockstore_meta {
|
||||
// Return error to main loop. Thread won't exit, will just log the error
|
||||
let entries = blockstore.get_slot_entries(slot, 0, None)?;
|
||||
let _parent_slot = if slot == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(blockstore_meta.parent_slot)
|
||||
};
|
||||
let ticks_per_slot = entries.iter().filter(|entry| entry.is_tick()).count() as u64;
|
||||
let mut tick_height = ticks_per_slot * slot;
|
||||
|
||||
for (i, entry) in entries.iter().enumerate() {
|
||||
if entry.is_tick() {
|
||||
tick_height += 1;
|
||||
}
|
||||
blockstream
|
||||
.emit_entry_event(slot, tick_height, &slot_leader, &entry)
|
||||
.unwrap_or_else(|e| {
|
||||
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
|
||||
});
|
||||
if i == entries.len() - 1 {
|
||||
for (i, entry) in entries.iter().enumerate() {
|
||||
if entry.is_tick() {
|
||||
tick_height += 1;
|
||||
}
|
||||
blockstream
|
||||
.emit_block_event(slot, tick_height, &slot_leader, entry.hash)
|
||||
.emit_entry_event(slot, tick_height, &slot_leader, &entry)
|
||||
.unwrap_or_else(|e| {
|
||||
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
|
||||
});
|
||||
if i == entries.len() - 1 {
|
||||
blockstream
|
||||
.emit_block_event(slot, tick_height, &slot_leader, entry.hash)
|
||||
.unwrap_or_else(|e| {
|
||||
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -272,7 +272,7 @@ impl ClusterInfo {
|
||||
|
||||
let ip_addr = node.gossip.ip();
|
||||
format!(
|
||||
"{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5} | {:5}| {:5} | {:5}| {:5} | {:5}| {:5}| v{}\n",
|
||||
"{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5} | {:5}| {:5} | {:5}| {:5} | {:5}| {:5}| {}\n",
|
||||
if ContactInfo::is_valid_address(&node.gossip) {
|
||||
ip_addr.to_string()
|
||||
} else {
|
||||
@ -405,7 +405,8 @@ impl ClusterInfo {
|
||||
.map(|x| x.value.contact_info().unwrap())
|
||||
}
|
||||
|
||||
pub fn rpc_peers(&self) -> Vec<ContactInfo> {
|
||||
/// all validators that have a valid rpc port regardless of `shred_version`.
|
||||
pub fn all_rpc_peers(&self) -> Vec<ContactInfo> {
|
||||
let me = self.my_data();
|
||||
self.gossip
|
||||
.crds
|
||||
@ -440,13 +441,15 @@ impl ClusterInfo {
|
||||
.values()
|
||||
.filter_map(|x| x.value.contact_info())
|
||||
.filter(|x| x.id != me)
|
||||
/* shred_version not considered for gossip peers (ie, spy nodes do not set
|
||||
shred_version) */
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.gossip))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// all validators that have a valid tvu port.
|
||||
pub fn tvu_peers(&self) -> Vec<ContactInfo> {
|
||||
/// all validators that have a valid tvu port regardless of `shred_version`.
|
||||
pub fn all_tvu_peers(&self) -> Vec<ContactInfo> {
|
||||
let me = self.my_data();
|
||||
self.gossip
|
||||
.crds
|
||||
@ -460,7 +463,37 @@ impl ClusterInfo {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// all peers that have a valid storage addr
|
||||
/// all validators that have a valid tvu port and are on the same `shred_version`.
|
||||
pub fn tvu_peers(&self) -> Vec<ContactInfo> {
|
||||
let me = self.my_data();
|
||||
self.gossip
|
||||
.crds
|
||||
.table
|
||||
.values()
|
||||
.filter_map(|x| x.value.contact_info())
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.tvu))
|
||||
.filter(|x| !ClusterInfo::is_archiver(x))
|
||||
.filter(|x| x.id != me.id)
|
||||
.filter(|x| x.shred_version == me.shred_version)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// all peers that have a valid storage addr regardless of `shred_version`.
|
||||
pub fn all_storage_peers(&self) -> Vec<ContactInfo> {
|
||||
let me = self.my_data();
|
||||
self.gossip
|
||||
.crds
|
||||
.table
|
||||
.values()
|
||||
.filter_map(|x| x.value.contact_info())
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.storage_addr))
|
||||
.filter(|x| x.id != me.id)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// all peers that have a valid storage addr and are on the same `shred_version`.
|
||||
pub fn storage_peers(&self) -> Vec<ContactInfo> {
|
||||
let me = self.my_data();
|
||||
self.gossip
|
||||
@ -470,6 +503,7 @@ impl ClusterInfo {
|
||||
.filter_map(|x| x.value.contact_info())
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.storage_addr))
|
||||
.filter(|x| x.id != me.id)
|
||||
.filter(|x| x.shred_version == me.shred_version)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
@ -483,6 +517,7 @@ impl ClusterInfo {
|
||||
.values()
|
||||
.filter_map(|x| x.value.contact_info())
|
||||
.filter(|x| x.id != me.id)
|
||||
.filter(|x| x.shred_version == me.shred_version)
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.tvu))
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.tvu_forwards))
|
||||
.cloned()
|
||||
@ -495,6 +530,7 @@ impl ClusterInfo {
|
||||
ClusterInfo::tvu_peers(self)
|
||||
.into_iter()
|
||||
.filter(|x| x.id != me.id)
|
||||
.filter(|x| x.shred_version == me.shred_version)
|
||||
.filter(|x| ContactInfo::is_valid_address(&x.gossip))
|
||||
.filter(|x| {
|
||||
self.get_epoch_state_for_node(&x.id, None)
|
||||
@ -1057,6 +1093,7 @@ impl ClusterInfo {
|
||||
.spawn(move || {
|
||||
let mut last_push = timestamp();
|
||||
let mut last_contact_info_trace = timestamp();
|
||||
let mut adopt_shred_version = obj.read().unwrap().my_data().shred_version == 0;
|
||||
let recycler = PacketsRecycler::default();
|
||||
loop {
|
||||
let start = timestamp();
|
||||
@ -1094,9 +1131,32 @@ impl ClusterInfo {
|
||||
let table_size = obj.read().unwrap().gossip.crds.table.len();
|
||||
datapoint_debug!(
|
||||
"cluster_info-purge",
|
||||
("tabel_size", table_size as i64, i64),
|
||||
("table_size", table_size as i64, i64),
|
||||
("purge_stake_timeout", timeout as i64, i64)
|
||||
);
|
||||
// Adopt the entrypoint's `shred_version` if ours is unset
|
||||
if adopt_shred_version {
|
||||
// If gossip was given an entrypoint, lookup its id
|
||||
let entrypoint_id = obj.read().unwrap().entrypoint.as_ref().map(|e| e.id);
|
||||
if let Some(entrypoint_id) = entrypoint_id {
|
||||
// If a pull from the entrypoint was successful, it should exist in the crds table
|
||||
let entrypoint = obj.read().unwrap().lookup(&entrypoint_id).cloned();
|
||||
if let Some(entrypoint) = entrypoint {
|
||||
let mut self_info = obj.read().unwrap().my_data();
|
||||
if entrypoint.shred_version == 0 {
|
||||
info!("Unable to adopt entrypoint's shred version");
|
||||
} else {
|
||||
info!(
|
||||
"Setting shred version to {:?} from entrypoint {:?}",
|
||||
entrypoint.shred_version, entrypoint.id
|
||||
);
|
||||
self_info.shred_version = entrypoint.shred_version;
|
||||
obj.write().unwrap().insert_self(self_info);
|
||||
adopt_shred_version = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: possibly tune this parameter
|
||||
//we saw a deadlock passing an obj.read().unwrap().timeout into sleep
|
||||
if start - last_push > CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 2 {
|
||||
@ -2663,6 +2723,14 @@ mod tests {
|
||||
cluster_info.insert_info(contact_info);
|
||||
stakes.insert(id3, 10);
|
||||
|
||||
// normal but with different shred version
|
||||
let id4 = Pubkey::new(&[4u8; 32]);
|
||||
let mut contact_info = ContactInfo::new_localhost(&id4, timestamp());
|
||||
contact_info.shred_version = 1;
|
||||
assert_ne!(contact_info.shred_version, d.shred_version);
|
||||
cluster_info.insert_info(contact_info.clone());
|
||||
stakes.insert(id4, 10);
|
||||
|
||||
let stakes = Arc::new(stakes);
|
||||
let (peers, peers_and_stakes) = cluster_info.sorted_tvu_peers_and_stakes(Some(stakes));
|
||||
assert_eq!(peers.len(), 2);
|
||||
|
@ -135,7 +135,7 @@ impl ClusterInfoRepairListener {
|
||||
}
|
||||
|
||||
let lowest_slot = blockstore.lowest_slot();
|
||||
let peers = cluster_info.read().unwrap().gossip_peers();
|
||||
let peers = cluster_info.read().unwrap().tvu_peers();
|
||||
let mut peers_needing_repairs: HashMap<Pubkey, EpochSlots> = HashMap::new();
|
||||
|
||||
// Iterate through all the known nodes in the network, looking for ones that
|
||||
|
@ -327,21 +327,16 @@ impl Tower {
|
||||
fork_stake.stake,
|
||||
total_staked
|
||||
);
|
||||
for (new_lockout, original_lockout) in
|
||||
lockouts.votes.iter().zip(self.lockouts.votes.iter())
|
||||
{
|
||||
if new_lockout.slot == original_lockout.slot {
|
||||
if new_lockout.confirmation_count <= self.threshold_depth as u32 {
|
||||
break;
|
||||
if vote.confirmation_count as usize > self.threshold_depth {
|
||||
for old_vote in &self.lockouts.votes {
|
||||
if old_vote.slot == vote.slot
|
||||
&& old_vote.confirmation_count == vote.confirmation_count
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if new_lockout.confirmation_count != original_lockout.confirmation_count {
|
||||
return lockout > self.threshold_size;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
true
|
||||
lockout > self.threshold_size
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -556,6 +551,24 @@ mod test {
|
||||
assert!(tower.check_vote_stake_threshold(0, &stakes, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_vote_threshold_no_skip_lockout_with_new_root() {
|
||||
solana_logger::setup();
|
||||
let mut tower = Tower::new_for_tests(4, 0.67);
|
||||
let mut stakes = HashMap::new();
|
||||
for i in 0..(MAX_LOCKOUT_HISTORY as u64 + 1) {
|
||||
stakes.insert(
|
||||
i,
|
||||
StakeLockout {
|
||||
stake: 1,
|
||||
lockout: 8,
|
||||
},
|
||||
);
|
||||
tower.record_vote(i, Hash::default());
|
||||
}
|
||||
assert!(!tower.check_vote_stake_threshold(MAX_LOCKOUT_HISTORY as u64 + 1, &stakes, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_slot_confirmed_not_enough_stake_failure() {
|
||||
let tower = Tower::new_for_tests(1, 0.67);
|
||||
|
@ -299,8 +299,8 @@ mod tests {
|
||||
assert_eq!(ci.gossip.port(), 11);
|
||||
assert_eq!(ci.tvu.port(), 12);
|
||||
assert_eq!(ci.tpu_forwards.port(), 13);
|
||||
assert_eq!(ci.rpc.port(), 8899);
|
||||
assert_eq!(ci.rpc_pubsub.port(), 8900);
|
||||
assert_eq!(ci.rpc.port(), rpc_port::DEFAULT_RPC_PORT);
|
||||
assert_eq!(ci.rpc_pubsub.port(), rpc_port::DEFAULT_RPC_PUBSUB_PORT);
|
||||
assert!(ci.storage_addr.ip().is_unspecified());
|
||||
}
|
||||
#[test]
|
||||
@ -315,8 +315,14 @@ mod tests {
|
||||
assert_eq!(d1.tvu, socketaddr!("127.0.0.1:1236"));
|
||||
assert_eq!(d1.tpu_forwards, socketaddr!("127.0.0.1:1237"));
|
||||
assert_eq!(d1.tpu, socketaddr!("127.0.0.1:1234"));
|
||||
assert_eq!(d1.rpc, socketaddr!("127.0.0.1:8899"));
|
||||
assert_eq!(d1.rpc_pubsub, socketaddr!("127.0.0.1:8900"));
|
||||
assert_eq!(
|
||||
d1.rpc,
|
||||
socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PORT))
|
||||
);
|
||||
assert_eq!(
|
||||
d1.rpc_pubsub,
|
||||
socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PUBSUB_PORT))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -197,10 +197,10 @@ fn spy(
|
||||
tvu_peers = spy_ref
|
||||
.read()
|
||||
.unwrap()
|
||||
.tvu_peers()
|
||||
.all_tvu_peers()
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>();
|
||||
archivers = spy_ref.read().unwrap().storage_peers();
|
||||
archivers = spy_ref.read().unwrap().all_storage_peers();
|
||||
if let Some(num) = num_nodes {
|
||||
if tvu_peers.len() + archivers.len() >= num {
|
||||
if let Some(gossip_addr) = find_node_by_gossip_addr {
|
||||
|
@ -68,9 +68,13 @@ impl LedgerCleanupService {
|
||||
let disk_utilization_pre = blockstore.storage_size();
|
||||
|
||||
let root = new_root_receiver.recv_timeout(Duration::from_secs(1))?;
|
||||
|
||||
// Notify blockstore of impending purge
|
||||
if root > *next_purge_batch {
|
||||
//cleanup
|
||||
blockstore.purge_slots(0, Some(root - max_ledger_slots));
|
||||
let lowest_slot = root - max_ledger_slots;
|
||||
*blockstore.lowest_cleanup_slot.write().unwrap() = lowest_slot;
|
||||
blockstore.purge_slots(0, Some(lowest_slot));
|
||||
*next_purge_batch += DEFAULT_PURGE_BATCH_SIZE;
|
||||
}
|
||||
|
||||
|
@ -527,6 +527,9 @@ impl ReplayStage {
|
||||
let tx_count = tx_count_after - tx_count_before;
|
||||
|
||||
confirm_result.map_err(|err| {
|
||||
// LedgerCleanupService should not be cleaning up anything
|
||||
// that comes after the root, so we should not see any
|
||||
// errors related to the slot being purged
|
||||
let slot = bank.slot();
|
||||
warn!("Fatal replay error in slot: {}, err: {:?}", slot, err);
|
||||
datapoint_error!(
|
||||
|
@ -45,21 +45,12 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
||||
Ok(Response { context, value })
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct JsonRpcConfig {
|
||||
pub enable_validator_exit: bool, // Enable the 'validatorExit' command
|
||||
pub faucet_addr: Option<SocketAddr>,
|
||||
}
|
||||
|
||||
impl Default for JsonRpcConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enable_validator_exit: false,
|
||||
faucet_addr: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JsonRpcRequestProcessor {
|
||||
bank_forks: Arc<RwLock<BankForks>>,
|
||||
@ -383,7 +374,11 @@ impl JsonRpcRequestProcessor {
|
||||
let stakes = HashMap::new();
|
||||
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);
|
||||
|
||||
Ok(self.blockstore.get_block_time(slot, slot_duration, stakes))
|
||||
Ok(self
|
||||
.blockstore
|
||||
.get_block_time(slot, slot_duration, stakes)
|
||||
.ok()
|
||||
.unwrap_or(None))
|
||||
}
|
||||
}
|
||||
|
||||
@ -724,11 +719,14 @@ impl RpcSol for RpcSolImpl {
|
||||
None
|
||||
}
|
||||
}
|
||||
let shred_version = cluster_info.my_data().shred_version;
|
||||
Ok(cluster_info
|
||||
.all_peers()
|
||||
.iter()
|
||||
.filter_map(|(contact_info, _)| {
|
||||
if ContactInfo::is_valid_address(&contact_info.gossip) {
|
||||
if shred_version == contact_info.shred_version
|
||||
&& ContactInfo::is_valid_address(&contact_info.gossip)
|
||||
{
|
||||
Some(RpcContactInfo {
|
||||
pubkey: contact_info.id.to_string(),
|
||||
gossip: Some(contact_info.gossip),
|
||||
@ -1117,6 +1115,7 @@ pub mod tests {
|
||||
fee_calculator::DEFAULT_BURN_PERCENT,
|
||||
hash::{hash, Hash},
|
||||
instruction::InstructionError,
|
||||
rpc_port,
|
||||
signature::{Keypair, KeypairUtil},
|
||||
system_transaction,
|
||||
transaction::TransactionError,
|
||||
@ -1355,8 +1354,9 @@ pub mod tests {
|
||||
.expect("actual response deserialization");
|
||||
|
||||
let expected = format!(
|
||||
r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:8899"}}],"id":1}}"#,
|
||||
r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:{}"}}],"id":1}}"#,
|
||||
leader_pubkey,
|
||||
rpc_port::DEFAULT_RPC_PORT
|
||||
);
|
||||
|
||||
let expected: Response =
|
||||
|
@ -131,6 +131,7 @@ impl JsonRpcService {
|
||||
.cors(DomainsValidation::AllowOnly(vec![
|
||||
AccessControlAllowOrigin::Any,
|
||||
]))
|
||||
.cors_max_age(86400)
|
||||
.request_middleware(RpcRequestMiddleware::new(ledger_path))
|
||||
.start_http(&rpc_addr);
|
||||
if let Err(e) = server {
|
||||
|
@ -56,12 +56,14 @@ pub struct ValidatorConfig {
|
||||
pub dev_sigverify_disabled: bool,
|
||||
pub dev_halt_at_slot: Option<Slot>,
|
||||
pub expected_genesis_hash: Option<Hash>,
|
||||
pub expected_shred_version: Option<u16>,
|
||||
pub voting_disabled: bool,
|
||||
pub transaction_status_service_disabled: bool,
|
||||
pub blockstream_unix_socket: Option<PathBuf>,
|
||||
pub storage_slots_per_turn: u64,
|
||||
pub account_paths: Vec<PathBuf>,
|
||||
pub rpc_config: JsonRpcConfig,
|
||||
pub rpc_ports: Option<(u16, u16)>, // (API, PubSub)
|
||||
pub snapshot_config: Option<SnapshotConfig>,
|
||||
pub max_ledger_slots: Option<u64>,
|
||||
pub broadcast_stage_type: BroadcastStageType,
|
||||
@ -77,6 +79,7 @@ impl Default for ValidatorConfig {
|
||||
dev_sigverify_disabled: false,
|
||||
dev_halt_at_slot: None,
|
||||
expected_genesis_hash: None,
|
||||
expected_shred_version: None,
|
||||
voting_disabled: false,
|
||||
transaction_status_service_disabled: false,
|
||||
blockstream_unix_socket: None,
|
||||
@ -84,6 +87,7 @@ impl Default for ValidatorConfig {
|
||||
max_ledger_slots: None,
|
||||
account_paths: Vec::new(),
|
||||
rpc_config: JsonRpcConfig::default(),
|
||||
rpc_ports: None,
|
||||
snapshot_config: None,
|
||||
broadcast_stage_type: BroadcastStageType::Standard,
|
||||
enable_partition: None,
|
||||
@ -114,8 +118,7 @@ impl ValidatorExit {
|
||||
pub struct Validator {
|
||||
pub id: Pubkey,
|
||||
validator_exit: Arc<RwLock<Option<ValidatorExit>>>,
|
||||
rpc_service: Option<JsonRpcService>,
|
||||
rpc_pubsub_service: Option<PubSubService>,
|
||||
rpc_service: Option<(JsonRpcService, PubSubService)>,
|
||||
transaction_status_service: Option<TransactionStatusService>,
|
||||
gossip_service: GossipService,
|
||||
poh_recorder: Arc<Mutex<PohRecorder>>,
|
||||
@ -126,7 +129,6 @@ pub struct Validator {
|
||||
}
|
||||
|
||||
impl Validator {
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn new(
|
||||
mut node: Node,
|
||||
keypair: &Arc<Keypair>,
|
||||
@ -194,6 +196,16 @@ impl Validator {
|
||||
compute_shred_version(&genesis_hash, &bank.hard_forks().read().unwrap());
|
||||
Self::print_node_info(&node);
|
||||
|
||||
if let Some(expected_shred_version) = config.expected_shred_version {
|
||||
if expected_shred_version != node.info.shred_version {
|
||||
error!(
|
||||
"shred version mismatch: expected {}",
|
||||
expected_shred_version
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
let cluster_info = Arc::new(RwLock::new(ClusterInfo::new(
|
||||
node.info.clone(),
|
||||
keypair.clone(),
|
||||
@ -207,36 +219,36 @@ impl Validator {
|
||||
|
||||
let blockstore = Arc::new(blockstore);
|
||||
|
||||
let rpc_service = if node.info.rpc.port() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(JsonRpcService::new(
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), node.info.rpc.port()),
|
||||
config.rpc_config.clone(),
|
||||
bank_forks.clone(),
|
||||
block_commitment_cache.clone(),
|
||||
blockstore.clone(),
|
||||
cluster_info.clone(),
|
||||
genesis_hash,
|
||||
ledger_path,
|
||||
storage_state.clone(),
|
||||
validator_exit.clone(),
|
||||
))
|
||||
};
|
||||
|
||||
let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
|
||||
let rpc_pubsub_service = if node.info.rpc_pubsub.port() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(PubSubService::new(
|
||||
&subscriptions,
|
||||
SocketAddr::new(
|
||||
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
||||
node.info.rpc_pubsub.port(),
|
||||
|
||||
let rpc_service = config.rpc_ports.map(|(rpc_port, rpc_pubsub_port)| {
|
||||
if ContactInfo::is_valid_address(&node.info.rpc) {
|
||||
assert!(ContactInfo::is_valid_address(&node.info.rpc_pubsub));
|
||||
assert_eq!(rpc_port, node.info.rpc.port());
|
||||
assert_eq!(rpc_pubsub_port, node.info.rpc_pubsub.port());
|
||||
} else {
|
||||
assert!(!ContactInfo::is_valid_address(&node.info.rpc_pubsub));
|
||||
}
|
||||
(
|
||||
JsonRpcService::new(
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rpc_port),
|
||||
config.rpc_config.clone(),
|
||||
bank_forks.clone(),
|
||||
block_commitment_cache.clone(),
|
||||
blockstore.clone(),
|
||||
cluster_info.clone(),
|
||||
genesis_hash,
|
||||
ledger_path,
|
||||
storage_state.clone(),
|
||||
validator_exit.clone(),
|
||||
),
|
||||
&exit,
|
||||
))
|
||||
};
|
||||
PubSubService::new(
|
||||
&subscriptions,
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rpc_pubsub_port),
|
||||
&exit,
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
let (transaction_status_sender, transaction_status_service) =
|
||||
if rpc_service.is_some() && !config.transaction_status_service_disabled {
|
||||
@ -305,47 +317,7 @@ impl Validator {
|
||||
.set_entrypoint(entrypoint_info.clone());
|
||||
}
|
||||
|
||||
if config.wait_for_supermajority {
|
||||
info!(
|
||||
"Waiting for more than 75% of activated stake at slot {} to be in gossip...",
|
||||
bank.slot()
|
||||
);
|
||||
loop {
|
||||
let gossip_stake_percent = get_stake_percent_in_gossip(&bank, &cluster_info);
|
||||
|
||||
info!("{}% of activated stake in gossip", gossip_stake_percent,);
|
||||
if gossip_stake_percent > 75 {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::new(1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
let sockets = Sockets {
|
||||
repair: node
|
||||
.sockets
|
||||
.repair
|
||||
.try_clone()
|
||||
.expect("Failed to clone repair socket"),
|
||||
retransmit: node
|
||||
.sockets
|
||||
.retransmit_sockets
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone retransmit socket"))
|
||||
.collect(),
|
||||
fetch: node
|
||||
.sockets
|
||||
.tvu
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone TVU Sockets"))
|
||||
.collect(),
|
||||
forwards: node
|
||||
.sockets
|
||||
.tvu_forwards
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone TVU forwards Sockets"))
|
||||
.collect(),
|
||||
};
|
||||
wait_for_supermajority(config, &bank, &cluster_info);
|
||||
|
||||
let voting_keypair = if config.voting_disabled {
|
||||
None
|
||||
@ -366,7 +338,31 @@ impl Validator {
|
||||
storage_keypair,
|
||||
&bank_forks,
|
||||
&cluster_info,
|
||||
sockets,
|
||||
Sockets {
|
||||
repair: node
|
||||
.sockets
|
||||
.repair
|
||||
.try_clone()
|
||||
.expect("Failed to clone repair socket"),
|
||||
retransmit: node
|
||||
.sockets
|
||||
.retransmit_sockets
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone retransmit socket"))
|
||||
.collect(),
|
||||
fetch: node
|
||||
.sockets
|
||||
.tvu
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone TVU Sockets"))
|
||||
.collect(),
|
||||
forwards: node
|
||||
.sockets
|
||||
.tvu_forwards
|
||||
.iter()
|
||||
.map(|s| s.try_clone().expect("Failed to clone TVU forwards Sockets"))
|
||||
.collect(),
|
||||
},
|
||||
blockstore.clone(),
|
||||
&storage_state,
|
||||
config.blockstream_unix_socket.as_ref(),
|
||||
@ -408,7 +404,6 @@ impl Validator {
|
||||
id,
|
||||
gossip_service,
|
||||
rpc_service,
|
||||
rpc_pubsub_service,
|
||||
transaction_status_service,
|
||||
tpu,
|
||||
tvu,
|
||||
@ -459,10 +454,8 @@ impl Validator {
|
||||
pub fn join(self) -> Result<()> {
|
||||
self.poh_service.join()?;
|
||||
drop(self.poh_recorder);
|
||||
if let Some(rpc_service) = self.rpc_service {
|
||||
if let Some((rpc_service, rpc_pubsub_service)) = self.rpc_service {
|
||||
rpc_service.join()?;
|
||||
}
|
||||
if let Some(rpc_pubsub_service) = self.rpc_pubsub_service {
|
||||
rpc_pubsub_service.join()?;
|
||||
}
|
||||
if let Some(transaction_status_service) = self.transaction_status_service {
|
||||
@ -563,6 +556,30 @@ fn new_banks_from_blockstore(
|
||||
)
|
||||
}
|
||||
|
||||
fn wait_for_supermajority(
|
||||
config: &ValidatorConfig,
|
||||
bank: &Arc<Bank>,
|
||||
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
||||
) {
|
||||
if !config.wait_for_supermajority {
|
||||
return;
|
||||
}
|
||||
|
||||
info!(
|
||||
"Waiting for more than 75% of activated stake at slot {} to be in gossip...",
|
||||
bank.slot()
|
||||
);
|
||||
loop {
|
||||
let gossip_stake_percent = get_stake_percent_in_gossip(&bank, &cluster_info);
|
||||
|
||||
info!("{}% of activated stake in gossip", gossip_stake_percent,);
|
||||
if gossip_stake_percent > 75 {
|
||||
break;
|
||||
}
|
||||
sleep(Duration::new(1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
|
||||
use crate::genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo};
|
||||
|
||||
@ -586,8 +603,11 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
|
||||
|
||||
let leader_voting_keypair = Arc::new(voting_keypair);
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let mut config = ValidatorConfig::default();
|
||||
config.transaction_status_service_disabled = true;
|
||||
let config = ValidatorConfig {
|
||||
transaction_status_service_disabled: true,
|
||||
rpc_ports: Some((node.info.rpc.port(), node.info.rpc_pubsub.port())),
|
||||
..ValidatorConfig::default()
|
||||
};
|
||||
let node = Validator::new(
|
||||
node,
|
||||
&node_keypair,
|
||||
@ -688,8 +708,14 @@ mod tests {
|
||||
|
||||
let voting_keypair = Arc::new(Keypair::new());
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let mut config = ValidatorConfig::default();
|
||||
config.transaction_status_service_disabled = true;
|
||||
let config = ValidatorConfig {
|
||||
transaction_status_service_disabled: true,
|
||||
rpc_ports: Some((
|
||||
validator_node.info.rpc.port(),
|
||||
validator_node.info.rpc_pubsub.port(),
|
||||
)),
|
||||
..ValidatorConfig::default()
|
||||
};
|
||||
let validator = Validator::new(
|
||||
validator_node,
|
||||
&Arc::new(validator_keypair),
|
||||
@ -722,8 +748,14 @@ mod tests {
|
||||
ledger_paths.push(validator_ledger_path.clone());
|
||||
let voting_keypair = Arc::new(Keypair::new());
|
||||
let storage_keypair = Arc::new(Keypair::new());
|
||||
let mut config = ValidatorConfig::default();
|
||||
config.transaction_status_service_disabled = true;
|
||||
let config = ValidatorConfig {
|
||||
transaction_status_service_disabled: true,
|
||||
rpc_ports: Some((
|
||||
validator_node.info.rpc.port(),
|
||||
validator_node.info.rpc_pubsub.port(),
|
||||
)),
|
||||
..ValidatorConfig::default()
|
||||
};
|
||||
Validator::new(
|
||||
validator_node,
|
||||
&Arc::new(validator_keypair),
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-crate-features"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
tokio = "0.1"
|
||||
tokio-codec = "0.1"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-genesis-programs"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.0" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.0" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.23.2" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.2" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-genesis"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@ -17,13 +17,13 @@ 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.23.0" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@ -55,7 +55,7 @@ pub const BATCH_FOUR_STAKER_INFOS: &[StakerInfo] = &[
|
||||
},
|
||||
StakerInfo {
|
||||
name: "unbecoming silver",
|
||||
staker: "42yapY7Vrs5jqht9TCKZsPoyb4vDFYcPfRkqAP85NSAQ",
|
||||
staker: "4AcoZa1P8fF5XK21RJsiuMRZPEScbbWNc75oakRFHiBz",
|
||||
lamports: 28_800 * LAMPORTS_PER_SOL,
|
||||
},
|
||||
StakerInfo {
|
||||
|
@ -3,19 +3,19 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-gossip"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-net-utils = { path = "../net-utils", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-install"
|
||||
description = "The solana cluster software installer"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@ -26,11 +26,11 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
|
||||
serde = "1.0.104"
|
||||
serde_derive = "1.0.103"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
tar = "0.4.26"
|
||||
tempdir = "0.3.7"
|
||||
url = "2.1.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-keygen"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana key generation utility"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -14,8 +14,9 @@ clap = "2.33"
|
||||
dirs = "2.0.2"
|
||||
num_cpus = "1.12.0"
|
||||
rpassword = "4.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-cli-config = { path = "../cli-config", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
tiny-bip39 = "0.7.0"
|
||||
|
||||
[[bin]]
|
||||
|
@ -8,6 +8,7 @@ use num_cpus;
|
||||
use solana_clap_utils::keypair::{
|
||||
keypair_from_seed_phrase, prompt_passphrase, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
};
|
||||
use solana_cli_config::config::{Config, CONFIG_FILE};
|
||||
use solana_sdk::{
|
||||
pubkey::write_pubkey_file,
|
||||
signature::{
|
||||
@ -21,7 +22,7 @@ use std::{
|
||||
path::Path,
|
||||
process::exit,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
thread,
|
||||
@ -30,6 +31,12 @@ use std::{
|
||||
|
||||
const NO_PASSPHRASE: &str = "";
|
||||
|
||||
struct GrindMatch {
|
||||
starts: String,
|
||||
ends: String,
|
||||
count: AtomicU64,
|
||||
}
|
||||
|
||||
fn check_for_overwrite(outfile: &str, matches: &ArgMatches) {
|
||||
let force = matches.is_present("force");
|
||||
if !force && Path::new(outfile).exists() {
|
||||
@ -38,23 +45,28 @@ fn check_for_overwrite(outfile: &str, matches: &ArgMatches) {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_keypair_from_matches(matches: &ArgMatches) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
fn get_keypair_from_matches(
|
||||
matches: &ArgMatches,
|
||||
config: Config,
|
||||
) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
let mut path = dirs::home_dir().expect("home directory");
|
||||
let infile = if matches.is_present("infile") {
|
||||
matches.value_of("infile").unwrap()
|
||||
let keypair = if matches.is_present("keypair") {
|
||||
matches.value_of("keypair").unwrap()
|
||||
} else if config.keypair_path != "" {
|
||||
&config.keypair_path
|
||||
} else {
|
||||
path.extend(&[".config", "solana", "id.json"]);
|
||||
path.to_str().unwrap()
|
||||
};
|
||||
|
||||
if infile == "-" {
|
||||
if keypair == "-" {
|
||||
let mut stdin = std::io::stdin();
|
||||
read_keypair(&mut stdin)
|
||||
} else if infile == ASK_KEYWORD {
|
||||
} else if keypair == ASK_KEYWORD {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase("pubkey recovery", skip_validation, false)
|
||||
} else {
|
||||
read_keypair_file(infile)
|
||||
read_keypair_file(keypair)
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,28 +85,152 @@ fn output_keypair(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grind_validator_starts_with(v: String) -> Result<(), String> {
|
||||
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
|
||||
return Err(String::from("Expected : between PREFIX and COUNT"));
|
||||
}
|
||||
let args: Vec<&str> = v.split(':').collect();
|
||||
bs58::decode(&args[0])
|
||||
.into_vec()
|
||||
.map_err(|err| format!("{}: {:?}", args[0], err))?;
|
||||
let count = args[1].parse::<u64>();
|
||||
if count.is_err() || count.unwrap() == 0 {
|
||||
return Err(String::from("Expected COUNT to be of type u64"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grind_validator_ends_with(v: String) -> Result<(), String> {
|
||||
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
|
||||
return Err(String::from("Expected : between SUFFIX and COUNT"));
|
||||
}
|
||||
let args: Vec<&str> = v.split(':').collect();
|
||||
bs58::decode(&args[0])
|
||||
.into_vec()
|
||||
.map_err(|err| format!("{}: {:?}", args[0], err))?;
|
||||
let count = args[1].parse::<u64>();
|
||||
if count.is_err() || count.unwrap() == 0 {
|
||||
return Err(String::from("Expected COUNT to be of type u64"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grind_validator_starts_and_ends_with(v: String) -> Result<(), String> {
|
||||
if v.matches(':').count() != 2 || (v.starts_with(':') || v.ends_with(':')) {
|
||||
return Err(String::from(
|
||||
"Expected : between PREFIX and SUFFIX and COUNT",
|
||||
));
|
||||
}
|
||||
let args: Vec<&str> = v.split(':').collect();
|
||||
bs58::decode(&args[0])
|
||||
.into_vec()
|
||||
.map_err(|err| format!("{}: {:?}", args[0], err))?;
|
||||
bs58::decode(&args[1])
|
||||
.into_vec()
|
||||
.map_err(|err| format!("{}: {:?}", args[1], err))?;
|
||||
let count = args[2].parse::<u64>();
|
||||
if count.is_err() || count.unwrap() == 0 {
|
||||
return Err(String::from("Expected COUNT to be a u64"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grind_print_info(grind_matches: &[GrindMatch]) {
|
||||
println!("Searching with {} threads for:", num_cpus::get());
|
||||
for gm in grind_matches {
|
||||
let mut msg = Vec::<String>::new();
|
||||
if gm.count.load(Ordering::Relaxed) > 1 {
|
||||
msg.push("pubkeys".to_string());
|
||||
msg.push("start".to_string());
|
||||
msg.push("end".to_string());
|
||||
} else {
|
||||
msg.push("pubkey".to_string());
|
||||
msg.push("starts".to_string());
|
||||
msg.push("ends".to_string());
|
||||
}
|
||||
println!(
|
||||
"\t{} {} that {} with '{}' and {} with '{}'",
|
||||
gm.count.load(Ordering::Relaxed),
|
||||
msg[0],
|
||||
msg[1],
|
||||
gm.starts,
|
||||
msg[2],
|
||||
gm.ends
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn grind_parse_args(
|
||||
starts_with_args: HashSet<String>,
|
||||
ends_with_args: HashSet<String>,
|
||||
starts_and_ends_with_args: HashSet<String>,
|
||||
) -> Vec<GrindMatch> {
|
||||
let mut grind_matches = Vec::<GrindMatch>::new();
|
||||
for sw in starts_with_args {
|
||||
let args: Vec<&str> = sw.split(':').collect();
|
||||
grind_matches.push(GrindMatch {
|
||||
starts: args[0].to_lowercase(),
|
||||
ends: "".to_string(),
|
||||
count: AtomicU64::new(args[1].parse::<u64>().unwrap()),
|
||||
});
|
||||
}
|
||||
for ew in ends_with_args {
|
||||
let args: Vec<&str> = ew.split(':').collect();
|
||||
grind_matches.push(GrindMatch {
|
||||
starts: "".to_string(),
|
||||
ends: args[0].to_lowercase(),
|
||||
count: AtomicU64::new(args[1].parse::<u64>().unwrap()),
|
||||
});
|
||||
}
|
||||
for swew in starts_and_ends_with_args {
|
||||
let args: Vec<&str> = swew.split(':').collect();
|
||||
grind_matches.push(GrindMatch {
|
||||
starts: args[0].to_lowercase(),
|
||||
ends: args[1].to_lowercase(),
|
||||
count: AtomicU64::new(args[2].parse::<u64>().unwrap()),
|
||||
});
|
||||
}
|
||||
grind_print_info(&grind_matches);
|
||||
grind_matches
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
let matches = App::new(crate_name!())
|
||||
.about(crate_description!())
|
||||
.version(solana_clap_utils::version!())
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp)
|
||||
.arg({
|
||||
let arg = Arg::with_name("config_file")
|
||||
.short("C")
|
||||
.long("config")
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.global(true)
|
||||
.help("Configuration file to use");
|
||||
if let Some(ref config_file) = *CONFIG_FILE {
|
||||
arg.default_value(&config_file)
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
})
|
||||
.subcommand(
|
||||
SubCommand::with_name("verify")
|
||||
.about("Verify a keypair can sign and verify a message.")
|
||||
.arg(
|
||||
Arg::with_name("infile")
|
||||
Arg::with_name("pubkey")
|
||||
.index(1)
|
||||
.value_name("BASE58_PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("Public key"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("keypair")
|
||||
.index(2)
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.help("Path to keypair file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("pubkey")
|
||||
.index(2)
|
||||
.value_name("BASE58_PUBKEY")
|
||||
.takes_value(true)
|
||||
.help("Public key"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("new")
|
||||
@ -148,33 +284,37 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.arg(
|
||||
Arg::with_name("ignore_case")
|
||||
.long("ignore-case")
|
||||
.help("Perform case insensitive matches"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("includes")
|
||||
.long("includes")
|
||||
.value_name("BASE58")
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.validator(|value| {
|
||||
bs58::decode(&value).into_vec()
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{}: {:?}", value, err))
|
||||
})
|
||||
.help("Save keypair if its public key includes this string\n(may be specified multiple times)"),
|
||||
.help("Performs case insensitive matches"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("starts_with")
|
||||
.long("starts-with")
|
||||
.value_name("BASE58 PREFIX")
|
||||
.value_name("PREFIX:COUNT")
|
||||
.number_of_values(1)
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.validator(|value| {
|
||||
bs58::decode(&value).into_vec()
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{}: {:?}", value, err))
|
||||
})
|
||||
.help("Save keypair if its public key starts with this prefix\n(may be specified multiple times)"),
|
||||
.validator(grind_validator_starts_with)
|
||||
.help("Saves specified number of keypairs whos public key starts with the indicated prefix\nExample: --starts-with sol:4\nPREFIX type is Base58\nCOUNT type is u64"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ends_with")
|
||||
.long("ends-with")
|
||||
.value_name("SUFFIX:COUNT")
|
||||
.number_of_values(1)
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.validator(grind_validator_ends_with)
|
||||
.help("Saves specified number of keypairs whos public key ends with the indicated suffix\nExample: --ends-with ana:4\nSUFFIX type is Base58\nCOUNT type is u64"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("starts_and_ends_with")
|
||||
.long("starts-and-ends-with")
|
||||
.value_name("PREFIX:SUFFIX:COUNT")
|
||||
.number_of_values(1)
|
||||
.takes_value(true)
|
||||
.multiple(true)
|
||||
.validator(grind_validator_starts_and_ends_with)
|
||||
.help("Saves specified number of keypairs whos public key starts and ends with the indicated perfix and suffix\nExample: --starts-and-ends-with sol:ana:4\nPREFIX and SUFFIX type is Base58\nCOUNT type is u64"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
@ -182,7 +322,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.about("Display the pubkey from a keypair file")
|
||||
.setting(AppSettings::DisableVersion)
|
||||
.arg(
|
||||
Arg::with_name("infile")
|
||||
Arg::with_name("keypair")
|
||||
.index(1)
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
@ -234,10 +374,15 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
|
||||
)
|
||||
.get_matches();
|
||||
let config = if let Some(config_file) = matches.value_of("config_file") {
|
||||
Config::load(config_file).unwrap_or_default()
|
||||
} else {
|
||||
Config::default()
|
||||
};
|
||||
|
||||
match matches.subcommand() {
|
||||
("pubkey", Some(matches)) => {
|
||||
let keypair = get_keypair_from_matches(matches)?;
|
||||
let keypair = get_keypair_from_matches(matches, config)?;
|
||||
|
||||
if matches.is_present("outfile") {
|
||||
let outfile = matches.value_of("outfile").unwrap();
|
||||
@ -311,16 +456,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
}
|
||||
("grind", Some(matches)) => {
|
||||
let ignore_case = matches.is_present("ignore_case");
|
||||
let includes = if matches.is_present("includes") {
|
||||
values_t_or_exit!(matches, "includes", String)
|
||||
.into_iter()
|
||||
.map(|s| if ignore_case { s.to_lowercase() } else { s })
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
||||
let starts_with = if matches.is_present("starts_with") {
|
||||
let starts_with_args = if matches.is_present("starts_with") {
|
||||
values_t_or_exit!(matches, "starts_with", String)
|
||||
.into_iter()
|
||||
.map(|s| if ignore_case { s.to_lowercase() } else { s })
|
||||
@ -328,68 +465,101 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
let ends_with_args = if matches.is_present("ends_with") {
|
||||
values_t_or_exit!(matches, "ends_with", String)
|
||||
.into_iter()
|
||||
.map(|s| if ignore_case { s.to_lowercase() } else { s })
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
let starts_and_ends_with_args = if matches.is_present("starts_and_ends_with") {
|
||||
values_t_or_exit!(matches, "starts_and_ends_with", String)
|
||||
.into_iter()
|
||||
.map(|s| if ignore_case { s.to_lowercase() } else { s })
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
||||
if includes.is_empty() && starts_with.is_empty() {
|
||||
if starts_with_args.is_empty()
|
||||
&& ends_with_args.is_empty()
|
||||
&& starts_and_ends_with_args.is_empty()
|
||||
{
|
||||
eprintln!(
|
||||
"Error: No keypair search criteria provided (--includes or --starts-with)"
|
||||
"Error: No keypair search criteria provided (--starts-with or --ends-with or --starts-and-ends-with)"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let grind_matches =
|
||||
grind_parse_args(starts_with_args, ends_with_args, starts_and_ends_with_args);
|
||||
|
||||
let grind_matches_thread_safe = Arc::new(grind_matches);
|
||||
let attempts = Arc::new(AtomicU64::new(1));
|
||||
let found = Arc::new(AtomicU64::new(0));
|
||||
let start = Instant::now();
|
||||
let done = Arc::new(AtomicBool::new(false));
|
||||
|
||||
println!(
|
||||
"Searching with {} threads for a pubkey containing {:?} or starting with {:?}",
|
||||
num_cpus::get(),
|
||||
includes,
|
||||
starts_with
|
||||
);
|
||||
for _ in 0..num_cpus::get() {
|
||||
let done = done.clone();
|
||||
let attempts = attempts.clone();
|
||||
let found = found.clone();
|
||||
let grind_matches_thread_safe = grind_matches_thread_safe.clone();
|
||||
|
||||
let _threads = (0..num_cpus::get())
|
||||
.map(|_| {
|
||||
let attempts = attempts.clone();
|
||||
let found = found.clone();
|
||||
let includes = includes.clone();
|
||||
let starts_with = starts_with.clone();
|
||||
|
||||
thread::spawn(move || loop {
|
||||
let attempts = attempts.fetch_add(1, Ordering::Relaxed);
|
||||
if attempts % 5_000_000 == 0 {
|
||||
println!(
|
||||
"Searched {} keypairs in {}s. {} matches found",
|
||||
attempts,
|
||||
start.elapsed().as_secs(),
|
||||
found.load(Ordering::Relaxed),
|
||||
);
|
||||
let handle = thread::spawn(move || loop {
|
||||
if done.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
let attempts = attempts.fetch_add(1, Ordering::Relaxed);
|
||||
if attempts % 1_000_000 == 0 {
|
||||
println!(
|
||||
"Searched {} keypairs in {}s. {} matches found.",
|
||||
attempts,
|
||||
start.elapsed().as_secs(),
|
||||
found.load(Ordering::Relaxed),
|
||||
);
|
||||
}
|
||||
let keypair = Keypair::new();
|
||||
let mut pubkey = bs58::encode(keypair.pubkey()).into_string();
|
||||
if ignore_case {
|
||||
pubkey = pubkey.to_lowercase();
|
||||
}
|
||||
let mut total_matches_found = 0;
|
||||
for i in 0..grind_matches_thread_safe.len() {
|
||||
if grind_matches_thread_safe[i].count.load(Ordering::Relaxed) == 0 {
|
||||
total_matches_found += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
let keypair = Keypair::new();
|
||||
let mut pubkey = bs58::encode(keypair.pubkey()).into_string();
|
||||
|
||||
if ignore_case {
|
||||
pubkey = pubkey.to_lowercase();
|
||||
}
|
||||
|
||||
if starts_with.iter().any(|s| pubkey.starts_with(s))
|
||||
|| includes.iter().any(|s| pubkey.contains(s))
|
||||
if (!grind_matches_thread_safe[i].starts.is_empty()
|
||||
&& grind_matches_thread_safe[i].ends.is_empty()
|
||||
&& pubkey.starts_with(&grind_matches_thread_safe[i].starts))
|
||||
|| (grind_matches_thread_safe[i].starts.is_empty()
|
||||
&& !grind_matches_thread_safe[i].ends.is_empty()
|
||||
&& pubkey.ends_with(&grind_matches_thread_safe[i].ends))
|
||||
|| (!grind_matches_thread_safe[i].starts.is_empty()
|
||||
&& !grind_matches_thread_safe[i].ends.is_empty()
|
||||
&& pubkey.starts_with(&grind_matches_thread_safe[i].starts)
|
||||
&& pubkey.ends_with(&grind_matches_thread_safe[i].ends))
|
||||
{
|
||||
let found = found.fetch_add(1, Ordering::Relaxed);
|
||||
output_keypair(
|
||||
&keypair,
|
||||
&format!("{}.json", keypair.pubkey()),
|
||||
&format!("{}", found),
|
||||
)
|
||||
.unwrap();
|
||||
let _found = found.fetch_add(1, Ordering::Relaxed);
|
||||
grind_matches_thread_safe[i]
|
||||
.count
|
||||
.fetch_sub(1, Ordering::Relaxed);
|
||||
println!("Wrote keypair to {}", &format!("{}.json", keypair.pubkey()));
|
||||
write_keypair_file(&keypair, &format!("{}.json", keypair.pubkey()))
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
thread::park();
|
||||
}
|
||||
if total_matches_found == grind_matches_thread_safe.len() {
|
||||
done.store(true, Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
handle.join().unwrap();
|
||||
}
|
||||
}
|
||||
("verify", Some(matches)) => {
|
||||
let keypair = get_keypair_from_matches(matches)?;
|
||||
let keypair = get_keypair_from_matches(matches, config)?;
|
||||
let test_data = b"test";
|
||||
let signature = Signature::new(&keypair.sign(test_data).to_bytes());
|
||||
let pubkey_bs58 = matches.value_of("pubkey").unwrap();
|
||||
|
@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-ledger-tool"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-ledger"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana ledger"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -29,19 +29,19 @@ reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0
|
||||
serde = "1.0.104"
|
||||
serde_bytes = "0.11.3"
|
||||
serde_derive = "1.0.103"
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-measure = { path = "../measure", version = "0.23.0" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-perf = { path = "../perf", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-measure = { path = "../measure", version = "0.23.2" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
solana-perf = { path = "../perf", version = "0.23.2" }
|
||||
ed25519-dalek = "1.0.0-pre.1"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
sys-info = "0.5.8"
|
||||
symlink = "0.1.0"
|
||||
tar = "0.4.26"
|
||||
@ -59,7 +59,7 @@ features = ["lz4"]
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
matches = "0.1.6"
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@ -90,6 +90,7 @@ pub struct Blockstore {
|
||||
insert_shreds_lock: Arc<Mutex<()>>,
|
||||
pub new_shreds_signals: Vec<SyncSender<bool>>,
|
||||
pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>,
|
||||
pub lowest_cleanup_slot: Arc<RwLock<u64>>,
|
||||
}
|
||||
|
||||
pub struct IndexMetaWorkingSetEntry {
|
||||
@ -207,7 +208,7 @@ impl Blockstore {
|
||||
|
||||
measure.stop();
|
||||
info!("{:?} {}", blockstore_path, measure);
|
||||
Ok(Blockstore {
|
||||
let blockstore = Blockstore {
|
||||
db,
|
||||
meta_cf,
|
||||
dead_slots_cf,
|
||||
@ -222,7 +223,9 @@ impl Blockstore {
|
||||
completed_slots_senders: vec![],
|
||||
insert_shreds_lock: Arc::new(Mutex::new(())),
|
||||
last_root,
|
||||
})
|
||||
lowest_cleanup_slot: Arc::new(RwLock::new(0)),
|
||||
};
|
||||
Ok(blockstore)
|
||||
}
|
||||
|
||||
pub fn open_with_signal(
|
||||
@ -1059,6 +1062,12 @@ impl Blockstore {
|
||||
to_index: u64,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(u64, usize)> {
|
||||
// lowest_cleanup_slot is the last slot that was not cleaned up by
|
||||
// LedgerCleanupService
|
||||
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
|
||||
if *lowest_cleanup_slot > slot {
|
||||
return Err(BlockstoreError::SlotCleanedUp);
|
||||
}
|
||||
let meta_cf = self.db.column::<cf::SlotMeta>();
|
||||
let mut buffer_offset = 0;
|
||||
let mut last_index = 0;
|
||||
@ -1288,14 +1297,26 @@ impl Blockstore {
|
||||
slot: Slot,
|
||||
slot_duration: Duration,
|
||||
stakes: &HashMap<Pubkey, (u64, Account)>,
|
||||
) -> Option<UnixTimestamp> {
|
||||
) -> Result<Option<UnixTimestamp>> {
|
||||
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
|
||||
// lowest_cleanup_slot is the last slot that was not cleaned up by
|
||||
// LedgerCleanupService
|
||||
if *lowest_cleanup_slot > slot {
|
||||
return Err(BlockstoreError::SlotCleanedUp);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
calculate_stake_weighted_timestamp(unique_timestamps, stakes, slot, slot_duration)
|
||||
Ok(calculate_stake_weighted_timestamp(
|
||||
unique_timestamps,
|
||||
stakes,
|
||||
slot,
|
||||
slot_duration,
|
||||
))
|
||||
}
|
||||
|
||||
fn get_timestamp_slots(
|
||||
@ -1346,6 +1367,12 @@ impl Blockstore {
|
||||
slot: Slot,
|
||||
encoding: Option<RpcTransactionEncoding>,
|
||||
) -> Result<RpcConfirmedBlock> {
|
||||
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
|
||||
// lowest_cleanup_slot is the last slot that was not cleaned up by
|
||||
// LedgerCleanupService
|
||||
if *lowest_cleanup_slot > slot {
|
||||
return Err(BlockstoreError::SlotCleanedUp);
|
||||
}
|
||||
let encoding = encoding.unwrap_or(RpcTransactionEncoding::Json);
|
||||
if self.is_root(slot) {
|
||||
let slot_meta_cf = self.db.column::<cf::SlotMeta>();
|
||||
@ -1466,6 +1493,14 @@ impl Blockstore {
|
||||
if self.is_dead(slot) {
|
||||
return Err(BlockstoreError::DeadSlot);
|
||||
}
|
||||
|
||||
// lowest_cleanup_slot is the last slot that was not cleaned up by
|
||||
// LedgerCleanupService
|
||||
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
|
||||
if *lowest_cleanup_slot > slot {
|
||||
return Err(BlockstoreError::SlotCleanedUp);
|
||||
}
|
||||
|
||||
let slot_meta_cf = self.db.column::<cf::SlotMeta>();
|
||||
let slot_meta = slot_meta_cf.get(slot)?;
|
||||
if slot_meta.is_none() {
|
||||
@ -4886,10 +4921,11 @@ pub mod tests {
|
||||
})
|
||||
.sum();
|
||||
expected_time /= total_stake;
|
||||
assert_eq!(block_time_slot_3.unwrap() as u64, expected_time);
|
||||
assert_eq!(block_time_slot_3.unwrap().unwrap() as u64, expected_time);
|
||||
assert_eq!(
|
||||
blockstore
|
||||
.get_block_time(8, slot_duration.clone(), &stakes)
|
||||
.unwrap()
|
||||
.unwrap() as u64,
|
||||
expected_time + 2 // At 400ms block duration, 5 slots == 2sec
|
||||
);
|
||||
|
@ -49,6 +49,7 @@ pub enum BlockstoreError {
|
||||
IO(#[from] std::io::Error),
|
||||
Serialize(#[from] Box<bincode::ErrorKind>),
|
||||
FsExtraError(#[from] fs_extra::error::Error),
|
||||
SlotCleanedUp,
|
||||
}
|
||||
pub(crate) type Result<T> = std::result::Result<T, BlockstoreError>;
|
||||
|
||||
|
@ -525,11 +525,6 @@ where
|
||||
|stream| {
|
||||
let mut bank: Bank = match snapshot_version {
|
||||
env!("CARGO_PKG_VERSION") => deserialize_from_snapshot(stream.by_ref())?,
|
||||
"0.22.3" => {
|
||||
let bank0223: solana_runtime::bank::LegacyBank0223 =
|
||||
deserialize_from_snapshot(stream.by_ref())?;
|
||||
bank0223.into()
|
||||
}
|
||||
_ => {
|
||||
return Err(get_io_error(&format!(
|
||||
"unsupported snapshot version: {}",
|
||||
|
@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-local-cluster"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@ -12,24 +12,24 @@ homepage = "https://solana.com/"
|
||||
itertools = "0.8.1"
|
||||
log = "0.4.8"
|
||||
rand = "0.6.5"
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.0" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.0" }
|
||||
solana-core = { path = "../core", version = "0.23.0" }
|
||||
solana-client = { path = "../client", version = "0.23.0" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.0" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.0" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.0" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "0.23.0" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.0" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.2" }
|
||||
solana-config-program = { path = "../programs/config", version = "0.23.2" }
|
||||
solana-core = { path = "../core", version = "0.23.2" }
|
||||
solana-client = { path = "../client", version = "0.23.2" }
|
||||
solana-faucet = { path = "../faucet", version = "0.23.2" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
|
||||
solana-ledger = { path = "../ledger", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-runtime = { path = "../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "0.23.2" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
|
||||
symlink = "0.1.0"
|
||||
tempfile = "3.1.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
|
@ -38,6 +38,7 @@ impl ClusterValidatorInfo {
|
||||
pub trait Cluster {
|
||||
fn get_node_pubkeys(&self) -> Vec<Pubkey>;
|
||||
fn get_validator_client(&self, pubkey: &Pubkey) -> Option<ThinClient>;
|
||||
fn get_contact_info(&self, pubkey: &Pubkey) -> Option<&ContactInfo>;
|
||||
fn exit_node(&mut self, pubkey: &Pubkey) -> ClusterValidatorInfo;
|
||||
fn restart_node(&mut self, pubkey: &Pubkey, cluster_validator_info: ClusterValidatorInfo);
|
||||
fn exit_restart_node(&mut self, pubkey: &Pubkey, config: ValidatorConfig);
|
||||
|
@ -207,6 +207,10 @@ impl LocalCluster {
|
||||
let leader_storage_keypair = Arc::new(storage_keypair);
|
||||
let leader_voting_keypair = Arc::new(voting_keypair);
|
||||
let mut leader_config = config.validator_configs[0].clone();
|
||||
leader_config.rpc_ports = Some((
|
||||
leader_node.info.rpc.port(),
|
||||
leader_node.info.rpc_pubsub.port(),
|
||||
));
|
||||
leader_config.transaction_status_service_disabled = true;
|
||||
let leader_server = Validator::new(
|
||||
leader_node,
|
||||
@ -351,6 +355,10 @@ impl LocalCluster {
|
||||
}
|
||||
|
||||
let mut config = validator_config.clone();
|
||||
config.rpc_ports = Some((
|
||||
validator_node.info.rpc.port(),
|
||||
validator_node.info.rpc_pubsub.port(),
|
||||
));
|
||||
config.transaction_status_service_disabled = true;
|
||||
let voting_keypair = Arc::new(voting_keypair);
|
||||
let validator_server = Validator::new(
|
||||
@ -658,6 +666,8 @@ impl Cluster for LocalCluster {
|
||||
// Update the stored ContactInfo for this node
|
||||
let node = Node::new_localhost_with_pubkey(&pubkey);
|
||||
cluster_validator_info.info.contact_info = node.info.clone();
|
||||
cluster_validator_info.config.rpc_ports =
|
||||
Some((node.info.rpc.port(), node.info.rpc_pubsub.port()));
|
||||
cluster_validator_info
|
||||
.config
|
||||
.transaction_status_service_disabled = true;
|
||||
@ -695,6 +705,10 @@ impl Cluster for LocalCluster {
|
||||
cluster_validator_info.config = validator_config;
|
||||
self.restart_node(pubkey, cluster_validator_info);
|
||||
}
|
||||
|
||||
fn get_contact_info(&self, pubkey: &Pubkey) -> Option<&ContactInfo> {
|
||||
self.validators.get(pubkey).map(|v| &v.info.contact_info)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LocalCluster {
|
||||
|
@ -73,12 +73,14 @@ fn run_archiver_startup_basic(num_nodes: usize, num_archivers: usize) {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[serial]
|
||||
fn test_archiver_startup_1_node() {
|
||||
run_archiver_startup_basic(1, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[serial]
|
||||
fn test_archiver_startup_2_nodes() {
|
||||
run_archiver_startup_basic(2, 1);
|
||||
|
@ -662,8 +662,11 @@ fn test_snapshot_restart_tower() {
|
||||
cluster.restart_node(&validator_id, validator_info);
|
||||
|
||||
// Test cluster can still make progress and get confirmations in tower
|
||||
// Use the restarted node as the discovery point so that we get updated
|
||||
// validator's ContactInfo
|
||||
let restarted_node_info = cluster.get_contact_info(&validator_id).unwrap();
|
||||
cluster_tests::spend_and_verify_all_nodes(
|
||||
&cluster.entry_point_info,
|
||||
&restarted_node_info,
|
||||
&cluster.funding_keypair,
|
||||
1,
|
||||
HashSet::new(),
|
||||
|
@ -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.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
|
||||
[[bin]]
|
||||
name = "solana-log-analyzer"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-logger"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0"
|
||||
version = "0.23.2"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "../README.md"
|
||||
@ -12,8 +12,8 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.8"
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
jemallocator = "0.3.2"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-merkle-tree"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-metrics"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.10.1", default-features = false, features = ["blocking", "rustls-tls"] }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
sys-info = "0.5.8"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -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.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
rand = "0.6.5"
|
||||
|
||||
[[bin]]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-net-utils"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
tokio = "0.1"
|
||||
tokio-codec = "0.1"
|
||||
|
||||
|
@ -868,6 +868,7 @@ EOF
|
||||
;;
|
||||
|
||||
config)
|
||||
failOnValidatorBootupFailure=false
|
||||
prepareInstancesAndWriteConfigFile
|
||||
;;
|
||||
info)
|
||||
|
@ -75,7 +75,7 @@ solana-bench-exchange)
|
||||
"
|
||||
;;
|
||||
idle)
|
||||
# Add the mint keypair to idle clients for convenience
|
||||
# Add the faucet keypair to idle clients for convenience
|
||||
net/scripts/rsync-retry.sh -vPrc \
|
||||
"$entrypointIp":~/solana/config/faucet-keypair.json ~/solana/
|
||||
exit 0
|
||||
|
@ -221,8 +221,8 @@ EOF
|
||||
# shellcheck disable=SC2206 # Do not want to quote $genesisOptions
|
||||
args+=($genesisOptions)
|
||||
|
||||
if [[ -f net/keypairs/mint.json ]]; then
|
||||
export FAUCET_KEYPAIR=net/keypairs/mint.json
|
||||
if [[ -f net/keypairs/faucet.json ]]; then
|
||||
export FAUCET_KEYPAIR=net/keypairs/faucet.json
|
||||
fi
|
||||
if [[ -f net/keypairs/bootstrap-validator-identity.json ]]; then
|
||||
export BOOTSTRAP_VALIDATOR_IDENTITY_KEYPAIR=net/keypairs/bootstrap-validator-identity.json
|
||||
@ -303,11 +303,11 @@ EOF
|
||||
fi
|
||||
|
||||
set -x
|
||||
# Add the mint keypair to validators for convenient access from tools
|
||||
# Add the faucet keypair to validators for convenient access from tools
|
||||
# like bench-tps and add to blocktreamers to run a faucet
|
||||
scp "$entrypointIp":~/solana/config/faucet-keypair.json config/
|
||||
if [[ $nodeType = blockstreamer ]]; then
|
||||
# Run another faucet with the mint keypair on the blockstreamer node.
|
||||
# Run another faucet with the same keypair on the blockstreamer node.
|
||||
# Typically the blockstreamer node has a static IP/DNS name for hosting
|
||||
# the blockexplorer web app, and is a location that somebody would expect
|
||||
# to be able to airdrop from
|
||||
|
@ -1,5 +1,3 @@
|
||||
asteroids|216.24.140.155|10.1.1.26|16|64|NVME|2000|||0|Denver
|
||||
pacman|216.24.140.154|10.1.1.25|16|64|NVME|2000|||0|Denver
|
||||
dumoulin|216.24.140.149|10.1.1.20|16|64|SATA|2000|NVME,NVME,NVME|1000,1000,1000|4|Denver
|
||||
foosball|216.24.140.150|10.1.1.21|16|64|SATA|2000|NVME|1000|2|Denver
|
||||
pingpong|216.24.140.151|10.1.1.22|16|64|SATA|2000|NVME|1000|2|Denver
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-perf"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.0" }
|
||||
solana-logger = { path = "../logger", version = "0.23.0" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.0" }
|
||||
solana-sdk = { path = "../sdk", version = "0.23.2" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.2" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
|
||||
solana-logger = { path = "../logger", version = "0.23.2" }
|
||||
solana-metrics = { path = "../metrics", version = "0.23.2" }
|
||||
|
||||
[lib]
|
||||
name = "solana_perf"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-bpf-programs"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-logger = { path = "../../logger", version = "0.23.0" }
|
||||
solana-runtime = { path = "../../runtime", version = "0.23.0" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.0" }
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "0.23.2" }
|
||||
solana-logger = { path = "../../logger", version = "0.23.2" }
|
||||
solana-runtime = { path = "../../runtime", version = "0.23.2" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.2" }
|
||||
solana_rbpf = "=0.1.19"
|
||||
|
||||
[[bench]]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.23.0" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.23.2" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit-dep"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-alloc"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-dep-crate"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-dup-accounts"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-external-spend"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-iter"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.23.0" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.23.2" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args-dep"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-noop"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-panic"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-param-passing"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.23.0" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.23.2" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-param-passing-dep"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-sysval"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "0.23.2", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.2" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-loader-program"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.0" }
|
||||
solana-logger = { path = "../../logger", version = "0.23.2" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.2" }
|
||||
solana_rbpf = "=0.1.19"
|
||||
|
||||
[lib]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-btc-spv-program"
|
||||
version = "0.23.0"
|
||||
version = "0.23.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.23.0"}
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.2"}
|
||||
hex = "0.3.2"
|
||||
|
||||
[lib]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "btc_spv_bin"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Bitcoin spv parsing program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-budget-program"
|
||||
version = "0.23.0"
|
||||
version = "0.23.2"
|
||||
description = "Solana Budget program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@ -16,11 +16,11 @@ num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
serde = "1.0.104"
|
||||
serde_derive = "1.0.103"
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.0" }
|
||||
solana-sdk = { path = "../../sdk", version = "0.23.2" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../../runtime", version = "0.23.0" }
|
||||
solana-runtime = { path = "../../runtime", version = "0.23.2" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user