Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c51a18a887 | ||
|
206ff02be9 | ||
|
8d7e90e9b8 | ||
|
eb11db3e3e | ||
|
8d8ad84527 | ||
|
fa059bb3c3 | ||
|
9652e832c2 | ||
|
52e27712e1 | ||
|
c00ec26a3b | ||
|
50eba96b58 | ||
|
e7c0629951 | ||
|
a08235da9a | ||
|
b213004157 | ||
|
92562b4349 | ||
|
01c490d354 | ||
|
cfdc0eb99e | ||
|
0b7b3c9f20 | ||
|
5cd685ed3a |
685
Cargo.lock
generated
685
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,7 @@ members = [
|
||||
"transaction-status",
|
||||
"upload-perf",
|
||||
"net-utils",
|
||||
"version",
|
||||
"vote-signer",
|
||||
"cli",
|
||||
"rayon-threadlimit",
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-bench"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,10 +10,10 @@ homepage = "https://solana.com/"
|
||||
[dependencies]
|
||||
log = "0.4.6"
|
||||
rayon = "1.3.0"
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-measure = { path = "../measure", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-measure = { path = "../measure", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
rand = "0.7.0"
|
||||
clap = "2.33.0"
|
||||
crossbeam-channel = "0.4"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-archiver-lib"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Archiver Library"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,23 +15,23 @@ ed25519-dalek = "=1.0.0-pre.3"
|
||||
log = "0.4.8"
|
||||
rand = "0.7.0"
|
||||
rand_chacha = "0.2.2"
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
thiserror = "1.0"
|
||||
serde = "1.0.105"
|
||||
serde_json = "1.0.48"
|
||||
serde_derive = "1.0.103"
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-chacha = { path = "../chacha", version = "1.1.10" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.10" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-chacha = { path = "../chacha", version = "1.1.11" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.11" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4.2"
|
||||
|
@@ -697,16 +697,11 @@ impl Archiver {
|
||||
RpcClient::new_socket(rpc_peers[node_index].rpc)
|
||||
};
|
||||
Ok(rpc_client
|
||||
.send(
|
||||
&RpcRequest::GetSlotsPerSegment,
|
||||
.send::<u64>(
|
||||
RpcRequest::GetSlotsPerSegment,
|
||||
serde_json::json!([client_commitment]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("Error while making rpc request {:?}", err);
|
||||
ArchiverError::ClientError(err)
|
||||
})?
|
||||
.as_u64()
|
||||
.unwrap())
|
||||
} else {
|
||||
Err(ArchiverError::NoRpcPeers)
|
||||
@@ -749,21 +744,14 @@ impl Archiver {
|
||||
let node_index = thread_rng().gen_range(0, rpc_peers.len());
|
||||
RpcClient::new_socket(rpc_peers[node_index].rpc)
|
||||
};
|
||||
let response = rpc_client
|
||||
.send(
|
||||
&RpcRequest::GetStorageTurn,
|
||||
serde_json::value::Value::Null,
|
||||
0,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("Error while making rpc request {:?}", err);
|
||||
ArchiverError::ClientError(err)
|
||||
})?;
|
||||
let RpcStorageTurn {
|
||||
blockhash: storage_blockhash,
|
||||
slot: turn_slot,
|
||||
} = serde_json::from_value::<RpcStorageTurn>(response)
|
||||
.map_err(ArchiverError::JsonError)?;
|
||||
} = rpc_client.send(
|
||||
RpcRequest::GetStorageTurn,
|
||||
serde_json::value::Value::Null,
|
||||
0,
|
||||
)?;
|
||||
let turn_blockhash = storage_blockhash.parse().map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-archiver-utils"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Archiver Utils"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,12 +11,12 @@ edition = "2018"
|
||||
[dependencies]
|
||||
log = "0.4.8"
|
||||
rand = "0.7.0"
|
||||
solana-chacha = { path = "../chacha", version = "1.1.10" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-chacha = { path = "../chacha", version = "1.1.11" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex = "0.4.2"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-archiver"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,13 +10,13 @@ homepage = "https://solana.com/"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
console = "0.10.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,14 +10,14 @@ homepage = "https://solana.com/"
|
||||
[dependencies]
|
||||
log = "0.4.6"
|
||||
rayon = "1.3.0"
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-measure = { path = "../measure", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-measure = { path = "../measure", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
rand = "0.7.0"
|
||||
crossbeam-channel = "0.4"
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-exchange"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -18,20 +18,20 @@ rand = "0.7.0"
|
||||
rayon = "1.3.0"
|
||||
serde_json = "1.0.48"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-genesis = { path = "../genesis", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.10" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-genesis = { path = "../genesis", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.11" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.1.10" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.1.11" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,17 +2,17 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,24 +14,24 @@ log = "0.4.8"
|
||||
rayon = "1.3.0"
|
||||
serde_json = "1.0.48"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-genesis = { path = "../genesis", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-genesis = { path = "../genesis", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.11" }
|
||||
#solana-librapay = { path = "../programs/librapay", version = "1.1.8", optional = true }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-measure = { path = "../measure", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-measure = { path = "../measure", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
#solana-move-loader-program = { path = "../programs/move_loader", version = "1.1.8", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.4.0"
|
||||
serial_test_derive = "0.4.0"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.1.10" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "1.1.11" }
|
||||
|
||||
#[features]
|
||||
#move = ["solana-librapay", "solana-move-loader-program"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-chacha-cuda"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10" }
|
||||
solana-chacha = { path = "../chacha", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.11" }
|
||||
solana-chacha = { path = "../chacha", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2.1"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-chacha-sys"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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.7.0"
|
||||
rand_chacha = "0.2.2"
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.2.1"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana utilities for the clap"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,8 +11,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
thiserror = "1.0.11"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.0"
|
||||
|
@@ -8,11 +8,15 @@ pub const COMMITMENT_ARG: ArgConstant<'static> = ArgConstant {
|
||||
};
|
||||
|
||||
pub fn commitment_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||
commitment_arg_with_default("recent")
|
||||
}
|
||||
|
||||
pub fn commitment_arg_with_default<'a, 'b>(default_value: &'static str) -> Arg<'a, 'b> {
|
||||
Arg::with_name(COMMITMENT_ARG.name)
|
||||
.long(COMMITMENT_ARG.long)
|
||||
.takes_value(true)
|
||||
.possible_values(&["recent", "root", "max"])
|
||||
.default_value("recent")
|
||||
.default_value(default_value)
|
||||
.value_name("COMMITMENT_LEVEL")
|
||||
.help(COMMITMENT_ARG.help)
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -27,28 +27,28 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.48"
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.10" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.11" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.1.11" }
|
||||
thiserror = "1.0.13"
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -16,7 +16,11 @@ use num_traits::FromPrimitive;
|
||||
use serde_json::{self, json, Value};
|
||||
use solana_budget_program::budget_instruction::{self, BudgetError};
|
||||
use solana_clap_utils::{
|
||||
input_parsers::*, input_validators::*, keypair::signer_from_path, offline::SIGN_ONLY_ARG,
|
||||
commitment::{commitment_arg_with_default, COMMITMENT_ARG},
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
keypair::signer_from_path,
|
||||
offline::SIGN_ONLY_ARG,
|
||||
ArgConstant,
|
||||
};
|
||||
use solana_client::{
|
||||
@@ -201,6 +205,10 @@ pub enum CliCommand {
|
||||
GetSlot {
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
Supply {
|
||||
commitment_config: CommitmentConfig,
|
||||
print_accounts: bool,
|
||||
},
|
||||
TotalSupply {
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
@@ -405,6 +413,7 @@ pub enum CliCommand {
|
||||
Balance {
|
||||
pubkey: Option<Pubkey>,
|
||||
use_lamports_unit: bool,
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
Cancel(Pubkey),
|
||||
Confirm(Signature),
|
||||
@@ -569,6 +578,7 @@ impl Default for CliConfig<'_> {
|
||||
command: CliCommand::Balance {
|
||||
pubkey: Some(Pubkey::default()),
|
||||
use_lamports_unit: false,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
},
|
||||
json_rpc_url: Self::default_json_rpc_url(),
|
||||
websocket_url: Self::default_websocket_url(),
|
||||
@@ -612,6 +622,7 @@ pub fn parse_command(
|
||||
}),
|
||||
("epoch", Some(matches)) => parse_get_epoch(matches),
|
||||
("slot", Some(matches)) => parse_get_slot(matches),
|
||||
("supply", Some(matches)) => parse_supply(matches),
|
||||
("total-supply", Some(matches)) => parse_total_supply(matches),
|
||||
("transaction-count", Some(matches)) => parse_get_transaction_count(matches),
|
||||
("leader-schedule", Some(_matches)) => Ok(CliCommandInfo {
|
||||
@@ -782,6 +793,7 @@ pub fn parse_command(
|
||||
}
|
||||
("balance", Some(matches)) => {
|
||||
let pubkey = pubkey_of_signer(matches, "pubkey", wallet_manager)?;
|
||||
let commitment_config = commitment_of(matches, COMMITMENT_ARG.long).unwrap();
|
||||
let signers = if pubkey.is_some() {
|
||||
vec![]
|
||||
} else {
|
||||
@@ -796,6 +808,7 @@ pub fn parse_command(
|
||||
command: CliCommand::Balance {
|
||||
pubkey,
|
||||
use_lamports_unit: matches.is_present("lamports"),
|
||||
commitment_config,
|
||||
},
|
||||
signers,
|
||||
})
|
||||
@@ -1178,19 +1191,17 @@ fn process_balance(
|
||||
config: &CliConfig,
|
||||
pubkey: &Option<Pubkey>,
|
||||
use_lamports_unit: bool,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ProcessResult {
|
||||
let pubkey = if let Some(pubkey) = pubkey {
|
||||
*pubkey
|
||||
} else {
|
||||
config.pubkey()?
|
||||
};
|
||||
let balance = rpc_client.retry_get_balance(&pubkey, 5)?;
|
||||
match balance {
|
||||
Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit, true)),
|
||||
None => Err(
|
||||
CliError::RpcRequestError("Received result of an unexpected type".to_string()).into(),
|
||||
),
|
||||
}
|
||||
let balance = rpc_client
|
||||
.get_balance_with_commitment(&pubkey, commitment_config)?
|
||||
.value;
|
||||
Ok(build_balance_message(balance, use_lamports_unit, true))
|
||||
}
|
||||
|
||||
fn process_confirm(
|
||||
@@ -1343,8 +1354,7 @@ fn process_deploy(
|
||||
)?;
|
||||
|
||||
trace!("Creating program account");
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut create_account_tx, &signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&create_account_tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config).map_err(|_| {
|
||||
CliError::DynamicProgramError("Program account allocation failed".to_string())
|
||||
})?;
|
||||
@@ -1354,7 +1364,7 @@ fn process_deploy(
|
||||
|
||||
trace!("Finalizing program account");
|
||||
rpc_client
|
||||
.send_and_confirm_transaction_with_spinner(&mut finalize_tx, &signers)
|
||||
.send_and_confirm_transaction_with_spinner(&finalize_tx)
|
||||
.map_err(|e| {
|
||||
CliError::DynamicProgramError(format!("Program finalize transaction failed: {}", e))
|
||||
})?;
|
||||
@@ -1419,8 +1429,7 @@ fn process_pay(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
} else if *witnesses == None {
|
||||
@@ -1455,10 +1464,7 @@ fn process_pay(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(
|
||||
&mut tx,
|
||||
&[config.signers[0], &contract_state],
|
||||
);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
let signature = log_instruction_custom_error::<BudgetError>(result, &config)?;
|
||||
Ok(json!({
|
||||
"signature": signature,
|
||||
@@ -1494,10 +1500,7 @@ fn process_pay(
|
||||
return_signers(&tx, &config)
|
||||
} else {
|
||||
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(
|
||||
&mut tx,
|
||||
&[config.signers[0], &contract_state],
|
||||
);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.signers[0].pubkey(),
|
||||
@@ -1532,8 +1535,7 @@ fn process_cancel(rpc_client: &RpcClient, config: &CliConfig, pubkey: &Pubkey) -
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<BudgetError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -1556,8 +1558,7 @@ fn process_time_elapsed(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<BudgetError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -1619,7 +1620,7 @@ fn process_transfer(
|
||||
let result = if no_wait {
|
||||
rpc_client.send_transaction(&tx)
|
||||
} else {
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers)
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&tx)
|
||||
};
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
@@ -1643,8 +1644,7 @@ fn process_witness(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<BudgetError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -1703,6 +1703,10 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
CliCommand::GetSlot { commitment_config } => {
|
||||
process_get_slot(&rpc_client, *commitment_config)
|
||||
}
|
||||
CliCommand::Supply {
|
||||
commitment_config,
|
||||
print_accounts,
|
||||
} => process_supply(&rpc_client, config, *commitment_config, *print_accounts),
|
||||
CliCommand::TotalSupply { commitment_config } => {
|
||||
process_total_supply(&rpc_client, *commitment_config)
|
||||
}
|
||||
@@ -2133,7 +2137,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
CliCommand::Balance {
|
||||
pubkey,
|
||||
use_lamports_unit,
|
||||
} => process_balance(&rpc_client, config, &pubkey, *use_lamports_unit),
|
||||
commitment_config,
|
||||
} => process_balance(
|
||||
&rpc_client,
|
||||
config,
|
||||
&pubkey,
|
||||
*use_lamports_unit,
|
||||
*commitment_config,
|
||||
),
|
||||
// Cancel a contract by contract Pubkey
|
||||
CliCommand::Cancel(pubkey) => process_cancel(&rpc_client, config, &pubkey),
|
||||
// Confirm the last client transaction by signature
|
||||
@@ -2275,8 +2286,8 @@ pub fn request_and_confirm_airdrop(
|
||||
sleep(Duration::from_secs(1));
|
||||
}
|
||||
}?;
|
||||
let mut tx = keypair.airdrop_transaction();
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[&keypair]);
|
||||
let tx = keypair.airdrop_transaction();
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -2402,7 +2413,8 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
.long("lamports")
|
||||
.takes_value(false)
|
||||
.help("Display balance in lamports instead of SOL"),
|
||||
),
|
||||
)
|
||||
.arg(commitment_arg_with_default("max")),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("cancel")
|
||||
@@ -2813,7 +2825,8 @@ mod tests {
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Balance {
|
||||
pubkey: Some(keypair.pubkey()),
|
||||
use_lamports_unit: false
|
||||
use_lamports_unit: false,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
},
|
||||
signers: vec![],
|
||||
}
|
||||
@@ -2829,7 +2842,8 @@ mod tests {
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Balance {
|
||||
pubkey: Some(keypair.pubkey()),
|
||||
use_lamports_unit: true
|
||||
use_lamports_unit: true,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
},
|
||||
signers: vec![],
|
||||
}
|
||||
@@ -2843,7 +2857,8 @@ mod tests {
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Balance {
|
||||
pubkey: None,
|
||||
use_lamports_unit: true
|
||||
use_lamports_unit: true,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
},
|
||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -3313,12 +3328,14 @@ mod tests {
|
||||
config.command = CliCommand::Balance {
|
||||
pubkey: None,
|
||||
use_lamports_unit: true,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
};
|
||||
assert_eq!(process_command(&config).unwrap(), "50 lamports");
|
||||
|
||||
config.command = CliCommand::Balance {
|
||||
pubkey: None,
|
||||
use_lamports_unit: false,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
};
|
||||
assert_eq!(process_command(&config).unwrap(), "0.00000005 SOL");
|
||||
|
||||
@@ -3552,6 +3569,7 @@ mod tests {
|
||||
config.command = CliCommand::Balance {
|
||||
pubkey: None,
|
||||
use_lamports_unit: false,
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
};
|
||||
assert!(process_command(&config).is_err());
|
||||
|
||||
|
@@ -4,9 +4,10 @@ use console::{style, Emoji};
|
||||
use inflector::cases::titlecase::to_title_case;
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
use solana_client::rpc_response::{RpcEpochInfo, RpcKeyedAccount, RpcVoteAccountInfo};
|
||||
use solana_client::rpc_response::{RpcEpochInfo, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo};
|
||||
use solana_sdk::{
|
||||
clock::{self, Epoch, Slot, UnixTimestamp},
|
||||
native_token::lamports_to_sol,
|
||||
stake_history::StakeHistoryEntry,
|
||||
};
|
||||
use solana_stake_program::stake_state::{Authorized, Lockup};
|
||||
@@ -907,3 +908,49 @@ impl fmt::Display for CliSignature {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CliSupply {
|
||||
pub total: u64,
|
||||
pub circulating: u64,
|
||||
pub non_circulating: u64,
|
||||
pub non_circulating_accounts: Vec<String>,
|
||||
#[serde(skip_serializing)]
|
||||
pub print_accounts: bool,
|
||||
}
|
||||
|
||||
impl From<RpcSupply> for CliSupply {
|
||||
fn from(rpc_supply: RpcSupply) -> Self {
|
||||
Self {
|
||||
total: rpc_supply.total,
|
||||
circulating: rpc_supply.circulating,
|
||||
non_circulating: rpc_supply.non_circulating,
|
||||
non_circulating_accounts: rpc_supply.non_circulating_accounts,
|
||||
print_accounts: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CliSupply {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln_name_value(f, "Total:", &format!("{} SOL", lamports_to_sol(self.total)))?;
|
||||
writeln_name_value(
|
||||
f,
|
||||
"Circulating:",
|
||||
&format!("{} SOL", lamports_to_sol(self.circulating)),
|
||||
)?;
|
||||
writeln_name_value(
|
||||
f,
|
||||
"Non-Circulating:",
|
||||
&format!("{} SOL", lamports_to_sol(self.non_circulating)),
|
||||
)?;
|
||||
if self.print_accounts {
|
||||
writeln!(f)?;
|
||||
writeln_name_value(f, "Non-Circulating Accounts:", " ")?;
|
||||
for account in &self.non_circulating_accounts {
|
||||
writeln!(f, " {}", account)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ use crate::{
|
||||
cli_output::*,
|
||||
display::println_name_value,
|
||||
};
|
||||
use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use console::{style, Emoji};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use solana_clap_utils::{
|
||||
@@ -121,8 +121,19 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||
SubCommand::with_name("epoch").about("Get current epoch")
|
||||
.arg(commitment_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("supply").about("Get information about the cluster supply of SOL")
|
||||
.arg(
|
||||
Arg::with_name("print_accounts")
|
||||
.long("print-accounts")
|
||||
.takes_value(false)
|
||||
.help("Print list of non-circualting account addresses")
|
||||
)
|
||||
.arg(commitment_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("total-supply").about("Get total number of SOL")
|
||||
.setting(AppSettings::Hidden)
|
||||
.arg(commitment_arg()),
|
||||
)
|
||||
.subcommand(
|
||||
@@ -346,6 +357,18 @@ pub fn parse_get_epoch(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliEr
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_supply(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let commitment_config = commitment_of(matches, COMMITMENT_ARG.long).unwrap();
|
||||
let print_accounts = matches.is_present("print_accounts");
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Supply {
|
||||
commitment_config,
|
||||
print_accounts,
|
||||
},
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_total_supply(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let commitment_config = commitment_of(matches, COMMITMENT_ARG.long).unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
@@ -653,7 +676,7 @@ pub fn process_show_block_production(
|
||||
slot_limit: Option<u64>,
|
||||
) -> ProcessResult {
|
||||
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
||||
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::max())?;
|
||||
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::root())?;
|
||||
|
||||
let epoch = epoch.unwrap_or(epoch_info.epoch);
|
||||
if epoch > epoch_info.epoch {
|
||||
@@ -712,7 +735,7 @@ pub fn process_show_block_production(
|
||||
|
||||
progress_bar.set_message(&format!("Fetching leader schedule for epoch {}...", epoch));
|
||||
let leader_schedule = rpc_client
|
||||
.get_leader_schedule_with_commitment(Some(start_slot), CommitmentConfig::max())?;
|
||||
.get_leader_schedule_with_commitment(Some(start_slot), CommitmentConfig::root())?;
|
||||
if leader_schedule.is_none() {
|
||||
return Err(format!("Unable to fetch leader schedule for slot {}", start_slot).into());
|
||||
}
|
||||
@@ -797,6 +820,18 @@ pub fn process_show_block_production(
|
||||
Ok(config.output_format.formatted_string(&block_production))
|
||||
}
|
||||
|
||||
pub fn process_supply(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
commitment_config: CommitmentConfig,
|
||||
print_accounts: bool,
|
||||
) -> ProcessResult {
|
||||
let supply_response = rpc_client.supply_with_commitment(commitment_config.clone())?;
|
||||
let mut supply: CliSupply = supply_response.value.into();
|
||||
supply.print_accounts = print_accounts;
|
||||
Ok(config.output_format.formatted_string(&supply))
|
||||
}
|
||||
|
||||
pub fn process_total_supply(
|
||||
rpc_client: &RpcClient,
|
||||
commitment_config: CommitmentConfig,
|
||||
|
@@ -462,7 +462,7 @@ pub fn process_authorize_nonce_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<NonceError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@ pub fn process_create_nonce_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -580,8 +580,7 @@ pub fn process_new_nonce(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0], nonce_authority]);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -640,7 +639,7 @@ pub fn process_withdraw_from_nonce_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<NonceError>(result, &config)
|
||||
}
|
||||
|
||||
|
@@ -894,7 +894,7 @@ pub fn process_create_stake_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -959,7 +959,7 @@ pub fn process_stake_authorize(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1013,7 +1013,7 @@ pub fn process_deactivate_stake_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1076,7 +1076,7 @@ pub fn process_withdraw_stake(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1210,7 +1210,7 @@ pub fn process_split_stake(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1267,7 +1267,7 @@ pub fn process_stake_set_lockup(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
@@ -1475,7 +1475,7 @@ pub fn process_delegate_stake(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<StakeError>(result, &config)
|
||||
}
|
||||
}
|
||||
|
@@ -242,7 +242,7 @@ pub fn process_create_storage_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ pub fn process_claim_storage_reward(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let signature = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?;
|
||||
let signature = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
|
||||
Ok(signature.to_string())
|
||||
}
|
||||
|
||||
|
@@ -367,7 +367,7 @@ pub fn process_set_validator_info(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?;
|
||||
let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
|
||||
|
||||
println!("Success! Validator info published at: {:?}", info_pubkey);
|
||||
println!("{}", signature_str);
|
||||
|
@@ -457,7 +457,7 @@ pub fn process_create_vote_account(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -497,8 +497,7 @@ pub fn process_vote_authorize(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -531,7 +530,7 @@ pub fn process_vote_update_validator(
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
@@ -636,8 +635,7 @@ pub fn process_withdraw_from_vote_account(
|
||||
&fee_calculator,
|
||||
&transaction.message,
|
||||
)?;
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction_with_spinner(&mut transaction, &config.signers);
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
|
||||
log_instruction_custom_error::<VoteError>(result, &config)
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -19,10 +19,10 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.48"
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
thiserror = "1.0"
|
||||
tungstenite = "0.10.1"
|
||||
url = "2.1.1"
|
||||
@@ -31,7 +31,7 @@ url = "2.1.1"
|
||||
assert_matches = "1.3.0"
|
||||
jsonrpc-core = "14.0.5"
|
||||
jsonrpc-http-server = "14.0.6"
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -50,28 +50,29 @@ impl Into<TransportError> for ClientErrorKind {
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{kind}")]
|
||||
pub struct ClientError {
|
||||
command: Option<&'static str>,
|
||||
request: Option<rpc_request::RpcRequest>,
|
||||
|
||||
#[source]
|
||||
kind: ClientErrorKind,
|
||||
}
|
||||
|
||||
impl ClientError {
|
||||
pub fn new_with_command(kind: ClientErrorKind, command: &'static str) -> Self {
|
||||
pub fn new_with_request(kind: ClientErrorKind, request: rpc_request::RpcRequest) -> Self {
|
||||
Self {
|
||||
command: Some(command),
|
||||
request: Some(request),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_with_command(self, command: &'static str) -> Self {
|
||||
pub fn into_with_request(self, request: rpc_request::RpcRequest) -> Self {
|
||||
Self {
|
||||
command: Some(command),
|
||||
request: Some(request),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(&self) -> Option<&'static str> {
|
||||
self.command
|
||||
pub fn request(&self) -> Option<&rpc_request::RpcRequest> {
|
||||
self.request.as_ref()
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> &ClientErrorKind {
|
||||
@@ -82,7 +83,7 @@ impl ClientError {
|
||||
impl From<ClientErrorKind> for ClientError {
|
||||
fn from(kind: ClientErrorKind) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
@@ -91,7 +92,7 @@ impl From<ClientErrorKind> for ClientError {
|
||||
impl From<TransportError> for ClientError {
|
||||
fn from(err: TransportError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -106,7 +107,7 @@ impl Into<TransportError> for ClientError {
|
||||
impl From<std::io::Error> for ClientError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -115,7 +116,7 @@ impl From<std::io::Error> for ClientError {
|
||||
impl From<reqwest::Error> for ClientError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -124,7 +125,7 @@ impl From<reqwest::Error> for ClientError {
|
||||
impl From<rpc_request::RpcError> for ClientError {
|
||||
fn from(err: rpc_request::RpcError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -133,7 +134,7 @@ impl From<rpc_request::RpcError> for ClientError {
|
||||
impl From<serde_json::error::Error> for ClientError {
|
||||
fn from(err: serde_json::error::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -142,7 +143,7 @@ impl From<serde_json::error::Error> for ClientError {
|
||||
impl From<SignerError> for ClientError {
|
||||
fn from(err: SignerError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
@@ -151,7 +152,7 @@ impl From<SignerError> for ClientError {
|
||||
impl From<TransactionError> for ClientError {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ use crate::{client_error::Result, rpc_request::RpcRequest};
|
||||
pub(crate) trait GenericRpcClientRequest {
|
||||
fn send(
|
||||
&self,
|
||||
request: &RpcRequest,
|
||||
request: RpcRequest,
|
||||
params: serde_json::Value,
|
||||
retries: usize,
|
||||
) -> Result<serde_json::Value>;
|
||||
|
@@ -40,11 +40,11 @@ impl MockRpcClientRequest {
|
||||
impl GenericRpcClientRequest for MockRpcClientRequest {
|
||||
fn send(
|
||||
&self,
|
||||
request: &RpcRequest,
|
||||
request: RpcRequest,
|
||||
params: serde_json::Value,
|
||||
_retries: usize,
|
||||
) -> Result<serde_json::Value> {
|
||||
if let Some(value) = self.mocks.write().unwrap().remove(request) {
|
||||
if let Some(value) = self.mocks.write().unwrap().remove(&request) {
|
||||
return Ok(value);
|
||||
}
|
||||
if self.url == "fails" {
|
||||
|
@@ -24,7 +24,7 @@ use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
signers::Signers,
|
||||
transaction::{self, Transaction, TransactionError},
|
||||
transaction::{self, Transaction},
|
||||
};
|
||||
use solana_transaction_status::{
|
||||
ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus,
|
||||
@@ -96,32 +96,25 @@ impl RpcClient {
|
||||
|
||||
pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<Signature> {
|
||||
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
||||
let response =
|
||||
self.client
|
||||
.send(&RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
|
||||
|
||||
match response.as_str() {
|
||||
None => {
|
||||
Err(RpcError::ForUser("Received result of an unexpected type".to_string()).into())
|
||||
}
|
||||
Some(signature_base58_str) => {
|
||||
let signature = signature_base58_str.parse::<Signature>().map_err(|err| {
|
||||
Into::<ClientError>::into(RpcError::ParseError(err.to_string()))
|
||||
})?;
|
||||
// A mismatching RPC response signature indicates an issue with the RPC node, and
|
||||
// should not be passed along to confirmation methods. The transaction may or may
|
||||
// not have been submitted to the cluster, so callers should verify the success of
|
||||
// the correct transaction signature independently.
|
||||
if signature != transaction.signatures[0] {
|
||||
Err(RpcError::RpcRequestError(format!(
|
||||
"RPC node returned mismatched signature {:?}, expected {:?}",
|
||||
signature, transaction.signatures[0]
|
||||
))
|
||||
.into())
|
||||
} else {
|
||||
Ok(transaction.signatures[0])
|
||||
}
|
||||
}
|
||||
let signature_base58_str: String =
|
||||
self.send(RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
|
||||
|
||||
let signature = signature_base58_str
|
||||
.parse::<Signature>()
|
||||
.map_err(|err| Into::<ClientError>::into(RpcError::ParseError(err.to_string())))?;
|
||||
// A mismatching RPC response signature indicates an issue with the RPC node, and
|
||||
// should not be passed along to confirmation methods. The transaction may or may
|
||||
// not have been submitted to the cluster, so callers should verify the success of
|
||||
// the correct transaction signature independently.
|
||||
if signature != transaction.signatures[0] {
|
||||
Err(RpcError::RpcRequestError(format!(
|
||||
"RPC node returned mismatched signature {:?}, expected {:?}",
|
||||
signature, transaction.signatures[0]
|
||||
))
|
||||
.into())
|
||||
} else {
|
||||
Ok(transaction.signatures[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,11 +130,7 @@ impl RpcClient {
|
||||
signatures: &[Signature],
|
||||
) -> RpcResult<Vec<Option<TransactionStatus>>> {
|
||||
let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
|
||||
let signature_status =
|
||||
self.client
|
||||
.send(&RpcRequest::GetSignatureStatuses, json!([signatures]), 5)?;
|
||||
Ok(serde_json::from_value(signature_status)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?)
|
||||
self.send(RpcRequest::GetSignatureStatuses, json!([signatures]), 5)
|
||||
}
|
||||
|
||||
pub fn get_signature_status_with_commitment(
|
||||
@@ -149,14 +138,11 @@ impl RpcClient {
|
||||
signature: &Signature,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||
let signature_status = self.client.send(
|
||||
&RpcRequest::GetSignatureStatuses,
|
||||
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
||||
RpcRequest::GetSignatureStatuses,
|
||||
json!([[signature.to_string()]]),
|
||||
5,
|
||||
)?;
|
||||
let result: Response<Vec<Option<TransactionStatus>>> =
|
||||
serde_json::from_value(signature_status)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
|
||||
Ok(result.value[0]
|
||||
.clone()
|
||||
.filter(|result| result.satisfies_commitment(commitment_config))
|
||||
@@ -169,16 +155,13 @@ impl RpcClient {
|
||||
commitment_config: CommitmentConfig,
|
||||
search_transaction_history: bool,
|
||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||
let signature_status = self.client.send(
|
||||
&RpcRequest::GetSignatureStatuses,
|
||||
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
||||
RpcRequest::GetSignatureStatuses,
|
||||
json!([[signature.to_string()], {
|
||||
"searchTransactionHistory": search_transaction_history
|
||||
}]),
|
||||
5,
|
||||
)?;
|
||||
let result: Response<Vec<Option<TransactionStatus>>> =
|
||||
serde_json::from_value(signature_status)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
|
||||
Ok(result.value[0]
|
||||
.clone()
|
||||
.filter(|result| result.satisfies_commitment(commitment_config))
|
||||
@@ -193,13 +176,14 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<Slot> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetSlot, json!([commitment_config]), 0)
|
||||
.map_err(|err| err.into_with_command("GetSlot"))?;
|
||||
self.send(RpcRequest::GetSlot, json!([commitment_config]), 0)
|
||||
}
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetSlot"))
|
||||
pub fn supply_with_commitment(
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<RpcSupply> {
|
||||
self.send(RpcRequest::GetSupply, json!([commitment_config]), 0)
|
||||
}
|
||||
|
||||
pub fn total_supply(&self) -> ClientResult<u64> {
|
||||
@@ -210,13 +194,7 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<u64> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetTotalSupply, json!([commitment_config]), 0)
|
||||
.map_err(|err| err.into_with_command("GetTotalSupply"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetTotalSupply"))
|
||||
self.send(RpcRequest::GetTotalSupply, json!([commitment_config]), 0)
|
||||
}
|
||||
|
||||
pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
|
||||
@@ -227,23 +205,11 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<RpcVoteAccountStatus> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetVoteAccounts, json!([commitment_config]), 0)
|
||||
.map_err(|err| err.into_with_command("GetVoteAccounts"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetVoteAccounts"))
|
||||
self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]), 0)
|
||||
}
|
||||
|
||||
pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetClusterNodes, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetClusterNodes"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetClusterNodes"))
|
||||
self.send(RpcRequest::GetClusterNodes, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
||||
@@ -255,13 +221,7 @@ impl RpcClient {
|
||||
slot: Slot,
|
||||
encoding: TransactionEncoding,
|
||||
) -> ClientResult<ConfirmedBlock> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetConfirmedBlock, json!([slot, encoding]), 0)
|
||||
.map_err(|err| err.into_with_command("GetConfirmedBlock"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetConfirmedBlock"))
|
||||
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]), 0)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_blocks(
|
||||
@@ -269,17 +229,11 @@ impl RpcClient {
|
||||
start_slot: Slot,
|
||||
end_slot: Option<Slot>,
|
||||
) -> ClientResult<Vec<Slot>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetConfirmedBlocks,
|
||||
json!([start_slot, end_slot]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetConfirmedBlocks"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetConfirmedBlocks"))
|
||||
self.send(
|
||||
RpcRequest::GetConfirmedBlocks,
|
||||
json!([start_slot, end_slot]),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_signatures_for_address(
|
||||
@@ -288,19 +242,11 @@ impl RpcClient {
|
||||
start_slot: Slot,
|
||||
end_slot: Slot,
|
||||
) -> ClientResult<Vec<Signature>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetConfirmedSignaturesForAddress,
|
||||
json!([address.to_string(), start_slot, end_slot]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetConfirmedSignaturesForAddress"))?;
|
||||
|
||||
let signatures_base58_str: Vec<String> =
|
||||
serde_json::from_value(response).map_err(|err| {
|
||||
ClientError::new_with_command(err.into(), "GetConfirmedSignaturesForAddress")
|
||||
})?;
|
||||
let signatures_base58_str: Vec<String> = self.send(
|
||||
RpcRequest::GetConfirmedSignaturesForAddress,
|
||||
json!([address.to_string(), start_slot, end_slot]),
|
||||
0,
|
||||
)?;
|
||||
|
||||
let mut signatures = vec![];
|
||||
for signature_base58_str in signatures_base58_str {
|
||||
@@ -318,23 +264,16 @@ impl RpcClient {
|
||||
signature: &Signature,
|
||||
encoding: TransactionEncoding,
|
||||
) -> ClientResult<ConfirmedTransaction> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetConfirmedTransaction,
|
||||
json!([signature.to_string(), encoding]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetConfirmedTransaction"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetConfirmedTransaction"))
|
||||
self.send(
|
||||
RpcRequest::GetConfirmedTransaction,
|
||||
json!([signature.to_string(), encoding]),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetBlockTime, json!([slot]), 0);
|
||||
let request = RpcRequest::GetBlockTime;
|
||||
let response = self.client.send(request, json!([slot]), 0);
|
||||
|
||||
response
|
||||
.map(|result_json| {
|
||||
@@ -342,11 +281,11 @@ impl RpcClient {
|
||||
return Err(RpcError::ForUser(format!("Block Not Found: slot={}", slot)).into());
|
||||
}
|
||||
let result = serde_json::from_value(result_json)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetBlockTime"))?;
|
||||
.map_err(|err| ClientError::new_with_request(err.into(), request))?;
|
||||
trace!("Response block timestamp {:?} {:?}", slot, result);
|
||||
Ok(result)
|
||||
})
|
||||
.map_err(|err| err.into_with_command("GetBlockTime"))?
|
||||
.map_err(|err| err.into_with_request(request))?
|
||||
}
|
||||
|
||||
pub fn get_epoch_info(&self) -> ClientResult<RpcEpochInfo> {
|
||||
@@ -357,13 +296,7 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<RpcEpochInfo> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetEpochInfo, json!([commitment_config]), 0)
|
||||
.map_err(|err| err.into_with_command("GetEpochInfo"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetEpochInfo"))
|
||||
self.send(RpcRequest::GetEpochInfo, json!([commitment_config]), 0)
|
||||
}
|
||||
|
||||
pub fn get_leader_schedule(
|
||||
@@ -378,81 +311,43 @@ impl RpcClient {
|
||||
slot: Option<Slot>,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetLeaderSchedule,
|
||||
json!([slot, commitment_config]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetLeaderSchedule"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetLeaderSchedule"))
|
||||
self.send(
|
||||
RpcRequest::GetLeaderSchedule,
|
||||
json!([slot, commitment_config]),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetEpochSchedule, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetEpochSchedule"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetEpochSchedule"))
|
||||
self.send(RpcRequest::GetEpochSchedule, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn get_identity(&self) -> ClientResult<Pubkey> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetIdentity, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetIdentity"))?;
|
||||
let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null, 0)?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetIdentity"))
|
||||
.and_then(|rpc_identity: RpcIdentity| {
|
||||
rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
|
||||
ClientError::new_with_command(
|
||||
RpcError::ParseError("Pubkey".to_string()).into(),
|
||||
"GetIdentity",
|
||||
)
|
||||
})
|
||||
})
|
||||
rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
|
||||
ClientError::new_with_request(
|
||||
RpcError::ParseError("Pubkey".to_string()).into(),
|
||||
RpcRequest::GetIdentity,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_inflation(&self) -> ClientResult<Inflation> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetInflation, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetInflation"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetInflation"))
|
||||
self.send(RpcRequest::GetInflation, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn get_version(&self) -> ClientResult<RpcVersionInfo> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetVersion, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetVersion"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetVersion"))
|
||||
self.send(RpcRequest::GetVersion, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::MinimumLedgerSlot, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("MinimumLedgerSlot"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "MinimumLedgerSlot"))
|
||||
self.send(RpcRequest::MinimumLedgerSlot, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn send_and_confirm_transaction<T: Signers>(
|
||||
pub fn send_and_confirm_transaction(
|
||||
&self,
|
||||
transaction: &mut Transaction,
|
||||
signer_keys: &T,
|
||||
transaction: &Transaction,
|
||||
) -> ClientResult<Signature> {
|
||||
let mut send_retries = 20;
|
||||
loop {
|
||||
@@ -476,11 +371,6 @@ impl RpcClient {
|
||||
send_retries = if let Some(result) = status.clone() {
|
||||
match result {
|
||||
Ok(_) => return Ok(signature),
|
||||
Err(TransactionError::AccountInUse) => {
|
||||
// Fetch a new blockhash and re-sign the transaction before sending it again
|
||||
self.resign_transaction(transaction, signer_keys)?;
|
||||
send_retries - 1
|
||||
}
|
||||
Err(_) => 0,
|
||||
}
|
||||
} else {
|
||||
@@ -491,7 +381,9 @@ impl RpcClient {
|
||||
return Err(err.unwrap_err().into());
|
||||
} else {
|
||||
return Err(
|
||||
RpcError::ForUser("unable to confirm transaction. This can happen in situations such as transaction expiration and insufficient fee-payer funds".to_string()).into(),
|
||||
RpcError::ForUser("unable to confirm transaction. \
|
||||
This can happen in situations such as transaction expiration \
|
||||
and insufficient fee-payer funds".to_string()).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -582,18 +474,15 @@ impl RpcClient {
|
||||
pubkey: &Pubkey,
|
||||
retries: usize,
|
||||
) -> Result<Option<u64>, Box<dyn error::Error>> {
|
||||
let request = RpcRequest::GetBalance;
|
||||
let balance_json = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetBalance,
|
||||
json!([pubkey.to_string()]),
|
||||
retries,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("RetryGetBalance"))?;
|
||||
.send(request, json!([pubkey.to_string()]), retries)
|
||||
.map_err(|err| err.into_with_request(request))?;
|
||||
|
||||
Ok(Some(
|
||||
serde_json::from_value::<Response<u64>>(balance_json)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "RetryGetBalance"))?
|
||||
.map_err(|err| ClientError::new_with_request(err.into(), request))?
|
||||
.value,
|
||||
))
|
||||
}
|
||||
@@ -610,7 +499,7 @@ impl RpcClient {
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<Option<Account>> {
|
||||
let response = self.client.send(
|
||||
&RpcRequest::GetAccountInfo,
|
||||
RpcRequest::GetAccountInfo,
|
||||
json!([pubkey.to_string(), commitment_config]),
|
||||
0,
|
||||
);
|
||||
@@ -646,18 +535,14 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult<u64> {
|
||||
let request = RpcRequest::GetMinimumBalanceForRentExemption;
|
||||
let minimum_balance_json = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetMinimumBalanceForRentExemption,
|
||||
json!([data_len]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetMinimumBalanceForRentExemption"))?;
|
||||
.send(request, json!([data_len]), 0)
|
||||
.map_err(|err| err.into_with_request(request))?;
|
||||
|
||||
let minimum_balance: u64 = serde_json::from_value(minimum_balance_json).map_err(|err| {
|
||||
ClientError::new_with_command(err.into(), "GetMinimumBalanceForRentExemption")
|
||||
})?;
|
||||
let minimum_balance: u64 = serde_json::from_value(minimum_balance_json)
|
||||
.map_err(|err| ClientError::new_with_request(err.into(), request))?;
|
||||
trace!(
|
||||
"Response minimum balance {:?} {:?}",
|
||||
data_len,
|
||||
@@ -678,39 +563,25 @@ impl RpcClient {
|
||||
pubkey: &Pubkey,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<u64> {
|
||||
let balance_json = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetBalance,
|
||||
json!([pubkey.to_string(), commitment_config]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetBalance"))?;
|
||||
|
||||
serde_json::from_value::<Response<u64>>(balance_json)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetBalance"))
|
||||
self.send(
|
||||
RpcRequest::GetBalance,
|
||||
json!([pubkey.to_string(), commitment_config]),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetProgramAccounts,
|
||||
json!([pubkey.to_string()]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetProgramAccounts"))?;
|
||||
|
||||
let accounts: Vec<RpcKeyedAccount> =
|
||||
serde_json::from_value::<Vec<RpcKeyedAccount>>(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetProgramAccounts"))?;
|
||||
|
||||
let accounts: Vec<RpcKeyedAccount> = self.send(
|
||||
RpcRequest::GetProgramAccounts,
|
||||
json!([pubkey.to_string()]),
|
||||
0,
|
||||
)?;
|
||||
let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new();
|
||||
for RpcKeyedAccount { pubkey, account } in accounts.into_iter() {
|
||||
let pubkey = pubkey.parse().map_err(|_| {
|
||||
ClientError::new_with_command(
|
||||
ClientError::new_with_request(
|
||||
RpcError::ParseError("Pubkey".to_string()).into(),
|
||||
"GetProgramAccounts",
|
||||
RpcRequest::GetProgramAccounts,
|
||||
)
|
||||
})?;
|
||||
pubkey_accounts.push((pubkey, account.decode().unwrap()));
|
||||
@@ -727,17 +598,11 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> ClientResult<u64> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetTransactionCount,
|
||||
json!([commitment_config]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetTransactionCount"))?;
|
||||
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetTransactionCount"))
|
||||
self.send(
|
||||
RpcRequest::GetTransactionCount,
|
||||
json!([commitment_config]),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> {
|
||||
@@ -750,15 +615,6 @@ impl RpcClient {
|
||||
&self,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> RpcResult<(Hash, FeeCalculator)> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetRecentBlockhash,
|
||||
json!([commitment_config]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetRecentBlockhash"))?;
|
||||
|
||||
let Response {
|
||||
context,
|
||||
value:
|
||||
@@ -766,12 +622,16 @@ impl RpcClient {
|
||||
blockhash,
|
||||
fee_calculator,
|
||||
},
|
||||
} = serde_json::from_value::<Response<RpcBlockhashFeeCalculator>>(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetRecentBlockhash"))?;
|
||||
} = self.send::<Response<RpcBlockhashFeeCalculator>>(
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
json!([commitment_config]),
|
||||
0,
|
||||
)?;
|
||||
|
||||
let blockhash = blockhash.parse().map_err(|_| {
|
||||
ClientError::new_with_command(
|
||||
ClientError::new_with_request(
|
||||
RpcError::ParseError("Hash".to_string()).into(),
|
||||
"GetRecentBlockhash",
|
||||
RpcRequest::GetRecentBlockhash,
|
||||
)
|
||||
})?;
|
||||
Ok(Response {
|
||||
@@ -784,31 +644,25 @@ impl RpcClient {
|
||||
&self,
|
||||
blockhash: &Hash,
|
||||
) -> ClientResult<Option<FeeCalculator>> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetFeeCalculatorForBlockhash,
|
||||
json!([blockhash.to_string()]),
|
||||
0,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetFeeCalculatorForBlockhash"))?;
|
||||
let Response { value, .. } = serde_json::from_value::<Response<Option<RpcFeeCalculator>>>(
|
||||
response,
|
||||
)
|
||||
.map_err(|e| ClientError::new_with_command(e.into(), "GetFeeCalculatorForBlockhash"))?;
|
||||
let Response { value, .. } = self.send::<Response<Option<RpcFeeCalculator>>>(
|
||||
RpcRequest::GetFeeCalculatorForBlockhash,
|
||||
json!([blockhash.to_string()]),
|
||||
0,
|
||||
)?;
|
||||
|
||||
Ok(value.map(|rf| rf.fee_calculator))
|
||||
}
|
||||
|
||||
pub fn get_fee_rate_governor(&self) -> RpcResult<FeeRateGovernor> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetFeeRateGovernor, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetFeeRateGovernor"))?;
|
||||
let Response {
|
||||
context,
|
||||
value: RpcFeeRateGovernor { fee_rate_governor },
|
||||
} = serde_json::from_value::<Response<RpcFeeRateGovernor>>(response)
|
||||
.map_err(|e| ClientError::new_with_command(e.into(), "GetFeeRateGovernor"))?;
|
||||
} = self.send::<Response<RpcFeeRateGovernor>>(
|
||||
RpcRequest::GetFeeRateGovernor,
|
||||
Value::Null,
|
||||
0,
|
||||
)?;
|
||||
|
||||
Ok(Response {
|
||||
context,
|
||||
value: fee_rate_governor,
|
||||
@@ -842,18 +696,11 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
pub fn get_genesis_hash(&self) -> ClientResult<Hash> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::GetGenesisHash, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("GetGenesisHash"))?;
|
||||
|
||||
let hash = serde_json::from_value::<String>(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetGenesisHash"))?;
|
||||
|
||||
let hash = hash.parse().map_err(|_| {
|
||||
ClientError::new_with_command(
|
||||
let hash_str: String = self.send(RpcRequest::GetGenesisHash, Value::Null, 0)?;
|
||||
let hash = hash_str.parse().map_err(|_| {
|
||||
ClientError::new_with_request(
|
||||
RpcError::ParseError("Hash".to_string()).into(),
|
||||
"GetGenesisHash",
|
||||
RpcRequest::GetGenesisHash,
|
||||
)
|
||||
})?;
|
||||
Ok(hash)
|
||||
@@ -909,7 +756,7 @@ impl RpcClient {
|
||||
return balance_result.ok();
|
||||
}
|
||||
trace!(
|
||||
"retry_get_balance[{}] {:?} {:?}",
|
||||
"wait_for_balance_with_commitment [{}] {:?} {:?}",
|
||||
run,
|
||||
balance_result,
|
||||
expected_balance
|
||||
@@ -1042,23 +889,18 @@ impl RpcClient {
|
||||
&self,
|
||||
signature: &Signature,
|
||||
) -> ClientResult<usize> {
|
||||
let response = self
|
||||
.client
|
||||
.send(
|
||||
&RpcRequest::GetSignatureStatuses,
|
||||
json!([[signature.to_string()]]),
|
||||
5,
|
||||
)
|
||||
.map_err(|err| err.into_with_command("GetSignatureStatuses"))?;
|
||||
let result: Response<Vec<Option<TransactionStatus>>> = serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
|
||||
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
||||
RpcRequest::GetSignatureStatuses,
|
||||
json!([[signature.to_string()]]),
|
||||
5,
|
||||
)?;
|
||||
|
||||
let confirmations = result.value[0]
|
||||
.clone()
|
||||
.ok_or_else(|| {
|
||||
ClientError::new_with_command(
|
||||
ClientError::new_with_request(
|
||||
ClientErrorKind::Custom("signature not found".to_string()),
|
||||
"GetSignatureStatuses",
|
||||
RpcRequest::GetSignatureStatuses,
|
||||
)
|
||||
})?
|
||||
.confirmations
|
||||
@@ -1066,10 +908,9 @@ impl RpcClient {
|
||||
Ok(confirmations)
|
||||
}
|
||||
|
||||
pub fn send_and_confirm_transaction_with_spinner<T: Signers>(
|
||||
pub fn send_and_confirm_transaction_with_spinner(
|
||||
&self,
|
||||
transaction: &mut Transaction,
|
||||
signer_keys: &T,
|
||||
transaction: &Transaction,
|
||||
) -> ClientResult<Signature> {
|
||||
let mut confirmations = 0;
|
||||
|
||||
@@ -1106,11 +947,6 @@ impl RpcClient {
|
||||
send_retries = if let Some(result) = status.clone() {
|
||||
match result {
|
||||
Ok(_) => 0,
|
||||
Err(TransactionError::AccountInUse) => {
|
||||
// Fetch a new blockhash and re-sign the transaction before sending it again
|
||||
self.resign_transaction(transaction, signer_keys)?;
|
||||
send_retries - 1
|
||||
}
|
||||
// If transaction errors, return right away; no point in counting confirmations
|
||||
Err(_) => 0,
|
||||
}
|
||||
@@ -1128,9 +964,13 @@ impl RpcClient {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(
|
||||
RpcError::ForUser("unable to confirm transaction. This can happen in situations such as transaction expiration and insufficient fee-payer funds".to_string()).into(),
|
||||
);
|
||||
return Err(RpcError::ForUser(
|
||||
"unable to confirm transaction. \
|
||||
This can happen in situations such as transaction \
|
||||
expiration and insufficient fee-payer funds"
|
||||
.to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1155,24 +995,29 @@ impl RpcClient {
|
||||
.unwrap_or(confirmations);
|
||||
if now.elapsed().as_secs() >= MAX_HASH_AGE_IN_SECONDS as u64 {
|
||||
return Err(
|
||||
RpcError::ForUser("transaction not finalized. This can happen when a transaction lands in an abandoned fork. Please retry.".to_string()).into(),
|
||||
RpcError::ForUser("transaction not finalized. \
|
||||
This can happen when a transaction lands in an abandoned fork. \
|
||||
Please retry.".to_string()).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validator_exit(&self) -> ClientResult<bool> {
|
||||
let response = self
|
||||
.client
|
||||
.send(&RpcRequest::ValidatorExit, Value::Null, 0)
|
||||
.map_err(|err| err.into_with_command("ValidatorExit"))?;
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_command(err.into(), "ValidatorExit"))
|
||||
self.send(RpcRequest::ValidatorExit, Value::Null, 0)
|
||||
}
|
||||
|
||||
pub fn send(&self, request: &RpcRequest, params: Value, retries: usize) -> ClientResult<Value> {
|
||||
pub fn send<T>(&self, request: RpcRequest, params: Value, retries: usize) -> ClientResult<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
assert!(params.is_array() || params.is_null());
|
||||
self.client.send(request, params, retries)
|
||||
let response = self
|
||||
.client
|
||||
.send(request, params, retries)
|
||||
.map_err(|err| err.into_with_request(request))?;
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_request(err.into(), request))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,21 +1087,23 @@ mod tests {
|
||||
let rpc_addr = receiver.recv().unwrap();
|
||||
let rpc_client = RpcClient::new_socket(rpc_addr);
|
||||
|
||||
let balance = rpc_client.send(
|
||||
&RpcRequest::GetBalance,
|
||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
|
||||
0,
|
||||
);
|
||||
assert_eq!(balance.unwrap().as_u64().unwrap(), 50);
|
||||
let balance: u64 = rpc_client
|
||||
.send(
|
||||
RpcRequest::GetBalance,
|
||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(balance, 50);
|
||||
|
||||
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, Value::Null, 0);
|
||||
assert_eq!(
|
||||
blockhash.unwrap().as_str().unwrap(),
|
||||
"deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"
|
||||
);
|
||||
let blockhash: String = rpc_client
|
||||
.send(RpcRequest::GetRecentBlockhash, Value::Null, 0)
|
||||
.unwrap();
|
||||
assert_eq!(blockhash, "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
|
||||
|
||||
// Send erroneous parameter
|
||||
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, json!(["parameter"]), 0);
|
||||
let blockhash: ClientResult<String> =
|
||||
rpc_client.send(RpcRequest::GetRecentBlockhash, json!(["parameter"]), 0);
|
||||
assert_eq!(blockhash.is_err(), true);
|
||||
}
|
||||
|
||||
@@ -1290,12 +1137,14 @@ mod tests {
|
||||
let rpc_addr = receiver.recv().unwrap();
|
||||
let rpc_client = RpcClient::new_socket(rpc_addr);
|
||||
|
||||
let balance = rpc_client.send(
|
||||
&RpcRequest::GetBalance,
|
||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]),
|
||||
10,
|
||||
);
|
||||
assert_eq!(balance.unwrap().as_u64().unwrap(), 5);
|
||||
let balance: u64 = rpc_client
|
||||
.send(
|
||||
RpcRequest::GetBalance,
|
||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]),
|
||||
10,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(balance, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1358,17 +1207,16 @@ mod tests {
|
||||
let key = Keypair::new();
|
||||
let to = Pubkey::new_rand();
|
||||
let blockhash = Hash::default();
|
||||
let mut tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||
let result = rpc_client.send_and_confirm_transaction(&tx);
|
||||
result.unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_mock("account_in_use".to_string());
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&tx);
|
||||
assert!(result.is_err());
|
||||
|
||||
let rpc_client = RpcClient::new_mock("instruction_error".to_string());
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&tx);
|
||||
assert_matches!(
|
||||
result.unwrap_err().kind(),
|
||||
ClientErrorKind::TransactionError(TransactionError::InstructionError(
|
||||
@@ -1378,7 +1226,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let rpc_client = RpcClient::new_mock("sig_not_found".to_string());
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&tx);
|
||||
if let ClientErrorKind::Io(err) = result.unwrap_err().kind() {
|
||||
assert_eq!(err.kind(), io::ErrorKind::Other);
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ impl RpcClientRequest {
|
||||
impl GenericRpcClientRequest for RpcClientRequest {
|
||||
fn send(
|
||||
&self,
|
||||
request: &RpcRequest,
|
||||
request: RpcRequest,
|
||||
params: serde_json::Value,
|
||||
mut retries: usize,
|
||||
) -> Result<serde_json::Value> {
|
||||
|
@@ -1,7 +1,8 @@
|
||||
use serde_json::{json, Value};
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum RpcRequest {
|
||||
DeregisterNode,
|
||||
ValidatorExit,
|
||||
@@ -30,6 +31,7 @@ pub enum RpcRequest {
|
||||
GetStorageTurnRate,
|
||||
GetSlotsPerSegment,
|
||||
GetStoragePubkeysForSlot,
|
||||
GetSupply,
|
||||
GetTotalSupply,
|
||||
GetTransactionCount,
|
||||
GetVersion,
|
||||
@@ -42,12 +44,8 @@ pub enum RpcRequest {
|
||||
MinimumLedgerSlot,
|
||||
}
|
||||
|
||||
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
|
||||
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
|
||||
|
||||
impl RpcRequest {
|
||||
pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value {
|
||||
let jsonrpc = "2.0";
|
||||
impl fmt::Display for RpcRequest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let method = match self {
|
||||
RpcRequest::DeregisterNode => "deregisterNode",
|
||||
RpcRequest::ValidatorExit => "validatorExit",
|
||||
@@ -76,6 +74,7 @@ impl RpcRequest {
|
||||
RpcRequest::GetStorageTurnRate => "getStorageTurnRate",
|
||||
RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment",
|
||||
RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
|
||||
RpcRequest::GetSupply => "getSupply",
|
||||
RpcRequest::GetTotalSupply => "getTotalSupply",
|
||||
RpcRequest::GetTransactionCount => "getTransactionCount",
|
||||
RpcRequest::GetVersion => "getVersion",
|
||||
@@ -87,10 +86,21 @@ impl RpcRequest {
|
||||
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
|
||||
RpcRequest::MinimumLedgerSlot => "minimumLedgerSlot",
|
||||
};
|
||||
|
||||
write!(f, "{}", method)
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
|
||||
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
|
||||
|
||||
impl RpcRequest {
|
||||
pub(crate) fn build_request_json(self, id: u64, params: Value) -> Value {
|
||||
let jsonrpc = "2.0";
|
||||
json!({
|
||||
"jsonrpc": jsonrpc,
|
||||
"id": id,
|
||||
"method": method,
|
||||
"method": format!("{}", self),
|
||||
"params": params,
|
||||
})
|
||||
}
|
||||
|
@@ -108,6 +108,8 @@ pub struct RpcContactInfo {
|
||||
pub tpu: Option<SocketAddr>,
|
||||
/// JSON RPC port
|
||||
pub rpc: Option<SocketAddr>,
|
||||
/// Software version
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
|
||||
@@ -199,3 +201,12 @@ pub struct RpcAccountBalance {
|
||||
pub address: String,
|
||||
pub lamports: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcSupply {
|
||||
pub total: u64,
|
||||
pub circulating: u64,
|
||||
pub non_circulating: u64,
|
||||
pub non_circulating_accounts: Vec<String>,
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "../README.md"
|
||||
@@ -41,36 +41,37 @@ regex = "1.3.6"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.48"
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.10" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.1.11" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.11" }
|
||||
ed25519-dalek = "=1.0.0-pre.3"
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-measure = { path = "../measure", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-chacha-cuda = { path = "../chacha-cuda", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.1.10" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-measure = { path = "../measure", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-chacha-cuda = { path = "../chacha-cuda", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
solana-streamer = { path = "../streamer", version = "1.1.11" }
|
||||
solana-version = { path = "../version", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
solana-vote-signer = { path = "../vote-signer", version = "1.1.11" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.1.11" }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0"
|
||||
tokio = "0.1"
|
||||
tokio-codec = "0.1"
|
||||
tokio-fs = "0.1"
|
||||
tokio-io = "0.1"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.10" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.11" }
|
||||
trees = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -18,8 +18,8 @@ use crate::{
|
||||
crds_gossip_error::CrdsGossipError,
|
||||
crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
|
||||
crds_value::{
|
||||
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash, Vote,
|
||||
MAX_WALLCLOCK,
|
||||
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash,
|
||||
Version, Vote, MAX_WALLCLOCK,
|
||||
},
|
||||
epoch_slots::EpochSlots,
|
||||
result::{Error, Result},
|
||||
@@ -378,6 +378,7 @@ impl ClusterInfo {
|
||||
archivers += 1;
|
||||
}
|
||||
|
||||
let node_version = self.get_node_version(&node.id);
|
||||
if my_shred_version != 0 && (node.shred_version != 0 && node.shred_version != my_shred_version) {
|
||||
different_shred_nodes += 1;
|
||||
None
|
||||
@@ -393,10 +394,9 @@ impl ClusterInfo {
|
||||
"none".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
let ip_addr = node.gossip.ip();
|
||||
Some(format!(
|
||||
"{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n",
|
||||
"{:15} {:2}| {:5} | {:44} |{:^15}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {:5}| {}\n",
|
||||
if ContactInfo::is_valid_address(&node.gossip) {
|
||||
ip_addr.to_string()
|
||||
} else {
|
||||
@@ -405,6 +405,11 @@ impl ClusterInfo {
|
||||
if node.id == my_pubkey { "me" } else { "" }.to_string(),
|
||||
now.saturating_sub(last_updated),
|
||||
node.id.to_string(),
|
||||
if let Some(node_version) = node_version {
|
||||
node_version.to_string()
|
||||
} else {
|
||||
"-".to_string()
|
||||
},
|
||||
addr_to_string(&ip_addr, &node.gossip),
|
||||
addr_to_string(&ip_addr, &node.tpu),
|
||||
addr_to_string(&ip_addr, &node.tpu_forwards),
|
||||
@@ -412,7 +417,6 @@ impl ClusterInfo {
|
||||
addr_to_string(&ip_addr, &node.tvu_forwards),
|
||||
addr_to_string(&ip_addr, &node.repair),
|
||||
addr_to_string(&ip_addr, &node.serve_repair),
|
||||
addr_to_string(&ip_addr, &node.storage_addr),
|
||||
addr_to_string(&ip_addr, &node.rpc),
|
||||
addr_to_string(&ip_addr, &node.rpc_pubsub),
|
||||
node.shred_version,
|
||||
@@ -423,9 +427,9 @@ impl ClusterInfo {
|
||||
|
||||
format!(
|
||||
"IP Address |Age(ms)| Node identifier \
|
||||
|Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR|Storag| RPC |PubSub|ShredVer\n\
|
||||
------------------+-------+----------------------------------------------+\
|
||||
------+------+------+------+------+------+------+------+------+------+--------\n\
|
||||
| Version |Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR| RPC |PubSub|ShredVer\n\
|
||||
------------------+-------+----------------------------------------------+---------------+\
|
||||
------+------+------+------+------+------+------+------+------+--------\n\
|
||||
{}\
|
||||
Nodes: {}{}{}{}",
|
||||
nodes.join(""),
|
||||
@@ -440,7 +444,7 @@ impl ClusterInfo {
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
if spy_nodes > 0 {
|
||||
if different_shred_nodes > 0 {
|
||||
format!(
|
||||
"\nNodes with different shred version: {}",
|
||||
different_shred_nodes
|
||||
@@ -703,6 +707,18 @@ impl ClusterInfo {
|
||||
(vec, max)
|
||||
}
|
||||
|
||||
pub fn get_node_version(&self, pubkey: &Pubkey) -> Option<solana_version::Version> {
|
||||
self.gossip
|
||||
.read()
|
||||
.unwrap()
|
||||
.crds
|
||||
.table
|
||||
.get(&CrdsValueLabel::Version(*pubkey))
|
||||
.map(|x| x.value.version())
|
||||
.flatten()
|
||||
.map(|version| version.version.clone())
|
||||
}
|
||||
|
||||
/// all validators that have a valid rpc port regardless of `shred_version`.
|
||||
pub fn all_rpc_peers(&self) -> Vec<ContactInfo> {
|
||||
self.gossip
|
||||
@@ -1313,6 +1329,9 @@ impl ClusterInfo {
|
||||
let mut last_contact_info_trace = timestamp();
|
||||
let mut adopt_shred_version = obj.my_shred_version() == 0;
|
||||
let recycler = PacketsRecycler::default();
|
||||
|
||||
let message = CrdsData::Version(Version::new(obj.id()));
|
||||
obj.push_message(CrdsValue::new_signed(message, &obj.keypair));
|
||||
loop {
|
||||
let start = timestamp();
|
||||
thread_mem_usage::datapoint("solana-gossip");
|
||||
|
@@ -75,6 +75,7 @@ pub enum CrdsData {
|
||||
SnapshotHashes(SnapshotHash),
|
||||
AccountsHashes(SnapshotHash),
|
||||
EpochSlots(EpochSlotsIndex, EpochSlots),
|
||||
Version(Version),
|
||||
}
|
||||
|
||||
impl Sanitize for CrdsData {
|
||||
@@ -101,6 +102,7 @@ impl Sanitize for CrdsData {
|
||||
}
|
||||
val.sanitize()
|
||||
}
|
||||
CrdsData::Version(version) => version.sanitize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,6 +208,33 @@ impl Vote {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
pub struct Version {
|
||||
pub from: Pubkey,
|
||||
pub wallclock: u64,
|
||||
pub version: solana_version::Version,
|
||||
}
|
||||
|
||||
impl Sanitize for Version {
|
||||
fn sanitize(&self) -> Result<(), SanitizeError> {
|
||||
if self.wallclock >= MAX_WALLCLOCK {
|
||||
return Err(SanitizeError::ValueOutOfBounds);
|
||||
}
|
||||
self.from.sanitize()?;
|
||||
self.version.sanitize()
|
||||
}
|
||||
}
|
||||
|
||||
impl Version {
|
||||
pub fn new(from: Pubkey) -> Self {
|
||||
Self {
|
||||
from,
|
||||
wallclock: timestamp(),
|
||||
version: solana_version::Version::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of the replicated value
|
||||
/// These are labels for values in a record that is associated with `Pubkey`
|
||||
#[derive(PartialEq, Hash, Eq, Clone, Debug)]
|
||||
@@ -216,6 +245,7 @@ pub enum CrdsValueLabel {
|
||||
SnapshotHashes(Pubkey),
|
||||
EpochSlots(EpochSlotsIndex, Pubkey),
|
||||
AccountsHashes(Pubkey),
|
||||
Version(Pubkey),
|
||||
}
|
||||
|
||||
impl fmt::Display for CrdsValueLabel {
|
||||
@@ -227,6 +257,7 @@ impl fmt::Display for CrdsValueLabel {
|
||||
CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()),
|
||||
CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()),
|
||||
CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", self.pubkey()),
|
||||
CrdsValueLabel::Version(_) => write!(f, "Version({})", self.pubkey()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,6 +271,7 @@ impl CrdsValueLabel {
|
||||
CrdsValueLabel::SnapshotHashes(p) => *p,
|
||||
CrdsValueLabel::EpochSlots(_, p) => *p,
|
||||
CrdsValueLabel::AccountsHashes(p) => *p,
|
||||
CrdsValueLabel::Version(p) => *p,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,7 +289,7 @@ impl CrdsValue {
|
||||
value.sign(keypair);
|
||||
value
|
||||
}
|
||||
/// Totally unsecure unverfiable wallclock of the node that generated this message
|
||||
/// Totally unsecure unverifiable wallclock of the node that generated this message
|
||||
/// Latest wallclock is always picked.
|
||||
/// This is used to time out push messages.
|
||||
pub fn wallclock(&self) -> u64 {
|
||||
@@ -268,6 +300,7 @@ impl CrdsValue {
|
||||
CrdsData::SnapshotHashes(hash) => hash.wallclock,
|
||||
CrdsData::AccountsHashes(hash) => hash.wallclock,
|
||||
CrdsData::EpochSlots(_, p) => p.wallclock,
|
||||
CrdsData::Version(version) => version.wallclock,
|
||||
}
|
||||
}
|
||||
pub fn pubkey(&self) -> Pubkey {
|
||||
@@ -278,6 +311,7 @@ impl CrdsValue {
|
||||
CrdsData::SnapshotHashes(hash) => hash.from,
|
||||
CrdsData::AccountsHashes(hash) => hash.from,
|
||||
CrdsData::EpochSlots(_, p) => p.from,
|
||||
CrdsData::Version(version) => version.from,
|
||||
}
|
||||
}
|
||||
pub fn label(&self) -> CrdsValueLabel {
|
||||
@@ -288,6 +322,7 @@ impl CrdsValue {
|
||||
CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()),
|
||||
CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()),
|
||||
CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()),
|
||||
CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()),
|
||||
}
|
||||
}
|
||||
pub fn contact_info(&self) -> Option<&ContactInfo> {
|
||||
@@ -338,6 +373,13 @@ impl CrdsValue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Option<&Version> {
|
||||
match &self.data {
|
||||
CrdsData::Version(version) => Some(version),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return all the possible labels for a record identified by Pubkey.
|
||||
pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> {
|
||||
let mut labels = vec![
|
||||
@@ -345,6 +387,7 @@ impl CrdsValue {
|
||||
CrdsValueLabel::LowestSlot(*key),
|
||||
CrdsValueLabel::SnapshotHashes(*key),
|
||||
CrdsValueLabel::AccountsHashes(*key),
|
||||
CrdsValueLabel::Version(*key),
|
||||
];
|
||||
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
|
||||
labels.extend((0..MAX_EPOCH_SLOTS).map(|ix| CrdsValueLabel::EpochSlots(ix, *key)));
|
||||
@@ -395,7 +438,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_labels() {
|
||||
let mut hits = [false; 4 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize];
|
||||
let mut hits = [false; 5 + MAX_VOTES as usize + MAX_EPOCH_SLOTS as usize];
|
||||
// this method should cover all the possible labels
|
||||
for v in &CrdsValue::record_labels(&Pubkey::default()) {
|
||||
match v {
|
||||
@@ -403,9 +446,10 @@ mod test {
|
||||
CrdsValueLabel::LowestSlot(_) => hits[1] = true,
|
||||
CrdsValueLabel::SnapshotHashes(_) => hits[2] = true,
|
||||
CrdsValueLabel::AccountsHashes(_) => hits[3] = true,
|
||||
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 4] = true,
|
||||
CrdsValueLabel::Version(_) => hits[4] = true,
|
||||
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 5] = true,
|
||||
CrdsValueLabel::EpochSlots(ix, _) => {
|
||||
hits[*ix as usize + MAX_VOTES as usize + 4] = true
|
||||
hits[*ix as usize + MAX_VOTES as usize + 5] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ pub mod gen_keys;
|
||||
pub mod gossip_service;
|
||||
pub mod ledger_cleanup_service;
|
||||
pub mod local_vote_signer_service;
|
||||
pub mod non_circulating_supply;
|
||||
pub mod poh_recorder;
|
||||
pub mod poh_service;
|
||||
pub mod progress_map;
|
||||
@@ -39,6 +40,7 @@ mod result;
|
||||
pub mod retransmit_stage;
|
||||
pub mod rewards_recorder_service;
|
||||
pub mod rpc;
|
||||
pub mod rpc_error;
|
||||
pub mod rpc_pubsub;
|
||||
pub mod rpc_pubsub_service;
|
||||
pub mod rpc_service;
|
||||
|
193
core/src/non_circulating_supply.rs
Normal file
193
core/src/non_circulating_supply.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_stake_program::stake_state::StakeState;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
pub struct NonCirculatingSupply {
|
||||
pub lamports: u64,
|
||||
pub accounts: Vec<Pubkey>,
|
||||
}
|
||||
|
||||
pub fn calculate_non_circulating_supply(bank: Arc<Bank>) -> NonCirculatingSupply {
|
||||
debug!("Updating Bank supply, epoch: {}", bank.epoch());
|
||||
let mut non_circulating_accounts_set: HashSet<Pubkey> = HashSet::new();
|
||||
|
||||
for key in non_circulating_accounts() {
|
||||
non_circulating_accounts_set.insert(key);
|
||||
}
|
||||
|
||||
let clock = bank.clock();
|
||||
let stake_accounts = bank.get_program_accounts(Some(&solana_stake_program::id()));
|
||||
for (pubkey, account) in stake_accounts.iter() {
|
||||
let stake_account = StakeState::from(&account).unwrap_or_default();
|
||||
match stake_account {
|
||||
StakeState::Initialized(meta) => {
|
||||
if meta.lockup.is_in_force(&clock, &HashSet::default())
|
||||
|| meta.authorized.withdrawer == withdraw_authority()
|
||||
{
|
||||
non_circulating_accounts_set.insert(*pubkey);
|
||||
}
|
||||
}
|
||||
StakeState::Stake(meta, _stake) => {
|
||||
if meta.lockup.is_in_force(&clock, &HashSet::default())
|
||||
|| meta.authorized.withdrawer == withdraw_authority()
|
||||
{
|
||||
non_circulating_accounts_set.insert(*pubkey);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let lamports = non_circulating_accounts_set
|
||||
.iter()
|
||||
.fold(0, |acc, pubkey| acc + bank.get_balance(&pubkey));
|
||||
|
||||
NonCirculatingSupply {
|
||||
lamports,
|
||||
accounts: non_circulating_accounts_set.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
// Mainnet-beta accounts that should be considered non-circulating
|
||||
solana_sdk::pubkeys!(
|
||||
non_circulating_accounts,
|
||||
[
|
||||
"9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA",
|
||||
"GK2zqSsXLA2rwVZk347RYhh6jJpRsCA69FjLW93ZGi3B",
|
||||
"HCV5dGFJXRrJ3jhDYA4DCeb9TEDTwGGYXtT3wHksu2Zr",
|
||||
"25odAafVXnd63L6Hq5Cx6xGmhKqkhE2y6UrLVuqUfWZj",
|
||||
"14FUT96s9swbmH7ZjpDvfEDywnAYy9zaNhv4xvezySGu",
|
||||
"HbZ5FfmKWNHC7uwk6TF1hVi6TCs7dtYfdjEcuPGgzFAg",
|
||||
"C7C8odR8oashR5Feyrq2tJKaXL18id1dSj2zbkDGL2C2",
|
||||
"APnSR52EC1eH676m7qTBHUJ1nrGpHYpV7XKPxgRDD8gX",
|
||||
"9ibqedFVnu5k4wo1mJRbH6KJ5HLBCyjpA9omPYkDeeT5",
|
||||
"FopBKzQkG9pkyQqjdMFBLMQ995pSkjy83ziR4aism4c6",
|
||||
"AiUHvJhTbMCcgFE2K26Ea9qCe74y3sFwqUt38iD5sfoR",
|
||||
"3DndE3W53QdHSfBJiSJgzDKGvKJBoQLVmRHvy5LtqYfG",
|
||||
"Eyr9P5XsjK2NUKNCnfu39eqpGoiLFgVAv1LSQgMZCwiQ",
|
||||
"DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ",
|
||||
"CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S",
|
||||
"7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2",
|
||||
"GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ",
|
||||
"Mc5XB47H3DKJHym5RLa9mPzWv5snERsF3KNv5AauXK8",
|
||||
"7cvkjYAkUYs4W8XcXsca7cBrEGFeSUjeZmKoNBvEwyri",
|
||||
"AG3m2bAibcY8raMt4oXEGqRHwX4FWKPPJVjZxn1LySDX",
|
||||
"5XdtyEDREHJXXW1CTtCsVjJRjBapAwK78ZquzvnNVRrV",
|
||||
"6yKHERk8rsbmJxvMpPuwPs1ct3hRiP7xaJF2tvnGU6nK",
|
||||
"CHmdL15akDcJgBkY6BP3hzs98Dqr6wbdDC5p8odvtSbq",
|
||||
"FR84wZQy3Y3j2gWz6pgETUiUoJtreMEuWfbg6573UCj9",
|
||||
"5q54XjQ7vDx4y6KphPeE97LUNiYGtP55spjvXAWPGBuf",
|
||||
]
|
||||
);
|
||||
|
||||
// Withdraw authority for autostaked accounts on mainnet-beta
|
||||
solana_sdk::pubkeys!(
|
||||
withdraw_authority,
|
||||
"8CUUMKYNGxdgYio5CLHRHyzMEhhVRMcqefgE6dLqnVRK"
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_sdk::{
|
||||
account::Account, epoch_schedule::EpochSchedule, genesis_config::GenesisConfig,
|
||||
};
|
||||
use solana_stake_program::stake_state::{Authorized, Lockup, Meta, StakeState};
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
fn new_from_parent(parent: &Arc<Bank>) -> Bank {
|
||||
Bank::new_from_parent(parent, &Pubkey::default(), parent.slot() + 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_calculate_non_circulating_supply() {
|
||||
let mut accounts: BTreeMap<Pubkey, Account> = BTreeMap::new();
|
||||
let balance = 10;
|
||||
let num_genesis_accounts = 10;
|
||||
for _ in 0..num_genesis_accounts {
|
||||
accounts.insert(
|
||||
Pubkey::new_rand(),
|
||||
Account::new(balance, 0, &Pubkey::default()),
|
||||
);
|
||||
}
|
||||
let non_circulating_accounts = non_circulating_accounts();
|
||||
let num_non_circulating_accounts = non_circulating_accounts.len() as u64;
|
||||
for key in non_circulating_accounts.clone() {
|
||||
accounts.insert(key, Account::new(balance, 0, &Pubkey::default()));
|
||||
}
|
||||
|
||||
let num_stake_accounts = 3;
|
||||
for _ in 0..num_stake_accounts {
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let meta = Meta {
|
||||
authorized: Authorized::auto(&pubkey),
|
||||
lockup: Lockup {
|
||||
epoch: 1,
|
||||
..Lockup::default()
|
||||
},
|
||||
..Meta::default()
|
||||
};
|
||||
let stake_account = Account::new_data_with_space(
|
||||
balance,
|
||||
&StakeState::Initialized(meta),
|
||||
std::mem::size_of::<StakeState>(),
|
||||
&solana_stake_program::id(),
|
||||
)
|
||||
.unwrap();
|
||||
accounts.insert(pubkey, stake_account);
|
||||
}
|
||||
|
||||
let slots_per_epoch = 32;
|
||||
let genesis_config = GenesisConfig {
|
||||
accounts,
|
||||
epoch_schedule: EpochSchedule::new(slots_per_epoch),
|
||||
..GenesisConfig::default()
|
||||
};
|
||||
let mut bank = Arc::new(Bank::new(&genesis_config));
|
||||
assert_eq!(
|
||||
bank.capitalization(),
|
||||
(num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance
|
||||
);
|
||||
|
||||
let non_circulating_supply = calculate_non_circulating_supply(bank.clone());
|
||||
assert_eq!(
|
||||
non_circulating_supply.lamports,
|
||||
(num_non_circulating_accounts + num_stake_accounts) * balance
|
||||
);
|
||||
assert_eq!(
|
||||
non_circulating_supply.accounts.len(),
|
||||
num_non_circulating_accounts as usize + num_stake_accounts as usize
|
||||
);
|
||||
|
||||
bank = Arc::new(new_from_parent(&bank));
|
||||
let new_balance = 11;
|
||||
for key in non_circulating_accounts {
|
||||
bank.store_account(&key, &Account::new(new_balance, 0, &Pubkey::default()));
|
||||
}
|
||||
let non_circulating_supply = calculate_non_circulating_supply(bank.clone());
|
||||
assert_eq!(
|
||||
non_circulating_supply.lamports,
|
||||
(num_non_circulating_accounts * new_balance) + (num_stake_accounts * balance)
|
||||
);
|
||||
assert_eq!(
|
||||
non_circulating_supply.accounts.len(),
|
||||
num_non_circulating_accounts as usize + num_stake_accounts as usize
|
||||
);
|
||||
|
||||
// Advance bank an epoch, which should unlock stakes
|
||||
for _ in 0..slots_per_epoch {
|
||||
bank = Arc::new(new_from_parent(&bank));
|
||||
}
|
||||
assert_eq!(bank.epoch(), 1);
|
||||
let non_circulating_supply = calculate_non_circulating_supply(bank.clone());
|
||||
assert_eq!(
|
||||
non_circulating_supply.lamports,
|
||||
num_non_circulating_accounts * new_balance
|
||||
);
|
||||
assert_eq!(
|
||||
non_circulating_supply.accounts.len(),
|
||||
num_non_circulating_accounts as usize
|
||||
);
|
||||
}
|
||||
}
|
@@ -17,12 +17,15 @@ use solana_ledger::{
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_metrics::inc_new_counter_error;
|
||||
use solana_perf::packet::Packets;
|
||||
use solana_sdk::clock::Slot;
|
||||
use solana_sdk::epoch_schedule::EpochSchedule;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use solana_streamer::streamer::PacketReceiver;
|
||||
use std::{
|
||||
cmp,
|
||||
collections::{BTreeMap, HashMap},
|
||||
net::UdpSocket,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
sync::mpsc::channel,
|
||||
sync::mpsc::RecvTimeoutError,
|
||||
sync::Mutex,
|
||||
@@ -35,6 +38,115 @@ use std::{
|
||||
// it doesn't pull up too much work.
|
||||
const MAX_PACKET_BATCH_SIZE: usize = 100;
|
||||
|
||||
#[derive(Default)]
|
||||
struct RetransmitStats {
|
||||
total_packets: AtomicU64,
|
||||
total_batches: AtomicU64,
|
||||
total_time: AtomicU64,
|
||||
repair_total: AtomicU64,
|
||||
discard_total: AtomicU64,
|
||||
retransmit_total: AtomicU64,
|
||||
last_ts: AtomicU64,
|
||||
compute_turbine_peers_total: AtomicU64,
|
||||
packets_by_slot: Mutex<BTreeMap<Slot, usize>>,
|
||||
packets_by_source: Mutex<BTreeMap<String, usize>>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn update_retransmit_stats(
|
||||
stats: &Arc<RetransmitStats>,
|
||||
total_time: u64,
|
||||
total_packets: usize,
|
||||
retransmit_total: u64,
|
||||
discard_total: u64,
|
||||
repair_total: u64,
|
||||
compute_turbine_peers_total: u64,
|
||||
peers_len: usize,
|
||||
packets_by_slot: HashMap<Slot, usize>,
|
||||
packets_by_source: HashMap<String, usize>,
|
||||
) {
|
||||
stats.total_time.fetch_add(total_time, Ordering::Relaxed);
|
||||
stats
|
||||
.total_packets
|
||||
.fetch_add(total_packets as u64, Ordering::Relaxed);
|
||||
stats
|
||||
.retransmit_total
|
||||
.fetch_add(retransmit_total, Ordering::Relaxed);
|
||||
stats
|
||||
.repair_total
|
||||
.fetch_add(repair_total, Ordering::Relaxed);
|
||||
stats
|
||||
.discard_total
|
||||
.fetch_add(discard_total, Ordering::Relaxed);
|
||||
stats
|
||||
.compute_turbine_peers_total
|
||||
.fetch_add(compute_turbine_peers_total, Ordering::Relaxed);
|
||||
stats.total_batches.fetch_add(1, Ordering::Relaxed);
|
||||
{
|
||||
let mut stats_packets_by_slot = stats.packets_by_slot.lock().unwrap();
|
||||
for (slot, count) in packets_by_slot {
|
||||
*stats_packets_by_slot.entry(slot).or_insert(0) += count;
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut stats_packets_by_source = stats.packets_by_source.lock().unwrap();
|
||||
for (source, count) in packets_by_source {
|
||||
*stats_packets_by_source.entry(source).or_insert(0) += count;
|
||||
}
|
||||
}
|
||||
|
||||
let now = timestamp();
|
||||
let last = stats.last_ts.load(Ordering::Relaxed);
|
||||
if now - last > 2000 && stats.last_ts.compare_and_swap(last, now, Ordering::Relaxed) == last {
|
||||
datapoint_info!("retransmit-num_nodes", ("count", peers_len, i64));
|
||||
datapoint_info!(
|
||||
"retransmit-stage",
|
||||
(
|
||||
"total_time",
|
||||
stats.total_time.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"total_batches",
|
||||
stats.total_batches.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"total_packets",
|
||||
stats.total_packets.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"retransmit_total",
|
||||
stats.retransmit_total.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"compute_turbine",
|
||||
stats.compute_turbine_peers_total.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"repair_total",
|
||||
stats.repair_total.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
(
|
||||
"discard_total",
|
||||
stats.discard_total.swap(0, Ordering::Relaxed) as i64,
|
||||
i64
|
||||
),
|
||||
);
|
||||
let mut packets_by_slot = stats.packets_by_slot.lock().unwrap();
|
||||
info!("retransmit: packets_by_slot: {:#?}", packets_by_slot);
|
||||
packets_by_slot.clear();
|
||||
drop(packets_by_slot);
|
||||
let mut packets_by_source = stats.packets_by_source.lock().unwrap();
|
||||
info!("retransmit: packets_by_source: {:#?}", packets_by_source);
|
||||
packets_by_source.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn retransmit(
|
||||
bank_forks: &Arc<RwLock<BankForks>>,
|
||||
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
||||
@@ -42,6 +154,7 @@ fn retransmit(
|
||||
r: &Arc<Mutex<PacketReceiver>>,
|
||||
sock: &UdpSocket,
|
||||
id: u32,
|
||||
stats: &Arc<RetransmitStats>,
|
||||
) -> Result<()> {
|
||||
let timer = Duration::new(1, 0);
|
||||
let r_lock = r.lock().unwrap();
|
||||
@@ -69,6 +182,8 @@ fn retransmit(
|
||||
let mut repair_total = 0;
|
||||
let mut retransmit_total = 0;
|
||||
let mut compute_turbine_peers_total = 0;
|
||||
let mut packets_by_slot: HashMap<Slot, usize> = HashMap::new();
|
||||
let mut packets_by_source: HashMap<String, usize> = HashMap::new();
|
||||
for mut packets in packet_v {
|
||||
for packet in packets.packets.iter_mut() {
|
||||
// skip discarded packets and repair packets
|
||||
@@ -103,7 +218,12 @@ fn retransmit(
|
||||
let neighbors: Vec<_> = neighbors.into_iter().map(|index| &peers[index]).collect();
|
||||
let children: Vec<_> = children.into_iter().map(|index| &peers[index]).collect();
|
||||
compute_turbine_peers.stop();
|
||||
compute_turbine_peers_total += compute_turbine_peers.as_ms();
|
||||
compute_turbine_peers_total += compute_turbine_peers.as_us();
|
||||
|
||||
*packets_by_slot.entry(packet.meta.slot).or_insert(0) += 1;
|
||||
*packets_by_source
|
||||
.entry(packet.meta.addr().to_string())
|
||||
.or_insert(0) += 1;
|
||||
|
||||
let leader =
|
||||
leader_schedule_cache.slot_leader_at(packet.meta.slot, Some(r_bank.as_ref()));
|
||||
@@ -115,7 +235,7 @@ fn retransmit(
|
||||
ClusterInfo::retransmit_to(&children, packet, leader, sock, true)?;
|
||||
}
|
||||
retransmit_time.stop();
|
||||
retransmit_total += retransmit_time.as_ms();
|
||||
retransmit_total += retransmit_time.as_us();
|
||||
}
|
||||
}
|
||||
timer_start.stop();
|
||||
@@ -126,16 +246,19 @@ fn retransmit(
|
||||
retransmit_total,
|
||||
id,
|
||||
);
|
||||
datapoint_debug!("cluster_info-num_nodes", ("count", peers_len, i64));
|
||||
datapoint_debug!(
|
||||
"retransmit-stage",
|
||||
("total_time", timer_start.as_ms() as i64, i64),
|
||||
("total_packets", total_packets as i64, i64),
|
||||
("retransmit_total", retransmit_total as i64, i64),
|
||||
("compute_turbine", compute_turbine_peers_total as i64, i64),
|
||||
("repair_total", i64::from(repair_total), i64),
|
||||
("discard_total", i64::from(discard_total), i64),
|
||||
update_retransmit_stats(
|
||||
stats,
|
||||
timer_start.as_us(),
|
||||
total_packets,
|
||||
retransmit_total,
|
||||
discard_total,
|
||||
repair_total,
|
||||
compute_turbine_peers_total,
|
||||
peers_len,
|
||||
packets_by_slot,
|
||||
packets_by_source,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -154,6 +277,7 @@ pub fn retransmitter(
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
r: Arc<Mutex<PacketReceiver>>,
|
||||
) -> Vec<JoinHandle<()>> {
|
||||
let stats = Arc::new(RetransmitStats::default());
|
||||
(0..sockets.len())
|
||||
.map(|s| {
|
||||
let sockets = sockets.clone();
|
||||
@@ -161,6 +285,7 @@ pub fn retransmitter(
|
||||
let leader_schedule_cache = leader_schedule_cache.clone();
|
||||
let r = r.clone();
|
||||
let cluster_info = cluster_info.clone();
|
||||
let stats = stats.clone();
|
||||
|
||||
Builder::new()
|
||||
.name("solana-retransmitter".to_string())
|
||||
@@ -174,6 +299,7 @@ pub fn retransmitter(
|
||||
&r,
|
||||
&sockets[s],
|
||||
s as u32,
|
||||
&stats,
|
||||
) {
|
||||
match e {
|
||||
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
|
||||
|
111
core/src/rpc.rs
111
core/src/rpc.rs
@@ -4,11 +4,13 @@ use crate::{
|
||||
cluster_info::ClusterInfo,
|
||||
commitment::{BlockCommitmentArray, BlockCommitmentCache},
|
||||
contact_info::ContactInfo,
|
||||
non_circulating_supply::calculate_non_circulating_supply,
|
||||
rpc_error::RpcCustomError,
|
||||
storage_stage::StorageState,
|
||||
validator::ValidatorExit,
|
||||
};
|
||||
use bincode::serialize;
|
||||
use jsonrpc_core::{Error, ErrorCode, Metadata, Result};
|
||||
use jsonrpc_core::{Error, Metadata, Result};
|
||||
use jsonrpc_derive::rpc;
|
||||
use solana_client::{
|
||||
rpc_request::{
|
||||
@@ -17,7 +19,9 @@ use solana_client::{
|
||||
rpc_response::*,
|
||||
};
|
||||
use solana_faucet::faucet::request_airdrop_transaction;
|
||||
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
||||
use solana_ledger::{
|
||||
bank_forks::BankForks, blockstore::Blockstore, blockstore_db::BlockstoreError,
|
||||
};
|
||||
use solana_perf::packet::PACKET_DATA_SIZE;
|
||||
use solana_runtime::{accounts::AccountAddressFilter, bank::Bank};
|
||||
use solana_sdk::{
|
||||
@@ -45,7 +49,6 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
const JSON_RPC_SERVER_ERROR_0: i64 = -32000;
|
||||
const NUM_LARGEST_ACCOUNTS: usize = 20;
|
||||
|
||||
type RpcResponse<T> = Result<Response<T>>;
|
||||
@@ -102,18 +105,13 @@ impl JsonRpcRequestProcessor {
|
||||
.unwrap()
|
||||
.largest_confirmed_root();
|
||||
debug!("RPC using block: {:?}", cluster_root);
|
||||
r_bank_forks
|
||||
.get(cluster_root)
|
||||
.cloned()
|
||||
.ok_or_else(|| Error {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_0),
|
||||
message: format!(
|
||||
"Cluster largest_confirmed_root {} does not exist on node. Node root: {}",
|
||||
cluster_root,
|
||||
r_bank_forks.root(),
|
||||
),
|
||||
data: None,
|
||||
})
|
||||
r_bank_forks.get(cluster_root).cloned().ok_or_else(|| {
|
||||
RpcCustomError::NonexistentClusterRoot {
|
||||
cluster_root,
|
||||
node_root: r_bank_forks.root(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +303,25 @@ impl JsonRpcRequestProcessor {
|
||||
)
|
||||
}
|
||||
|
||||
fn get_supply(&self, commitment: Option<CommitmentConfig>) -> RpcResponse<RpcSupply> {
|
||||
let bank = self.bank(commitment)?;
|
||||
let non_circulating_supply = calculate_non_circulating_supply(bank.clone());
|
||||
let total_supply = bank.capitalization();
|
||||
new_response(
|
||||
&bank,
|
||||
RpcSupply {
|
||||
total: total_supply,
|
||||
circulating: total_supply - non_circulating_supply.lamports,
|
||||
non_circulating: non_circulating_supply.lamports,
|
||||
non_circulating_accounts: non_circulating_supply
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|pubkey| pubkey.to_string())
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn get_vote_accounts(
|
||||
&self,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
@@ -404,6 +421,29 @@ impl JsonRpcRequestProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_slot_cleaned_up<T>(
|
||||
&self,
|
||||
result: &std::result::Result<T, BlockstoreError>,
|
||||
slot: Slot,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
if result.is_err() {
|
||||
if let BlockstoreError::SlotCleanedUp = result.as_ref().unwrap_err() {
|
||||
return Err(RpcCustomError::BlockCleanedUp {
|
||||
slot,
|
||||
first_available_block: self
|
||||
.blockstore
|
||||
.get_first_available_block()
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_confirmed_block(
|
||||
&self,
|
||||
slot: Slot,
|
||||
@@ -417,7 +457,9 @@ impl JsonRpcRequestProcessor {
|
||||
.unwrap()
|
||||
.largest_confirmed_root()
|
||||
{
|
||||
Ok(self.blockstore.get_confirmed_block(slot, encoding).ok())
|
||||
let result = self.blockstore.get_confirmed_block(slot, encoding);
|
||||
self.check_slot_cleaned_up(&result, slot)?;
|
||||
Ok(result.ok())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -465,11 +507,9 @@ 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()
|
||||
.unwrap_or(None))
|
||||
let result = self.blockstore.get_block_time(slot, slot_duration, stakes);
|
||||
self.check_slot_cleaned_up(&result, slot)?;
|
||||
Ok(result.ok().unwrap_or(None))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -795,6 +835,7 @@ pub trait RpcSol {
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<u64>;
|
||||
|
||||
// DEPRECATED
|
||||
#[rpc(meta, name = "getTotalSupply")]
|
||||
fn get_total_supply(
|
||||
&self,
|
||||
@@ -809,6 +850,13 @@ pub trait RpcSol {
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<Vec<RpcAccountBalance>>;
|
||||
|
||||
#[rpc(meta, name = "getSupply")]
|
||||
fn get_supply(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<RpcSupply>;
|
||||
|
||||
#[rpc(meta, name = "requestAirdrop")]
|
||||
fn request_airdrop(
|
||||
&self,
|
||||
@@ -1024,6 +1072,9 @@ impl RpcSol for RpcSolImpl {
|
||||
gossip: Some(contact_info.gossip),
|
||||
tpu: valid_address_or_none(&contact_info.tpu),
|
||||
rpc: valid_address_or_none(&contact_info.rpc),
|
||||
version: cluster_info
|
||||
.get_node_version(&contact_info.id)
|
||||
.map(|v| v.to_string()),
|
||||
})
|
||||
} else {
|
||||
None // Exclude spy nodes
|
||||
@@ -1222,6 +1273,18 @@ impl RpcSol for RpcSolImpl {
|
||||
.get_largest_accounts(commitment)
|
||||
}
|
||||
|
||||
fn get_supply(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> RpcResponse<RpcSupply> {
|
||||
debug!("get_supply rpc request received");
|
||||
meta.request_processor
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_supply(commitment)
|
||||
}
|
||||
|
||||
fn request_airdrop(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
@@ -1414,7 +1477,7 @@ impl RpcSol for RpcSolImpl {
|
||||
|
||||
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
||||
Ok(RpcVersionInfo {
|
||||
solana_core: solana_clap_utils::version!().to_string(),
|
||||
solana_core: solana_version::Version::default().to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1777,7 +1840,7 @@ 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:{}"}}],"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:{}", "version": null}}],"id":1}}"#,
|
||||
leader_pubkey,
|
||||
rpc_port::DEFAULT_RPC_PORT
|
||||
);
|
||||
@@ -2577,7 +2640,7 @@ pub mod tests {
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"solana-core": solana_clap_utils::version!().to_string()
|
||||
"solana-core": solana_version::version!().to_string()
|
||||
},
|
||||
"id": 1
|
||||
});
|
||||
|
45
core/src/rpc_error.rs
Normal file
45
core/src/rpc_error.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use jsonrpc_core::{Error, ErrorCode};
|
||||
use solana_sdk::clock::Slot;
|
||||
|
||||
const JSON_RPC_SERVER_ERROR_0: i64 = -32000;
|
||||
const JSON_RPC_SERVER_ERROR_1: i64 = -32001;
|
||||
|
||||
pub enum RpcCustomError {
|
||||
NonexistentClusterRoot {
|
||||
cluster_root: Slot,
|
||||
node_root: Slot,
|
||||
},
|
||||
BlockCleanedUp {
|
||||
slot: Slot,
|
||||
first_available_block: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<RpcCustomError> for Error {
|
||||
fn from(e: RpcCustomError) -> Self {
|
||||
match e {
|
||||
RpcCustomError::NonexistentClusterRoot {
|
||||
cluster_root,
|
||||
node_root,
|
||||
} => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_0),
|
||||
message: format!(
|
||||
"Cluster largest_confirmed_root {} does not exist on node. Node root: {}",
|
||||
cluster_root, node_root,
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
RpcCustomError::BlockCleanedUp {
|
||||
slot,
|
||||
first_available_block,
|
||||
} => Self {
|
||||
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_1),
|
||||
message: format!(
|
||||
"Block {} cleaned up, does not exist on node. First available block: {}",
|
||||
slot, first_available_block,
|
||||
),
|
||||
data: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,12 +22,23 @@ use std::time::Instant;
|
||||
|
||||
pub type ShredsReceived = HashMap<Slot, BitVec<u64>>;
|
||||
|
||||
#[derive(Default)]
|
||||
struct ShredFetchStats {
|
||||
index_overrun: usize,
|
||||
shred_count: usize,
|
||||
index_bad_deserialize: usize,
|
||||
index_out_of_bounds: usize,
|
||||
slot_bad_deserialize: usize,
|
||||
duplicate_shred: usize,
|
||||
slot_out_of_range: usize,
|
||||
}
|
||||
|
||||
pub struct ShredFetchStage {
|
||||
thread_hdls: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl ShredFetchStage {
|
||||
fn get_slot_index(p: &Packet, index_overrun: &mut usize) -> Option<(u64, u32)> {
|
||||
fn get_slot_index(p: &Packet, stats: &mut ShredFetchStats) -> Option<(u64, u32)> {
|
||||
let index_start = OFFSET_OF_SHRED_INDEX;
|
||||
let index_end = index_start + SIZE_OF_SHRED_INDEX;
|
||||
let slot_start = OFFSET_OF_SHRED_SLOT;
|
||||
@@ -38,11 +49,17 @@ impl ShredFetchStage {
|
||||
if index < MAX_DATA_SHREDS_PER_SLOT as u32 && slot_end <= p.meta.size {
|
||||
if let Ok(slot) = limited_deserialize::<Slot>(&p.data[slot_start..slot_end]) {
|
||||
return Some((slot, index));
|
||||
} else {
|
||||
stats.slot_bad_deserialize += 1;
|
||||
}
|
||||
} else {
|
||||
stats.index_out_of_bounds += 1;
|
||||
}
|
||||
} else {
|
||||
stats.index_bad_deserialize += 1;
|
||||
}
|
||||
} else {
|
||||
*index_overrun += 1;
|
||||
stats.index_overrun += 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -50,7 +67,7 @@ impl ShredFetchStage {
|
||||
fn process_packet<F>(
|
||||
p: &mut Packet,
|
||||
shreds_received: &mut ShredsReceived,
|
||||
index_overrun: &mut usize,
|
||||
stats: &mut ShredFetchStats,
|
||||
last_root: Slot,
|
||||
last_slot: Slot,
|
||||
slots_per_epoch: u64,
|
||||
@@ -59,7 +76,7 @@ impl ShredFetchStage {
|
||||
F: Fn(&mut Packet),
|
||||
{
|
||||
p.meta.discard = true;
|
||||
if let Some((slot, index)) = Self::get_slot_index(p, index_overrun) {
|
||||
if let Some((slot, index)) = Self::get_slot_index(p, stats) {
|
||||
// Seems reasonable to limit shreds to 2 epochs away
|
||||
if slot > last_root && slot < (last_slot + 2 * slots_per_epoch) {
|
||||
// Shred filter
|
||||
@@ -70,7 +87,11 @@ impl ShredFetchStage {
|
||||
p.meta.discard = false;
|
||||
modify(p);
|
||||
slot_received.set(index.into(), true);
|
||||
} else {
|
||||
stats.duplicate_shred += 1;
|
||||
}
|
||||
} else {
|
||||
stats.slot_out_of_range += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +101,7 @@ impl ShredFetchStage {
|
||||
recvr: PacketReceiver,
|
||||
sendr: PacketSender,
|
||||
bank_forks: Option<Arc<RwLock<BankForks>>>,
|
||||
name: &'static str,
|
||||
modify: F,
|
||||
) where
|
||||
F: Fn(&mut Packet),
|
||||
@@ -92,6 +114,9 @@ impl ShredFetchStage {
|
||||
let mut last_slot = std::u64::MAX;
|
||||
let mut slots_per_epoch = 0;
|
||||
|
||||
let mut last_stats = Instant::now();
|
||||
let mut stats = ShredFetchStats::default();
|
||||
|
||||
while let Some(mut p) = recvr.iter().next() {
|
||||
if last_cleared.elapsed().as_millis() > 200 {
|
||||
shreds_received.clear();
|
||||
@@ -105,22 +130,32 @@ impl ShredFetchStage {
|
||||
slots_per_epoch = root_bank.get_slots_in_epoch(root_bank.epoch());
|
||||
}
|
||||
}
|
||||
let mut index_overrun = 0;
|
||||
let mut shred_count = 0;
|
||||
stats.shred_count += p.packets.len();
|
||||
p.packets.iter_mut().for_each(|mut packet| {
|
||||
shred_count += 1;
|
||||
Self::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
&modify,
|
||||
);
|
||||
});
|
||||
inc_new_counter_warn!("shred_fetch_stage-shred_index_overrun", index_overrun);
|
||||
inc_new_counter_info!("shred_fetch_stage-shred_count", shred_count);
|
||||
if last_stats.elapsed().as_millis() > 1000 {
|
||||
datapoint_info!(
|
||||
name,
|
||||
("index_overrun", stats.index_overrun, i64),
|
||||
("shred_count", stats.shred_count, i64),
|
||||
("slot_bad_deserialize", stats.slot_bad_deserialize, i64),
|
||||
("index_bad_deserialize", stats.index_bad_deserialize, i64),
|
||||
("index_out_of_bounds", stats.index_out_of_bounds, i64),
|
||||
("slot_out_of_range", stats.slot_out_of_range, i64),
|
||||
("duplicate_shred", stats.duplicate_shred, i64),
|
||||
);
|
||||
stats = ShredFetchStats::default();
|
||||
last_stats = Instant::now();
|
||||
}
|
||||
if sendr.send(p).is_err() {
|
||||
break;
|
||||
}
|
||||
@@ -133,6 +168,7 @@ impl ShredFetchStage {
|
||||
sender: PacketSender,
|
||||
recycler: Recycler<PinnedVec<Packet>>,
|
||||
bank_forks: Option<Arc<RwLock<BankForks>>>,
|
||||
name: &'static str,
|
||||
modify: F,
|
||||
) -> (Vec<JoinHandle<()>>, JoinHandle<()>)
|
||||
where
|
||||
@@ -154,7 +190,7 @@ impl ShredFetchStage {
|
||||
|
||||
let modifier_hdl = Builder::new()
|
||||
.name("solana-tvu-fetch-stage-packet-modifier".to_string())
|
||||
.spawn(move || Self::modify_packets(packet_receiver, sender, bank_forks, modify))
|
||||
.spawn(move || Self::modify_packets(packet_receiver, sender, bank_forks, name, modify))
|
||||
.unwrap();
|
||||
(streamers, modifier_hdl)
|
||||
}
|
||||
@@ -185,6 +221,7 @@ impl ShredFetchStage {
|
||||
sender.clone(),
|
||||
recycler.clone(),
|
||||
bank_forks.clone(),
|
||||
"shred_fetch_tvu_forwards",
|
||||
|p| p.meta.forward = true,
|
||||
);
|
||||
|
||||
@@ -194,6 +231,7 @@ impl ShredFetchStage {
|
||||
sender.clone(),
|
||||
recycler.clone(),
|
||||
bank_forks,
|
||||
"shred_fetch_repair",
|
||||
|p| p.meta.repair = true,
|
||||
);
|
||||
|
||||
@@ -225,7 +263,7 @@ mod tests {
|
||||
solana_logger::setup();
|
||||
let mut shreds_received = ShredsReceived::default();
|
||||
let mut packet = Packet::default();
|
||||
let mut index_overrun = 0;
|
||||
let mut stats = ShredFetchStats::default();
|
||||
let last_root = 0;
|
||||
let last_slot = 100;
|
||||
let slots_per_epoch = 10;
|
||||
@@ -233,13 +271,13 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
&|_p| {},
|
||||
);
|
||||
assert_eq!(index_overrun, 1);
|
||||
assert_eq!(stats.index_overrun, 1);
|
||||
assert!(packet.meta.discard);
|
||||
let shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0);
|
||||
shred.copy_to_packet(&mut packet);
|
||||
@@ -248,7 +286,7 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
3,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
@@ -260,7 +298,7 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
@@ -272,7 +310,7 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
@@ -287,7 +325,7 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
@@ -301,7 +339,7 @@ mod tests {
|
||||
ShredFetchStage::process_packet(
|
||||
&mut packet,
|
||||
&mut shreds_received,
|
||||
&mut index_overrun,
|
||||
&mut stats,
|
||||
last_root,
|
||||
last_slot,
|
||||
slots_per_epoch,
|
||||
@@ -315,10 +353,10 @@ mod tests {
|
||||
let shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0);
|
||||
let mut packet = Packet::default();
|
||||
shred.copy_to_packet(&mut packet);
|
||||
let mut index_overrun = 0;
|
||||
let mut stats = ShredFetchStats::default();
|
||||
assert_eq!(
|
||||
Some((1, 3)),
|
||||
ShredFetchStage::get_slot_index(&packet, &mut index_overrun)
|
||||
ShredFetchStage::get_slot_index(&packet, &mut stats)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ fn test_rpc_client() {
|
||||
|
||||
assert_eq!(
|
||||
client.get_version().unwrap().solana_core,
|
||||
solana_clap_utils::version!()
|
||||
solana_version::version!()
|
||||
);
|
||||
|
||||
assert!(client.get_account(&bob_pubkey).is_err());
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-crate-features"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Crate Features"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@@ -43,8 +43,8 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
||||
* [getStoragePubkeysForSlot](jsonrpc-api.md#getstoragepubkeysforslot)
|
||||
* [getStorageTurn](jsonrpc-api.md#getstorageturn)
|
||||
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
|
||||
* [getSupply](jsonrpc-api.md#getsupply)
|
||||
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
||||
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
|
||||
* [getVersion](jsonrpc-api.md#getversion)
|
||||
* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
|
||||
* [minimumLedgerSlot](jsonrpc-api.md#minimumledgerslot)
|
||||
@@ -259,7 +259,8 @@ The result field will be an array of JSON objects, each with the following sub f
|
||||
* `pubkey: <string>` - Node public key, as base-58 encoded string
|
||||
* `gossip: <string>` - Gossip network address for the node
|
||||
* `tpu: <string>` - TPU network address for the node
|
||||
* `rpc: <string>` - JSON RPC network address for the node, or `null` if the JSON RPC service is not enabled
|
||||
* `rpc: <string>|null` - JSON RPC network address for the node, or `null` if the JSON RPC service is not enabled
|
||||
* `version: <string>|null` - The software version of the node, or `null` if the version information is not available
|
||||
|
||||
#### Example:
|
||||
|
||||
@@ -268,7 +269,7 @@ The result field will be an array of JSON objects, each with the following sub f
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":[{"gossip":"10.239.6.48:8001","pubkey":"9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ","rpc":"10.239.6.48:8899","tpu":"10.239.6.48:8856"}],"id":1}
|
||||
{"jsonrpc":"2.0","result":[{"gossip":"10.239.6.48:8001","pubkey":"9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ","rpc":"10.239.6.48:8899","tpu":"10.239.6.48:8856"},"version":"1.0.0 c375ce1f"],"id":1}
|
||||
```
|
||||
|
||||
### getConfirmedBlock
|
||||
@@ -944,6 +945,32 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
||||
{"jsonrpc":"2.0","result":1024,"id":1}
|
||||
```
|
||||
|
||||
### getSupply
|
||||
|
||||
Returns information about the current supply.
|
||||
|
||||
#### Parameters:
|
||||
|
||||
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||
|
||||
#### Results:
|
||||
|
||||
The result will be an RpcResponse JSON object with `value` equal to a JSON object containing:
|
||||
|
||||
* `total: <u64>` - Total supply in lamports
|
||||
* `circulating: <u64>` - Circulating supply in lamports
|
||||
* `nonCirculating: <u64>` - Non-circulating supply in lamports
|
||||
* `nonCirculatingAccounts: <array>` - an array of account addresses of non-circulating accounts, as strings
|
||||
|
||||
#### Example:
|
||||
|
||||
```bash
|
||||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getCirculatingSupply"}' http://localhost:8899
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"context":{"slot":1114},"value":{"circulating":16000,"nonCirculating":1000000,"nonCirculatingAccounts":["FEy8pTbP5fEoqMV1GdTz83byuA8EKByqYat1PKDgVAq5","9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA","3mi1GmwEE3zo2jmfDuzvjSX9ovRXsDUKHvsntpkhuLJ9","BYxEJTDerkaRWBem3XgnVcdhppktBXa2HbkHPKj2Ui4Z],total:1016000}},"id":1}
|
||||
```
|
||||
|
||||
### getTransactionCount
|
||||
|
||||
Returns the current Transaction count from the ledger
|
||||
@@ -966,28 +993,6 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
||||
{"jsonrpc":"2.0","result":268,"id":1}
|
||||
```
|
||||
|
||||
### getTotalSupply
|
||||
|
||||
Returns the current total supply in lamports
|
||||
|
||||
#### Parameters:
|
||||
|
||||
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||
|
||||
#### Results:
|
||||
|
||||
* `<u64>` - Total supply
|
||||
|
||||
#### Example:
|
||||
|
||||
```bash
|
||||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTotalSupply"}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":10126,"id":1}
|
||||
```
|
||||
|
||||
### getVersion
|
||||
|
||||
Returns the current solana versions running on the node
|
||||
@@ -1008,7 +1013,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": "1.1.10"},"id":1}
|
||||
{"jsonrpc":"2.0","result":{"solana-core": "1.1.11"},"id":1}
|
||||
```
|
||||
|
||||
### getVoteAccounts
|
||||
|
@@ -1,6 +1,18 @@
|
||||
# Install the Solana Tool Suite
|
||||
|
||||
Install the Solana release
|
||||
There are multiple ways to install the Solana tools on your computer
|
||||
depending on your preferred workflow:
|
||||
- [Use Solana's Install Tool (Simplest option)](#use-solanas-install-tool)
|
||||
- [Download Prebuilt Binaries](#download-prebuilt-binaries)
|
||||
- [Build from Source](#build-from-source)
|
||||
|
||||
## Use Solana's Install Tool
|
||||
|
||||
### MacOS & Linux
|
||||
|
||||
- Open your favorite Terminal application
|
||||
|
||||
- Install the Solana release
|
||||
[LATEST_SOLANA_RELEASE_VERSION](https://github.com/solana-labs/solana/releases/tag/LATEST_SOLANA_RELEASE_VERSION) on your
|
||||
machine by running:
|
||||
|
||||
@@ -8,11 +20,11 @@ machine by running:
|
||||
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/LATEST_SOLANA_RELEASE_VERSION/install/solana-install-init.sh | sh -s - LATEST_SOLANA_RELEASE_VERSION
|
||||
```
|
||||
|
||||
If you are connecting to a different testnet, you can replace `LATEST_SOLANA_RELEASE_VERSION` with the
|
||||
- If you are connecting to a different testnet, you can replace `LATEST_SOLANA_RELEASE_VERSION` with the
|
||||
release tag matching the software version of your desired testnet, or replace it
|
||||
with the named channel `stable`, `beta`, or `edge`.
|
||||
|
||||
The following output indicates a successful update:
|
||||
- The following output indicates a successful update:
|
||||
|
||||
```text
|
||||
looking for latest release
|
||||
@@ -24,8 +36,59 @@ Active release directory: /home/solana/.local/share/solana/install/active_releas
|
||||
Update successful
|
||||
```
|
||||
|
||||
After a successful install, `solana-install update` may be used to easily update
|
||||
the cluster software to a newer version at any time.
|
||||
- Depending on your system, the end of the installer messaging may prompt you
|
||||
to
|
||||
```bash
|
||||
Please update your PATH environment variable to include the solana programs:
|
||||
```
|
||||
- If you get the above message, copy and paste the recommended command below
|
||||
it to update `PATH`
|
||||
- Confirm you have the desired version of `solana` installed by running:
|
||||
```bash
|
||||
solana --version
|
||||
```
|
||||
|
||||
- After a successful install, `solana-install update` may be used to easily
|
||||
update the Solana software to a newer version at any time.
|
||||
|
||||
***
|
||||
|
||||
###Windows
|
||||
|
||||
- Open a Command Prompt (`cmd.exe`) as an Administrator
|
||||
- Search for Command Prompt in the Windows search bar. When the Command
|
||||
Prompt app appears, right-click and select “Open as Administrator”.
|
||||
If you are prompted by a pop-up window asking “Do you want to allow this app to
|
||||
make changes to your device?”, click Yes.
|
||||
|
||||
- Copy and paste the following command, then press Enter to download the Solana
|
||||
installer into a temporary directory:
|
||||
|
||||
```bash
|
||||
curl http://release.solana.com/LATEST_SOLANA_RELEASE_VERSION/solana-install-init-x86_64-pc-windows-gnu.exe --output C:\solana-install-tmp\solana-install-init.exe --create-dirs
|
||||
```
|
||||
|
||||
- Copy and paste the following command, then press Enter to install the latest
|
||||
version of Solana. If you see a security pop-up by your system, please select
|
||||
to allow the program to run.
|
||||
|
||||
```bash
|
||||
C:\solana-install-tmp\solana-install-init.exe LATEST_SOLANA_RELEASE_VERSION
|
||||
```
|
||||
|
||||
- When the installer is finished, press Enter.
|
||||
|
||||
- Close the command prompt window and re-open a new command prompt window as a
|
||||
normal user
|
||||
- Search for "Command Prompt" in the search bar, then left click on the
|
||||
Command Prompt app icon, no need to run as Administrator)
|
||||
- Confirm you have the desired version of `solana` installed by entering:
|
||||
```bash
|
||||
solana --version
|
||||
```
|
||||
|
||||
- After a successful install, `solana-install update` may be used to easily
|
||||
update the Solana software to a newer version at any time.
|
||||
|
||||
## Download Prebuilt Binaries
|
||||
|
||||
@@ -45,7 +108,7 @@ cd solana-release/
|
||||
export PATH=$PWD/bin:$PATH
|
||||
```
|
||||
|
||||
### macOS
|
||||
### MacOS
|
||||
|
||||
Download the binaries by navigating to
|
||||
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
|
||||
@@ -58,6 +121,21 @@ cd solana-release/
|
||||
export PATH=$PWD/bin:$PATH
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
- Download the binaries by navigating to
|
||||
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
|
||||
download **solana-release-x86\_64-pc-windows-gnu.tar.bz2**, then extract the
|
||||
archive using WinZip or similar.
|
||||
|
||||
- Open a Command Prompt and navigate to the directory into which you extracted
|
||||
the binaries and run:
|
||||
|
||||
```bash
|
||||
cd solana-release/
|
||||
set PATH=%cd%/bin;%PATH%
|
||||
```
|
||||
|
||||
## Build From Source
|
||||
|
||||
If you are unable to use the prebuilt binaries or prefer to build it yourself
|
||||
|
@@ -6,7 +6,7 @@ Solana takes a very different approach, which it calls _Proof of History_ or _Po
|
||||
|
||||
Solana technically never sends a _block_, but uses the term to describe the sequence of entries that validators vote on to achieve _confirmation_. In that way, Solana's confirmation times can be compared apples to apples to block-based systems. The current implementation sets block time to 800ms.
|
||||
|
||||
What's happening under the hood is that entries are streamed to validators as quickly as a leader node can batch a set of valid transactions into an entry. Validators process those entries long before it is time to vote on their validity. By processing the transactions optimistically, there is effectively no delay between the time the last entry is received and the time when the node can vote. In the event consensus is **not** achieved, a node simply rolls back its state. This optimisic processing technique was introduced in 1981 and called [Optimistic Concurrency Control](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.105.4735). It can be applied to blockchain architecture where a cluster votes on a hash that represents the full ledger up to some _block height_. In Solana, it is implemented trivially using the last entry's PoH hash.
|
||||
What's happening under the hood is that entries are streamed to validators as quickly as a leader node can batch a set of valid transactions into an entry. Validators process those entries long before it is time to vote on their validity. By processing the transactions optimistically, there is effectively no delay between the time the last entry is received and the time when the node can vote. In the event consensus is **not** achieved, a node simply rolls back its state. This optimisic processing technique was introduced in 1981 and called [Optimistic Concurrency Control](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.115.4735). It can be applied to blockchain architecture where a cluster votes on a hash that represents the full ledger up to some _block height_. In Solana, it is implemented trivially using the last entry's PoH hash.
|
||||
|
||||
## Relationship to VDFs
|
||||
|
||||
|
@@ -6,9 +6,9 @@ Solana is an open source project implementing a new, high-performance, permissio
|
||||
|
||||
## Why Solana?
|
||||
|
||||
It is possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes. A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control [\[H.T.Kung, J.T.Robinson (1981)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.105.4735). At Solana, we are demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network. The key ingredient? Finding a way to share time when nodes cannot trust one-another. Once nodes can trust time, suddenly ~40 years of distributed systems research becomes applicable to blockchain!
|
||||
It is possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes. A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control [\[H.T.Kung, J.T.Robinson (1981)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.115.4735). At Solana, we are demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network. The key ingredient? Finding a way to share time when nodes cannot trust one-another. Once nodes can trust time, suddenly ~40 years of distributed systems research becomes applicable to blockchain!
|
||||
|
||||
> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time. Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions. However, if a distributed system is really a single system, then the processes must be synchronized in some way. Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time. Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time. Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files. This is an approach we have advocated even when fault-tolerance is not required. The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. [\[L.Lamport (1984)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.101.1078)
|
||||
> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time. Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions. However, if a distributed system is really a single system, then the processes must be synchronized in some way. Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time. Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time. Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files. This is an approach we have advocated even when fault-tolerance is not required. The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. [\[L.Lamport (1984)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.111.1078)
|
||||
|
||||
Furthermore, and much to our surprise, it can be implemented using a mechanism that has existed in Bitcoin since day one. The Bitcoin feature is called nLocktime and it can be used to postdate transactions using block height instead of a timestamp. As a Bitcoin client, you would use block height instead of a timestamp if you don't trust the network. Block height turns out to be an instance of what's being called a Verifiable Delay Function in cryptography circles. It's a cryptographically secure way to say time has passed. In Solana, we use a far more granular verifiable delay function, a SHA 256 hash chain, to checkpoint the ledger and coordinate consensus. With it, we implement Optimistic Concurrency Control and are now well en route towards that theoretical limit of 710,000 transactions per second.
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-dos"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,10 +13,10 @@ clap = "2.33.0"
|
||||
log = "0.4.8"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.3.0"
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-download-utils"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Download Utils"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,8 +14,8 @@ console = "0.10.0"
|
||||
indicatif = "0.14.0"
|
||||
log = "0.4.8"
|
||||
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
tar = "0.4.26"
|
||||
|
||||
[lib]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-faucet"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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.105"
|
||||
serde_derive = "1.0.103"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
tokio = "0.1"
|
||||
tokio-codec = "0.1"
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-genesis-programs"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana genesis programs"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,13 +10,13 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.4.8" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "1.1.10" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.1.11" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "1.1.11" }
|
||||
|
||||
[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 = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -15,13 +15,13 @@ chrono = "0.4"
|
||||
serde = "1.0.105"
|
||||
serde_json = "1.0.48"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -3,19 +3,19 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-gossip"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-net-utils = { path = "../net-utils", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
|
||||
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-install"
|
||||
description = "The solana cluster software installer"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -24,11 +24,11 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
semver = "0.9.0"
|
||||
tar = "0.4.26"
|
||||
tempdir = "0.3.7"
|
||||
|
@@ -221,8 +221,7 @@ fn new_update_manifest(
|
||||
let mut transaction = Transaction::new_unsigned_instructions(new_account);
|
||||
let signers = [from_keypair, update_manifest_keypair];
|
||||
transaction.sign(&signers, recent_blockhash);
|
||||
|
||||
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
|
||||
rpc_client.send_and_confirm_transaction(&transaction)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -245,8 +244,8 @@ fn store_update_manifest(
|
||||
);
|
||||
|
||||
let message = Message::new_with_payer(&[instruction], Some(&from_keypair.pubkey()));
|
||||
let mut transaction = Transaction::new(&signers, message, recent_blockhash);
|
||||
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
|
||||
let transaction = Transaction::new(&signers, message, recent_blockhash);
|
||||
rpc_client.send_and_confirm_transaction(&transaction)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-keygen"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana key generation utility"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -13,10 +13,10 @@ bs58 = "0.3.0"
|
||||
clap = "2.33"
|
||||
dirs = "2.0.2"
|
||||
num_cpus = "1.12.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.1.10" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.1.11" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
tiny-bip39 = "0.7.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -75,7 +75,7 @@ fn output_keypair(
|
||||
write_keypair(&keypair, &mut stdout)?;
|
||||
} else {
|
||||
write_keypair_file(&keypair, outfile)?;
|
||||
eprintln!("Wrote {} keypair to {}", source, outfile);
|
||||
println!("Wrote {} keypair to {}", source, outfile);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -443,7 +443,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
||||
let passphrase = if matches.is_present("no_passphrase") {
|
||||
NO_PASSPHRASE.to_string()
|
||||
} else {
|
||||
eprintln!("Generating a new keypair");
|
||||
println!("Generating a new keypair");
|
||||
prompt_passphrase(
|
||||
"For added security, enter a passphrase (empty for no passphrase): ",
|
||||
)?
|
||||
@@ -459,7 +459,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
||||
if !silent {
|
||||
let phrase: &str = mnemonic.phrase();
|
||||
let divider = String::from_utf8(vec![b'='; phrase.len()]).unwrap();
|
||||
eprintln!(
|
||||
println!(
|
||||
"{}\npubkey: {}\n{}\nSave this seed phrase to recover your new keypair:\n{}\n{}",
|
||||
÷r, keypair.pubkey(), ÷r, phrase, ÷r
|
||||
);
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-ledger-tool"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,15 +14,15 @@ clap = "2.33.0"
|
||||
histogram = "*"
|
||||
serde_json = "1.0.48"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-cli = { path = "../cli", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-cli = { path = "../cli", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -726,6 +726,13 @@ fn main() {
|
||||
.takes_value(false)
|
||||
.help("Include sysvars too"),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("capitalization")
|
||||
.about("Print capitalization (aka, total suppy)")
|
||||
.arg(&no_snapshot_arg)
|
||||
.arg(&account_paths_arg)
|
||||
.arg(&halt_at_slot_arg)
|
||||
.arg(&hard_forks_arg)
|
||||
).subcommand(
|
||||
SubCommand::with_name("prune")
|
||||
.about("Prune the ledger at the block height")
|
||||
@@ -1049,6 +1056,83 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
("capitalization", Some(arg_matches)) => {
|
||||
let dev_halt_at_slot = value_t!(arg_matches, "halt_at_slot", Slot).ok();
|
||||
let process_options = ProcessOptions {
|
||||
dev_halt_at_slot,
|
||||
new_hard_forks: hardforks_of(arg_matches, "hard_forks"),
|
||||
poh_verify: false,
|
||||
..ProcessOptions::default()
|
||||
};
|
||||
let genesis_config = open_genesis_config(&ledger_path);
|
||||
match load_bank_forks(arg_matches, &ledger_path, &genesis_config, process_options) {
|
||||
Ok((bank_forks, bank_forks_info, _leader_schedule_cache, _snapshot_hash)) => {
|
||||
let slot = dev_halt_at_slot.unwrap_or_else(|| {
|
||||
if bank_forks_info.len() > 1 {
|
||||
eprintln!("Error: multiple forks present");
|
||||
exit(1);
|
||||
}
|
||||
bank_forks_info[0].bank_slot
|
||||
});
|
||||
|
||||
let bank = bank_forks.get(slot).unwrap_or_else(|| {
|
||||
eprintln!("Error: Slot {} is not available", slot);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
use solana_sdk::native_token::LAMPORTS_PER_SOL;
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
pub struct Sol(u64);
|
||||
|
||||
impl Display for Sol {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
write!(
|
||||
f,
|
||||
"{}.{:09} SOL",
|
||||
self.0 / LAMPORTS_PER_SOL,
|
||||
self.0 % LAMPORTS_PER_SOL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let computed_capitalization: u64 = bank
|
||||
.get_program_accounts(None)
|
||||
.into_iter()
|
||||
.filter_map(|(_pubkey, account)| {
|
||||
if account.lamports == u64::max_value() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_specially_retained =
|
||||
solana_sdk::native_loader::check_id(&account.owner)
|
||||
|| solana_sdk::sysvar::check_id(&account.owner);
|
||||
|
||||
if is_specially_retained {
|
||||
// specially retained accounts are ensured to exist by
|
||||
// alwaysing having a balance of 1 lamports, which is
|
||||
// outside the capitalization calculation.
|
||||
Some(account.lamports - 1)
|
||||
} else {
|
||||
Some(account.lamports)
|
||||
}
|
||||
})
|
||||
.sum();
|
||||
|
||||
if bank.capitalization() != computed_capitalization {
|
||||
panic!(
|
||||
"Capitalization mismatch!?: {} != {}",
|
||||
bank.capitalization(),
|
||||
computed_capitalization
|
||||
);
|
||||
}
|
||||
println!("Capitalization: {}", Sol(bank.capitalization()));
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Failed to load ledger: {:?}", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
("purge", Some(arg_matches)) => {
|
||||
let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot);
|
||||
let end_slot = value_t!(arg_matches, "end_slot", Slot);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-ledger"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana ledger"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -28,19 +28,19 @@ reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0
|
||||
regex = "1.3.6"
|
||||
serde = "1.0.105"
|
||||
serde_bytes = "0.11.3"
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-measure = { path = "../measure", version = "1.1.10" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-perf = { path = "../perf", version = "1.1.10" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-measure = { path = "../measure", version = "1.1.11" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
solana-perf = { path = "../perf", version = "1.1.11" }
|
||||
ed25519-dalek = "1.0.0-pre.3"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
symlink = "0.1.0"
|
||||
tar = "0.4.26"
|
||||
thiserror = "1.0"
|
||||
@@ -57,7 +57,7 @@ features = ["lz4"]
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
matches = "0.1.6"
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -913,14 +913,14 @@ impl Blockstore {
|
||||
// ToDo: This is a potential slashing condition
|
||||
warn!("Received multiple erasure configs for the same erasure set!!!");
|
||||
warn!(
|
||||
"Stored config: {:#?}, new config: {:#?}",
|
||||
erasure_meta.config, erasure_config
|
||||
"Slot: {}, shred index: {}, set_index: {}, is_duplicate: {}, stored config: {:#?}, new config: {:#?}",
|
||||
slot, shred.index(), set_index, self.has_duplicate_shreds_in_slot(slot), erasure_meta.config, erasure_config
|
||||
);
|
||||
}
|
||||
|
||||
// Should be safe to modify index_meta here. Two cases
|
||||
// 1) Recovery happens: Then all inserted erasure metas are removed
|
||||
// from just_received_coding_shreds, and nothing wll be committed by
|
||||
// from just_received_coding_shreds, and nothing will be committed by
|
||||
// `check_insert_coding_shred`, so the coding index meta will not be
|
||||
// committed
|
||||
index_meta.coding_mut().set_present(shred_index, true);
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-local-cluster"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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.9.0"
|
||||
log = "0.4.8"
|
||||
rand = "0.7.0"
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.10" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.10" }
|
||||
solana-core = { path = "../core", version = "1.1.10" }
|
||||
solana-client = { path = "../client", version = "1.1.10" }
|
||||
solana-download-utils = { path = "../download-utils", version = "1.1.10" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.10" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.10" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.10" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "1.1.10" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.10" }
|
||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.11" }
|
||||
solana-config-program = { path = "../programs/config", version = "1.1.11" }
|
||||
solana-core = { path = "../core", version = "1.1.11" }
|
||||
solana-client = { path = "../client", version = "1.1.11" }
|
||||
solana-download-utils = { path = "../download-utils", version = "1.1.11" }
|
||||
solana-faucet = { path = "../faucet", version = "1.1.11" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
|
||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
|
||||
solana-ledger = { path = "../ledger", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-runtime = { path = "../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
|
||||
solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "1.1.11" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
|
||||
tempfile = "3.1.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.10" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-log-analyzer"
|
||||
description = "The solana cluster network analysis tool"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,8 +14,8 @@ byte-unit = "3.0.3"
|
||||
clap = "2.33.0"
|
||||
serde = "1.0.105"
|
||||
serde_json = "1.0.48"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
|
||||
[[bin]]
|
||||
name = "solana-log-analyzer"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-logger"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
jemallocator = "0.3.2"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-merkle-tree"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
fast-math = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-metrics"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Metrics"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,7 +14,7 @@ gethostname = "0.2.1"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.8"
|
||||
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7.0"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-net-shaper"
|
||||
description = "The solana cluster network shaping tool"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,8 +13,8 @@ publish = false
|
||||
clap = "2.33.0"
|
||||
serde = "1.0.105"
|
||||
serde_json = "1.0.48"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
rand = "0.7.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-net-utils"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Network Utilities"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -18,8 +18,8 @@ rand = "0.7.0"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
socket2 = "0.3.11"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
tokio = "0.1"
|
||||
tokio-codec = "0.1"
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-perf"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Performance APIs"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -17,11 +17,11 @@ serde = "1.0.105"
|
||||
dlopen_derive = "0.1.4"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.8"
|
||||
solana-sdk = { path = "../sdk", version = "1.1.10" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.10" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.10" }
|
||||
solana-logger = { path = "../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.10" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.11" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.11" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
|
||||
solana-logger = { path = "../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../metrics", version = "1.1.11" }
|
||||
|
||||
[lib]
|
||||
name = "solana_perf"
|
||||
|
597
programs/bpf/Cargo.lock
generated
597
programs/bpf/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-bpf-programs"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "README.md"
|
||||
@@ -22,11 +22,11 @@ walkdir = "2"
|
||||
bincode = "1.1.4"
|
||||
byteorder = "1.3.2"
|
||||
elf = "0.0.10"
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.1.10" }
|
||||
solana-logger = { path = "../../logger", version = "1.1.10" }
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10" }
|
||||
solana_rbpf = "=0.1.25"
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.1.11" }
|
||||
solana-logger = { path = "../../logger", version = "1.1.11" }
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.11" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11" }
|
||||
solana_rbpf = "=0.1.27"
|
||||
|
||||
[[bench]]
|
||||
name = "bpf_loader"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.1.11" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit-dep"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-alloc"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-dep-crate"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-dup-accounts"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-error-handling"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,11 +14,11 @@ edition = "2018"
|
||||
[dependencies]
|
||||
num-derive = "0.2"
|
||||
num-traits = "0.2"
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-external-spend"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-iter"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.1.11" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args-dep"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-noop"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-panic"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-param-passing"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "1.1.11" }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-param-passing-dep"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-sysval"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10", default-features = false }
|
||||
solana-sdk = { path = "../../../../sdk/", version = "1.1.11", default-features = false }
|
||||
|
||||
[dev_dependencies]
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.10" }
|
||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.1.11" }
|
||||
|
||||
[features]
|
||||
program = ["solana-sdk/program"]
|
||||
|
@@ -92,7 +92,7 @@ mod bpf {
|
||||
.native_instruction_processors
|
||||
.push(solana_bpf_loader_program!());
|
||||
let bank = Arc::new(Bank::new(&genesis_config));
|
||||
// Create bank with specific slot, used by solana_bpf_rust_sysvar test
|
||||
// Create bank with a specific slot, used by solana_bpf_rust_sysvar test
|
||||
let bank =
|
||||
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-loader-program"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana BPF loader"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,11 +15,14 @@ libc = "0.2.68"
|
||||
log = "0.4.8"
|
||||
num-derive = { version = "0.3" }
|
||||
num-traits = { version = "0.2" }
|
||||
solana-logger = { path = "../../logger", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10" }
|
||||
solana_rbpf = "=0.1.25"
|
||||
solana-logger = { path = "../../logger", version = "1.1.11" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11" }
|
||||
solana_rbpf = "=0.1.27"
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7.3"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
name = "solana_bpf_loader_program"
|
||||
|
@@ -25,7 +25,7 @@ impl BPFAllocator {
|
||||
|
||||
impl Alloc for BPFAllocator {
|
||||
fn alloc(&mut self, layout: Layout) -> Result<u64, AllocErr> {
|
||||
if self.pos + layout.size() as u64 <= self.len {
|
||||
if self.pos.saturating_add(layout.size() as u64) <= self.len {
|
||||
let addr = self.start + self.pos;
|
||||
self.pos += layout.size() as u64;
|
||||
Ok(addr)
|
||||
|
@@ -2,36 +2,56 @@ use crate::BPFError;
|
||||
use solana_rbpf::ebpf;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Error definitions
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VerifierError {
|
||||
/// ProgramLengthNotMultiple
|
||||
#[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)]
|
||||
ProgramLengthNotMultiple,
|
||||
/// ProgramTooLarge
|
||||
#[error("program too big, max {}, is {}", ebpf::PROG_MAX_INSNS, .0)]
|
||||
ProgramTooLarge(usize),
|
||||
/// NoProgram
|
||||
#[error("no program set, call prog_set() to load one")]
|
||||
NoProgram,
|
||||
#[error("division by 0 (insn #{0})")]
|
||||
DivisionByZero(usize),
|
||||
/// UnsupportedLEBEArgument
|
||||
#[error("unsupported argument for LE/BE (insn #{0})")]
|
||||
UnsupportedLEBEArgument(usize),
|
||||
/// LDDWCannotBeLast
|
||||
#[error("LD_DW instruction cannot be last in program")]
|
||||
LDDWCannotBeLast,
|
||||
/// IncompleteLDDW
|
||||
#[error("incomplete LD_DW instruction (insn #{0})")]
|
||||
IncompleteLDDW(usize),
|
||||
/// InfiniteLoop
|
||||
#[error("infinite loop (insn #{0})")]
|
||||
InfiniteLoop(usize),
|
||||
/// JumpOutOfCode
|
||||
#[error("jump out of code to #{0} (insn #{1})")]
|
||||
JumpOutOfCode(usize, usize),
|
||||
/// JumpToMiddleOfLDDW
|
||||
#[error("jump to middle of LD_DW at #{0} (insn #{1})")]
|
||||
JumpToMiddleOfLDDW(usize, usize),
|
||||
/// InvalidSourceRegister
|
||||
#[error("invalid source register (insn #{0})")]
|
||||
InvalidSourceRegister(usize),
|
||||
/// CannotWriteR10
|
||||
#[error("cannot write into register r10 (insn #{0})")]
|
||||
CannotWriteR10(usize),
|
||||
/// InvalidDestinationRegister
|
||||
#[error("invalid destination register (insn #{0})")]
|
||||
InvalidDestinationRegister(usize),
|
||||
/// UnknownOpCode
|
||||
#[error("unknown eBPF opcode {0:#2x} (insn #{1:?})")]
|
||||
UnknownOpCode(u8, usize),
|
||||
/// Shift with overflow
|
||||
#[error("Shift with overflow at instruction {0}")]
|
||||
ShiftWithOverflow(usize),
|
||||
/// Invalid register specified
|
||||
#[error("Invalid register specified at instruction {0}")]
|
||||
InvalidRegister(usize),
|
||||
}
|
||||
|
||||
fn check_prog_len(prog: &[u8]) -> Result<(), BPFError> {
|
||||
@@ -102,6 +122,23 @@ fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<()
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the imm is a valid shift operand
|
||||
fn check_imm_shift(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> {
|
||||
if insn.imm < 0 || insn.imm as u64 >= 64 {
|
||||
return Err(VerifierError::ShiftWithOverflow(insn_ptr));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that the imm is a valid register number
|
||||
fn check_imm_register(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), VerifierError> {
|
||||
if insn.imm < 0 || insn.imm > 10 {
|
||||
return Err(VerifierError::InvalidRegister(insn_ptr));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn check(prog: &[u8]) -> Result<(), BPFError> {
|
||||
check_prog_len(prog)?;
|
||||
|
||||
@@ -111,189 +148,126 @@ pub fn check(prog: &[u8]) -> Result<(), BPFError> {
|
||||
let mut store = false;
|
||||
|
||||
match insn.opc {
|
||||
// BPF_LD class
|
||||
ebpf::LD_ABS_B => {}
|
||||
ebpf::LD_ABS_H => {}
|
||||
ebpf::LD_ABS_W => {}
|
||||
ebpf::LD_ABS_DW => {}
|
||||
ebpf::LD_IND_B => {}
|
||||
ebpf::LD_IND_H => {}
|
||||
ebpf::LD_IND_W => {}
|
||||
ebpf::LD_IND_DW => {}
|
||||
|
||||
ebpf::LD_DW_IMM => {
|
||||
// BPF_LD class
|
||||
ebpf::LD_ABS_B => {},
|
||||
ebpf::LD_ABS_H => {},
|
||||
ebpf::LD_ABS_W => {},
|
||||
ebpf::LD_ABS_DW => {},
|
||||
ebpf::LD_IND_B => {},
|
||||
ebpf::LD_IND_H => {},
|
||||
ebpf::LD_IND_W => {},
|
||||
ebpf::LD_IND_DW => {},
|
||||
|
||||
ebpf::LD_DW_IMM => {
|
||||
store = true;
|
||||
check_load_dw(prog, insn_ptr)?;
|
||||
insn_ptr += 1;
|
||||
}
|
||||
},
|
||||
|
||||
// BPF_LDX class
|
||||
ebpf::LD_B_REG => {}
|
||||
ebpf::LD_H_REG => {}
|
||||
ebpf::LD_W_REG => {}
|
||||
ebpf::LD_DW_REG => {}
|
||||
ebpf::LD_B_REG => {},
|
||||
ebpf::LD_H_REG => {},
|
||||
ebpf::LD_W_REG => {},
|
||||
ebpf::LD_DW_REG => {},
|
||||
|
||||
// BPF_ST class
|
||||
ebpf::ST_B_IMM => store = true,
|
||||
ebpf::ST_H_IMM => store = true,
|
||||
ebpf::ST_W_IMM => store = true,
|
||||
ebpf::ST_DW_IMM => store = true,
|
||||
ebpf::ST_B_IMM => store = true,
|
||||
ebpf::ST_H_IMM => store = true,
|
||||
ebpf::ST_W_IMM => store = true,
|
||||
ebpf::ST_DW_IMM => store = true,
|
||||
|
||||
// BPF_STX class
|
||||
ebpf::ST_B_REG => store = true,
|
||||
ebpf::ST_H_REG => store = true,
|
||||
ebpf::ST_W_REG => store = true,
|
||||
ebpf::ST_DW_REG => store = true,
|
||||
ebpf::ST_W_XADD => {
|
||||
unimplemented!();
|
||||
}
|
||||
ebpf::ST_DW_XADD => {
|
||||
unimplemented!();
|
||||
}
|
||||
ebpf::ST_B_REG => store = true,
|
||||
ebpf::ST_H_REG => store = true,
|
||||
ebpf::ST_W_REG => store = true,
|
||||
ebpf::ST_DW_REG => store = true,
|
||||
|
||||
// BPF_ALU class
|
||||
ebpf::ADD32_IMM => {}
|
||||
ebpf::ADD32_REG => {}
|
||||
ebpf::SUB32_IMM => {}
|
||||
ebpf::SUB32_REG => {}
|
||||
ebpf::MUL32_IMM => {}
|
||||
ebpf::MUL32_REG => {}
|
||||
ebpf::DIV32_IMM => {
|
||||
check_imm_nonzero(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::DIV32_REG => {}
|
||||
ebpf::OR32_IMM => {}
|
||||
ebpf::OR32_REG => {}
|
||||
ebpf::AND32_IMM => {}
|
||||
ebpf::AND32_REG => {}
|
||||
ebpf::LSH32_IMM => {}
|
||||
ebpf::LSH32_REG => {}
|
||||
ebpf::RSH32_IMM => {}
|
||||
ebpf::RSH32_REG => {}
|
||||
ebpf::NEG32 => {}
|
||||
ebpf::MOD32_IMM => {
|
||||
check_imm_nonzero(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::MOD32_REG => {}
|
||||
ebpf::XOR32_IMM => {}
|
||||
ebpf::XOR32_REG => {}
|
||||
ebpf::MOV32_IMM => {}
|
||||
ebpf::MOV32_REG => {}
|
||||
ebpf::ARSH32_IMM => {}
|
||||
ebpf::ARSH32_REG => {}
|
||||
ebpf::LE => {
|
||||
check_imm_endian(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::BE => {
|
||||
check_imm_endian(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::ADD32_IMM => {},
|
||||
ebpf::ADD32_REG => {},
|
||||
ebpf::SUB32_IMM => {},
|
||||
ebpf::SUB32_REG => {},
|
||||
ebpf::MUL32_IMM => {},
|
||||
ebpf::MUL32_REG => {},
|
||||
ebpf::DIV32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
|
||||
ebpf::DIV32_REG => {},
|
||||
ebpf::OR32_IMM => {},
|
||||
ebpf::OR32_REG => {},
|
||||
ebpf::AND32_IMM => {},
|
||||
ebpf::AND32_REG => {},
|
||||
ebpf::LSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::LSH32_REG => {},
|
||||
ebpf::RSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::RSH32_REG => {},
|
||||
ebpf::NEG32 => {},
|
||||
ebpf::MOD32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
|
||||
ebpf::MOD32_REG => {},
|
||||
ebpf::XOR32_IMM => {},
|
||||
ebpf::XOR32_REG => {},
|
||||
ebpf::MOV32_IMM => {},
|
||||
ebpf::MOV32_REG => {},
|
||||
ebpf::ARSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::ARSH32_REG => {},
|
||||
ebpf::LE => { check_imm_endian(&insn, insn_ptr)?; },
|
||||
ebpf::BE => { check_imm_endian(&insn, insn_ptr)?; },
|
||||
|
||||
// BPF_ALU64 class
|
||||
ebpf::ADD64_IMM => {}
|
||||
ebpf::ADD64_REG => {}
|
||||
ebpf::SUB64_IMM => {}
|
||||
ebpf::SUB64_REG => {}
|
||||
ebpf::MUL64_IMM => {
|
||||
check_imm_nonzero(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::MUL64_REG => {}
|
||||
ebpf::DIV64_IMM => {
|
||||
check_imm_nonzero(&insn, insn_ptr)?;
|
||||
}
|
||||
ebpf::DIV64_REG => {}
|
||||
ebpf::OR64_IMM => {}
|
||||
ebpf::OR64_REG => {}
|
||||
ebpf::AND64_IMM => {}
|
||||
ebpf::AND64_REG => {}
|
||||
ebpf::LSH64_IMM => {}
|
||||
ebpf::LSH64_REG => {}
|
||||
ebpf::RSH64_IMM => {}
|
||||
ebpf::RSH64_REG => {}
|
||||
ebpf::NEG64 => {}
|
||||
ebpf::MOD64_IMM => {}
|
||||
ebpf::MOD64_REG => {}
|
||||
ebpf::XOR64_IMM => {}
|
||||
ebpf::XOR64_REG => {}
|
||||
ebpf::MOV64_IMM => {}
|
||||
ebpf::MOV64_REG => {}
|
||||
ebpf::ARSH64_IMM => {}
|
||||
ebpf::ARSH64_REG => {}
|
||||
ebpf::ADD64_IMM => {},
|
||||
ebpf::ADD64_REG => {},
|
||||
ebpf::SUB64_IMM => {},
|
||||
ebpf::SUB64_REG => {},
|
||||
ebpf::MUL64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
|
||||
ebpf::MUL64_REG => {},
|
||||
ebpf::DIV64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
|
||||
ebpf::DIV64_REG => {},
|
||||
ebpf::OR64_IMM => {},
|
||||
ebpf::OR64_REG => {},
|
||||
ebpf::AND64_IMM => {},
|
||||
ebpf::AND64_REG => {},
|
||||
ebpf::LSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::LSH64_REG => {},
|
||||
ebpf::RSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::RSH64_REG => {},
|
||||
ebpf::NEG64 => {},
|
||||
ebpf::MOD64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
|
||||
ebpf::MOD64_REG => {},
|
||||
ebpf::XOR64_IMM => {},
|
||||
ebpf::XOR64_REG => {},
|
||||
ebpf::MOV64_IMM => {},
|
||||
ebpf::MOV64_REG => {},
|
||||
ebpf::ARSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
|
||||
ebpf::ARSH64_REG => {},
|
||||
|
||||
// BPF_JMP class
|
||||
ebpf::JA => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JEQ_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JEQ_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JGT_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JGT_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JGE_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JGE_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JLT_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JLT_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JLE_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JLE_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSET_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSET_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JNE_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JNE_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSGT_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSGT_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSGE_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSGE_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSLT_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSLT_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSLE_IMM => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::JSLE_REG => {
|
||||
check_jmp_offset(prog, insn_ptr)?;
|
||||
}
|
||||
ebpf::CALL_IMM => {}
|
||||
ebpf::CALL_REG => {}
|
||||
ebpf::EXIT => {}
|
||||
ebpf::JA => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JEQ_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JEQ_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JGT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JGT_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JGE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JGE_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JLT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JLT_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JLE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JLE_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSET_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSET_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JNE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JNE_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSGT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSGT_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSGE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSGE_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSLT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSLT_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSLE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::JSLE_REG => { check_jmp_offset(prog, insn_ptr)?; },
|
||||
ebpf::CALL_IMM => {},
|
||||
ebpf::CALL_REG => { check_imm_register(&insn, insn_ptr)?; },
|
||||
ebpf::EXIT => {},
|
||||
|
||||
_ => {
|
||||
_ => {
|
||||
return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr).into());
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
pub mod alloc;
|
||||
pub mod allocator_bump;
|
||||
pub mod bpf_verifier;
|
||||
pub mod helpers;
|
||||
pub mod syscalls;
|
||||
|
||||
use crate::{bpf_verifier::VerifierError, helpers::HelperError};
|
||||
use crate::{bpf_verifier::VerifierError, syscalls::SyscallError};
|
||||
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
||||
use log::*;
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
@@ -50,7 +50,7 @@ pub enum BPFError {
|
||||
#[error("{0}")]
|
||||
VerifierError(#[from] VerifierError),
|
||||
#[error("{0}")]
|
||||
HelperError(#[from] HelperError),
|
||||
SyscallError(#[from] SyscallError),
|
||||
}
|
||||
impl UserDefinedError for BPFError {}
|
||||
|
||||
@@ -60,7 +60,7 @@ pub fn create_vm(prog: &[u8]) -> Result<(EbpfVm<BPFError>, MemoryRegion), EbpfEr
|
||||
vm.set_max_instruction_count(100_000)?;
|
||||
vm.set_elf(&prog)?;
|
||||
|
||||
let heap_region = helpers::register_helpers(&mut vm)?;
|
||||
let heap_region = syscalls::register_syscalls(&mut vm)?;
|
||||
|
||||
Ok((vm, heap_region))
|
||||
}
|
||||
@@ -197,8 +197,8 @@ pub fn process_instruction(
|
||||
Err(error) => {
|
||||
warn!("BPF program failed: {}", error);
|
||||
return match error {
|
||||
EbpfError::UserError(BPFError::HelperError(
|
||||
HelperError::InstructionError(error),
|
||||
EbpfError::UserError(BPFError::SyscallError(
|
||||
SyscallError::InstructionError(error),
|
||||
)) => Err(error),
|
||||
_ => Err(BPFLoaderError::VirtualMachineFailedToRunProgram.into()),
|
||||
};
|
||||
@@ -250,8 +250,9 @@ pub fn process_instruction(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand::Rng;
|
||||
use solana_sdk::{account::Account, rent::Rent};
|
||||
use std::{fs::File, io::Read};
|
||||
use std::{fs::File, io::Read, ops::Range};
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "ExceededMaxInstructions(10)")]
|
||||
@@ -416,4 +417,61 @@ mod tests {
|
||||
process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![])
|
||||
);
|
||||
}
|
||||
|
||||
/// fuzzing utility function
|
||||
fn fuzz<F>(
|
||||
bytes: &[u8],
|
||||
outer_iters: usize,
|
||||
inner_iters: usize,
|
||||
offset: Range<usize>,
|
||||
value: Range<u8>,
|
||||
work: F,
|
||||
) where
|
||||
F: Fn(&mut [u8]),
|
||||
{
|
||||
let mut rng = rand::thread_rng();
|
||||
for _ in 0..outer_iters {
|
||||
let mut mangled_bytes = bytes.to_vec();
|
||||
for _ in 0..inner_iters {
|
||||
let offset = rng.gen_range(offset.start, offset.end);
|
||||
let value = rng.gen_range(value.start, value.end);
|
||||
mangled_bytes[offset] = value;
|
||||
work(&mut mangled_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_fuzz() {
|
||||
let program_id = Pubkey::new_rand();
|
||||
let program_key = Pubkey::new_rand();
|
||||
|
||||
// Create program account
|
||||
let mut file = File::open("test_elfs/noop.so").expect("file open failed");
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
|
||||
info!("mangle the whole file");
|
||||
fuzz(
|
||||
&elf,
|
||||
1_000_000_000,
|
||||
100,
|
||||
0..elf.len(),
|
||||
0..255,
|
||||
|bytes: &mut [u8]| {
|
||||
let program_account = Account::new_ref(1, 0, &program_id);
|
||||
program_account.borrow_mut().data = bytes.to_vec();
|
||||
program_account.borrow_mut().executable = true;
|
||||
|
||||
let parameter_account = Account::new_ref(1, 0, &program_id);
|
||||
let keyed_accounts = vec![
|
||||
KeyedAccount::new(&program_key, false, &program_account),
|
||||
KeyedAccount::new(&program_key, false, ¶meter_account),
|
||||
];
|
||||
|
||||
let _result = process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ use crate::{alloc, BPFError};
|
||||
use alloc::Alloc;
|
||||
use log::*;
|
||||
use solana_rbpf::{
|
||||
ebpf::{EbpfError, HelperObject, ELF_INSN_DUMP_OFFSET, MM_HEAP_START},
|
||||
ebpf::{EbpfError, SyscallObject, ELF_INSN_DUMP_OFFSET, MM_HEAP_START},
|
||||
memory_region::{translate_addr, MemoryRegion},
|
||||
EbpfVm,
|
||||
};
|
||||
@@ -17,7 +17,7 @@ use thiserror::Error as ThisError;
|
||||
|
||||
/// Error definitions
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum HelperError {
|
||||
pub enum SyscallError {
|
||||
#[error("{0}: {1:?}")]
|
||||
InvalidString(Utf8Error, Vec<u8>),
|
||||
#[error("BPF program called abort()!")]
|
||||
@@ -27,8 +27,8 @@ pub enum HelperError {
|
||||
#[error("{0}")]
|
||||
InstructionError(InstructionError),
|
||||
}
|
||||
impl From<HelperError> for EbpfError<BPFError> {
|
||||
fn from(error: HelperError) -> Self {
|
||||
impl From<SyscallError> for EbpfError<BPFError> {
|
||||
fn from(error: SyscallError) -> Self {
|
||||
EbpfError::UserError(error.into())
|
||||
}
|
||||
}
|
||||
@@ -45,21 +45,21 @@ use crate::allocator_bump::BPFAllocator;
|
||||
/// are expected to enforce this
|
||||
const DEFAULT_HEAP_SIZE: usize = 32 * 1024;
|
||||
|
||||
pub fn register_helpers<'a>(
|
||||
pub fn register_syscalls<'a>(
|
||||
vm: &mut EbpfVm<'a, BPFError>,
|
||||
) -> Result<MemoryRegion, EbpfError<BPFError>> {
|
||||
// Helper function common across languages
|
||||
vm.register_helper_ex("abort", helper_abort)?;
|
||||
vm.register_helper_ex("sol_panic_", helper_sol_panic)?;
|
||||
vm.register_helper_ex("sol_log_", helper_sol_log)?;
|
||||
vm.register_helper_ex("sol_log_64_", helper_sol_log_u64)?;
|
||||
vm.register_syscall_ex("abort", syscall_abort)?;
|
||||
vm.register_syscall_ex("sol_panic_", syscall_sol_panic)?;
|
||||
vm.register_syscall_ex("sol_log_", syscall_sol_log)?;
|
||||
vm.register_syscall_ex("sol_log_64_", syscall_sol_log_u64)?;
|
||||
|
||||
// Memory allocator
|
||||
let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
|
||||
let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START);
|
||||
vm.register_helper_with_context_ex(
|
||||
vm.register_syscall_with_context_ex(
|
||||
"sol_alloc_free_",
|
||||
Box::new(HelperSolAllocFree {
|
||||
Box::new(SyscallSolAllocFree {
|
||||
allocator: BPFAllocator::new(heap, MM_HEAP_START),
|
||||
}),
|
||||
)?;
|
||||
@@ -136,15 +136,14 @@ fn translate_string_and_do(
|
||||
};
|
||||
match from_utf8(&buf[..i]) {
|
||||
Ok(message) => work(message),
|
||||
Err(err) => Err(HelperError::InvalidString(err, buf[..i].to_vec()).into()),
|
||||
Err(err) => Err(SyscallError::InvalidString(err, buf[..i].to_vec()).into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Abort helper functions, called when the BPF program calls `abort()`
|
||||
/// LLVM will insert calls to `abort()` if it detects an untenable situation,
|
||||
/// `abort()` is not intended to be called explicitly by the program.
|
||||
/// Causes the BPF program to be halted immediately
|
||||
pub fn helper_abort(
|
||||
/// Abort syscall functions, called when the BPF program calls `abort()`
|
||||
/// The verify function returns an error which will cause the BPF program
|
||||
/// to be halted immediately
|
||||
pub fn syscall_abort(
|
||||
_arg1: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
@@ -153,12 +152,13 @@ pub fn helper_abort(
|
||||
_ro_regions: &[MemoryRegion],
|
||||
_rw_regions: &[MemoryRegion],
|
||||
) -> Result<u64, EbpfError<BPFError>> {
|
||||
Err(HelperError::Abort.into())
|
||||
Err(SyscallError::Abort.into())
|
||||
}
|
||||
|
||||
/// Panic helper function, called when the BPF program calls 'sol_panic_()`
|
||||
/// Causes the BPF program to be halted immediately
|
||||
pub fn helper_sol_panic(
|
||||
/// Panic syscall functions, called when the BPF program calls 'sol_panic_()`
|
||||
/// The verify function returns an error which will cause the BPF program
|
||||
/// to be halted immediately
|
||||
pub fn syscall_sol_panic(
|
||||
file: u64,
|
||||
len: u64,
|
||||
line: u64,
|
||||
@@ -168,12 +168,12 @@ pub fn helper_sol_panic(
|
||||
_rw_regions: &[MemoryRegion],
|
||||
) -> Result<u64, EbpfError<BPFError>> {
|
||||
translate_string_and_do(file, len, ro_regions, &|string: &str| {
|
||||
Err(HelperError::Panic(string.to_string(), line, column).into())
|
||||
Err(SyscallError::Panic(string.to_string(), line, column).into())
|
||||
})
|
||||
}
|
||||
|
||||
/// Log a user's info message
|
||||
pub fn helper_sol_log(
|
||||
pub fn syscall_sol_log(
|
||||
addr: u64,
|
||||
len: u64,
|
||||
_arg3: u64,
|
||||
@@ -191,8 +191,8 @@ pub fn helper_sol_log(
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Log 5 64-bit values
|
||||
pub fn helper_sol_log_u64(
|
||||
/// Log 5 u64 values
|
||||
pub fn syscall_sol_log_u64(
|
||||
arg1: u64,
|
||||
arg2: u64,
|
||||
arg3: u64,
|
||||
@@ -210,16 +210,16 @@ pub fn helper_sol_log_u64(
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// Dynamic memory allocation helper called when the BPF program calls
|
||||
/// Dynamic memory allocation syscall called when the BPF program calls
|
||||
/// `sol_alloc_free_()`. The allocator is expected to allocate/free
|
||||
/// from/to a given chunk of memory and enforce size restrictions. The
|
||||
/// memory chunk is given to the allocator during allocator creation and
|
||||
/// information about that memory (start address and size) is passed
|
||||
/// to the VM to use for enforcement.
|
||||
pub struct HelperSolAllocFree {
|
||||
pub struct SyscallSolAllocFree {
|
||||
allocator: BPFAllocator,
|
||||
}
|
||||
impl HelperObject<BPFError> for HelperSolAllocFree {
|
||||
impl SyscallObject<BPFError> for SyscallSolAllocFree {
|
||||
fn call(
|
||||
&mut self,
|
||||
size: u64,
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-btc-spv-program"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Bitcoin spv parsing program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,7 +15,7 @@ num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10"}
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11"}
|
||||
hex = "0.4.2"
|
||||
|
||||
[lib]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "btc_spv_bin"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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 = "1.1.10"
|
||||
version = "1.1.11"
|
||||
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.105"
|
||||
serde_derive = "1.0.103"
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.10" }
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.11" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-config-program"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Config program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,10 +14,10 @@ chrono = { version = "0.4.11", features = ["serde"] }
|
||||
log = "0.4.8"
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-logger = { path = "../../logger", version = "1.1.10" }
|
||||
solana-logger = { path = "../../logger", version = "1.1.11" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-exchange-program"
|
||||
version = "1.1.10"
|
||||
version = "1.1.11"
|
||||
description = "Solana Exchange program"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,13 +15,13 @@ num-derive = { version = "0.3" }
|
||||
num-traits = { version = "0.2" }
|
||||
serde = "1.0.105"
|
||||
serde_derive = "1.0.103"
|
||||
solana-logger = { path = "../../logger", version = "1.1.10" }
|
||||
solana-metrics = { path = "../../metrics", version = "1.1.10" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.10" }
|
||||
solana-logger = { path = "../../logger", version = "1.1.11" }
|
||||
solana-metrics = { path = "../../metrics", version = "1.1.11" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.1.11" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.10" }
|
||||
solana-runtime = { path = "../../runtime", version = "1.1.11" }
|
||||
|
||||
[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