Compare commits

...

18 Commits

Author SHA1 Message Date
Michael Vines
c51a18a887 getClusterNodes RPC API now includes the node software version (#9993) 2020-05-11 21:38:19 -07:00
mergify[bot]
206ff02be9 Fix up a couple cli commands that fail when a node is in the --wait-for-supermajority state (#9985) (#9991)
automerge

(cherry picked from commit 3b9dc50541)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-11 19:48:59 -07:00
Michael Vines
8d7e90e9b8 Advertise node version in gossip (#9986)
automerge
2020-05-11 17:45:19 -07:00
mergify[bot]
eb11db3e3e Check slot cleaned up for RPC blockstore/slot queries (#9982) (#9989)
automerge
2020-05-11 16:49:22 -07:00
mergify[bot]
8d8ad84527 Add retransmit packets_by_slot metrics (#9975) (#9984)
automerge
2020-05-11 15:25:40 -07:00
Dan Albert
fa059bb3c3 Add windows instructions to CLI install docs (#9987)
automerge
2020-05-11 14:50:26 -07:00
mergify[bot]
9652e832c2 Write non-error output to stdout (#9960) (#9972)
automerge
2020-05-11 10:18:15 -07:00
mergify[bot]
52e27712e1 Retransmit and shred fetch metrics (#9965) (#9969)
automerge
2020-05-10 23:15:15 -07:00
mergify[bot]
c00ec26a3b Cli: Add solana supply command; hide total-supply (bp #9956) (#9963)
automerge
2020-05-10 18:04:46 -07:00
mergify[bot]
50eba96b58 More logging around failure (#9967) (#9968)
automerge
2020-05-10 17:23:30 -07:00
mergify[bot]
e7c0629951 Remove RpcClient code duplication (#9952) (#9961)
automerge
2020-05-10 10:36:56 -07:00
mergify[bot]
a08235da9a send_and_confirm_transaction() no longer needs a keypair (#9950) (#9962)
automerge
2020-05-10 10:14:31 -07:00
mergify[bot]
b213004157 Rpc: Add getCirculatingSupply endpoint, redux (#9953) (#9955)
automerge
2020-05-09 12:32:08 -07:00
Jack May
92562b4349 Pull in hardened BPF virtual machine (#9931) 2020-05-08 16:06:22 -07:00
Jack May
01c490d354 Rename BPF helper to syscall (#9819)
automerge
2020-05-08 16:06:22 -07:00
Ryo Onodera
cfdc0eb99e Maintain sysvar balances for consistent market cap. (#9942)
automerge
2020-05-08 12:15:37 -07:00
mergify[bot]
0b7b3c9f20 Support ad-hoc genesis args in run.sh (#9697) (#9940)
automerge
2020-05-08 08:29:29 -07:00
Michael Vines
5cd685ed3a Bump version to v1.1.11 2020-05-07 16:57:43 -07:00
137 changed files with 2833 additions and 2085 deletions

685
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,7 @@ members = [
"transaction-status", "transaction-status",
"upload-perf", "upload-perf",
"net-utils", "net-utils",
"version",
"vote-signer", "vote-signer",
"cli", "cli",
"rayon-threadlimit", "rayon-threadlimit",

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-accounts-bench" name = "solana-accounts-bench"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -10,10 +10,10 @@ homepage = "https://solana.com/"
[dependencies] [dependencies]
log = "0.4.6" log = "0.4.6"
rayon = "1.3.0" rayon = "1.3.0"
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-measure = { path = "../measure", version = "1.1.10" } solana-measure = { path = "../measure", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
rand = "0.7.0" rand = "0.7.0"
clap = "2.33.0" clap = "2.33.0"
crossbeam-channel = "0.4" crossbeam-channel = "0.4"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-archiver-lib" name = "solana-archiver-lib"
version = "1.1.10" version = "1.1.11"
description = "Solana Archiver Library" description = "Solana Archiver Library"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -15,23 +15,23 @@ ed25519-dalek = "=1.0.0-pre.3"
log = "0.4.8" log = "0.4.8"
rand = "0.7.0" rand = "0.7.0"
rand_chacha = "0.2.2" rand_chacha = "0.2.2"
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
thiserror = "1.0" thiserror = "1.0"
serde = "1.0.105" serde = "1.0.105"
serde_json = "1.0.48" serde_json = "1.0.48"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-chacha = { path = "../chacha", version = "1.1.10" } solana-chacha = { path = "../chacha", version = "1.1.11" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" } solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-streamer = { path = "../streamer", version = "1.1.10" } solana-streamer = { path = "../streamer", version = "1.1.11" }
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.10" } solana-archiver-utils = { path = "../archiver-utils", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
[dev-dependencies] [dev-dependencies]
hex = "0.4.2" hex = "0.4.2"

View File

@@ -697,16 +697,11 @@ impl Archiver {
RpcClient::new_socket(rpc_peers[node_index].rpc) RpcClient::new_socket(rpc_peers[node_index].rpc)
}; };
Ok(rpc_client Ok(rpc_client
.send( .send::<u64>(
&RpcRequest::GetSlotsPerSegment, RpcRequest::GetSlotsPerSegment,
serde_json::json!([client_commitment]), serde_json::json!([client_commitment]),
0, 0,
) )
.map_err(|err| {
warn!("Error while making rpc request {:?}", err);
ArchiverError::ClientError(err)
})?
.as_u64()
.unwrap()) .unwrap())
} else { } else {
Err(ArchiverError::NoRpcPeers) Err(ArchiverError::NoRpcPeers)
@@ -749,21 +744,14 @@ impl Archiver {
let node_index = thread_rng().gen_range(0, rpc_peers.len()); let node_index = thread_rng().gen_range(0, rpc_peers.len());
RpcClient::new_socket(rpc_peers[node_index].rpc) 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 { let RpcStorageTurn {
blockhash: storage_blockhash, blockhash: storage_blockhash,
slot: turn_slot, slot: turn_slot,
} = serde_json::from_value::<RpcStorageTurn>(response) } = rpc_client.send(
.map_err(ArchiverError::JsonError)?; RpcRequest::GetStorageTurn,
serde_json::value::Value::Null,
0,
)?;
let turn_blockhash = storage_blockhash.parse().map_err(|err| { let turn_blockhash = storage_blockhash.parse().map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-archiver-utils" name = "solana-archiver-utils"
version = "1.1.10" version = "1.1.11"
description = "Solana Archiver Utils" description = "Solana Archiver Utils"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -11,12 +11,12 @@ edition = "2018"
[dependencies] [dependencies]
log = "0.4.8" log = "0.4.8"
rand = "0.7.0" rand = "0.7.0"
solana-chacha = { path = "../chacha", version = "1.1.10" } solana-chacha = { path = "../chacha", version = "1.1.11" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" } solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
[dev-dependencies] [dev-dependencies]
hex = "0.4.2" hex = "0.4.2"

View File

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

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-banking-bench" name = "solana-banking-bench"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -10,14 +10,14 @@ homepage = "https://solana.com/"
[dependencies] [dependencies]
log = "0.4.6" log = "0.4.6"
rayon = "1.3.0" rayon = "1.3.0"
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-streamer = { path = "../streamer", version = "1.1.10" } solana-streamer = { path = "../streamer", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-measure = { path = "../measure", version = "1.1.10" } solana-measure = { path = "../measure", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
rand = "0.7.0" rand = "0.7.0"
crossbeam-channel = "0.4" crossbeam-channel = "0.4"

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-exchange" name = "solana-bench-exchange"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -18,20 +18,20 @@ rand = "0.7.0"
rayon = "1.3.0" rayon = "1.3.0"
serde_json = "1.0.48" serde_json = "1.0.48"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-genesis = { path = "../genesis", version = "1.1.10" } solana-genesis = { path = "../genesis", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-faucet = { path = "../faucet", version = "1.1.10" } solana-faucet = { path = "../faucet", version = "1.1.11" }
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" } solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
[dev-dependencies] [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] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -2,17 +2,17 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-streamer" name = "solana-bench-streamer"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
[dependencies] [dependencies]
clap = "2.33.0" clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-streamer = { path = "../streamer", version = "1.1.10" } solana-streamer = { path = "../streamer", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
[package.metadata.docs.rs] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-tps" name = "solana-bench-tps"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -14,24 +14,24 @@ log = "0.4.8"
rayon = "1.3.0" rayon = "1.3.0"
serde_json = "1.0.48" serde_json = "1.0.48"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-genesis = { path = "../genesis", version = "1.1.10" } solana-genesis = { path = "../genesis", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-faucet = { path = "../faucet", version = "1.1.10" } solana-faucet = { path = "../faucet", version = "1.1.11" }
#solana-librapay = { path = "../programs/librapay", version = "1.1.8", optional = true } #solana-librapay = { path = "../programs/librapay", version = "1.1.8", optional = true }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
solana-measure = { path = "../measure", version = "1.1.10" } solana-measure = { path = "../measure", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
#solana-move-loader-program = { path = "../programs/move_loader", version = "1.1.8", optional = true } #solana-move-loader-program = { path = "../programs/move_loader", version = "1.1.8", optional = true }
[dev-dependencies] [dev-dependencies]
serial_test = "0.4.0" serial_test = "0.4.0"
serial_test_derive = "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] #[features]
#move = ["solana-librapay", "solana-move-loader-program"] #move = ["solana-librapay", "solana-move-loader-program"]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-chacha-cuda" name = "solana-chacha-cuda"
version = "1.1.10" version = "1.1.11"
description = "Solana Chacha Cuda APIs" description = "Solana Chacha Cuda APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -10,12 +10,12 @@ edition = "2018"
[dependencies] [dependencies]
log = "0.4.8" log = "0.4.8"
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.10" } solana-archiver-utils = { path = "../archiver-utils", version = "1.1.11" }
solana-chacha = { path = "../chacha", version = "1.1.10" } solana-chacha = { path = "../chacha", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
[dev-dependencies] [dev-dependencies]
hex-literal = "0.2.1" hex-literal = "0.2.1"

View File

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

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-chacha" name = "solana-chacha"
version = "1.1.10" version = "1.1.11"
description = "Solana Chacha APIs" description = "Solana Chacha APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,11 +12,11 @@ edition = "2018"
log = "0.4.8" log = "0.4.8"
rand = "0.7.0" rand = "0.7.0"
rand_chacha = "0.2.2" rand_chacha = "0.2.2"
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.10" } solana-chacha-sys = { path = "../chacha-sys", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
[dev-dependencies] [dev-dependencies]
hex-literal = "0.2.1" hex-literal = "0.2.1"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-clap-utils" name = "solana-clap-utils"
version = "1.1.10" version = "1.1.11"
description = "Solana utilities for the clap" description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -11,8 +11,8 @@ edition = "2018"
[dependencies] [dependencies]
clap = "2.33.0" clap = "2.33.0"
rpassword = "4.0" rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" } solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
thiserror = "1.0.11" thiserror = "1.0.11"
tiny-bip39 = "0.7.0" tiny-bip39 = "0.7.0"
url = "2.1.0" url = "2.1.0"

View File

@@ -8,11 +8,15 @@ pub const COMMITMENT_ARG: ArgConstant<'static> = ArgConstant {
}; };
pub fn commitment_arg<'a, 'b>() -> Arg<'a, 'b> { 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) Arg::with_name(COMMITMENT_ARG.name)
.long(COMMITMENT_ARG.long) .long(COMMITMENT_ARG.long)
.takes_value(true) .takes_value(true)
.possible_values(&["recent", "root", "max"]) .possible_values(&["recent", "root", "max"])
.default_value("recent") .default_value(default_value)
.value_name("COMMITMENT_LEVEL") .value_name("COMMITMENT_LEVEL")
.help(COMMITMENT_ARG.help) .help(COMMITMENT_ARG.help)
} }

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-cli-config" name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-cli" name = "solana-cli"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -27,28 +27,28 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.48" serde_json = "1.0.48"
solana-budget-program = { path = "../programs/budget", version = "1.1.10" } solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-cli-config = { path = "../cli-config", version = "1.1.10" } solana-cli-config = { path = "../cli-config", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-config-program = { path = "../programs/config", version = "1.1.10" } solana-config-program = { path = "../programs/config", version = "1.1.11" }
solana-faucet = { path = "../faucet", version = "1.1.10" } solana-faucet = { path = "../faucet", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" } solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" } solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
solana-vote-signer = { path = "../vote-signer", version = "1.1.10" } solana-vote-signer = { path = "../vote-signer", version = "1.1.11" }
thiserror = "1.0.13" thiserror = "1.0.13"
url = "2.1.1" url = "2.1.1"
[dev-dependencies] [dev-dependencies]
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-budget-program = { path = "../programs/budget", version = "1.1.10" } solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
tempfile = "3.1.0" tempfile = "3.1.0"
[[bin]] [[bin]]

View File

@@ -16,7 +16,11 @@ use num_traits::FromPrimitive;
use serde_json::{self, json, Value}; use serde_json::{self, json, Value};
use solana_budget_program::budget_instruction::{self, BudgetError}; use solana_budget_program::budget_instruction::{self, BudgetError};
use solana_clap_utils::{ 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, ArgConstant,
}; };
use solana_client::{ use solana_client::{
@@ -201,6 +205,10 @@ pub enum CliCommand {
GetSlot { GetSlot {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
}, },
Supply {
commitment_config: CommitmentConfig,
print_accounts: bool,
},
TotalSupply { TotalSupply {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
}, },
@@ -405,6 +413,7 @@ pub enum CliCommand {
Balance { Balance {
pubkey: Option<Pubkey>, pubkey: Option<Pubkey>,
use_lamports_unit: bool, use_lamports_unit: bool,
commitment_config: CommitmentConfig,
}, },
Cancel(Pubkey), Cancel(Pubkey),
Confirm(Signature), Confirm(Signature),
@@ -569,6 +578,7 @@ impl Default for CliConfig<'_> {
command: CliCommand::Balance { command: CliCommand::Balance {
pubkey: Some(Pubkey::default()), pubkey: Some(Pubkey::default()),
use_lamports_unit: false, use_lamports_unit: false,
commitment_config: CommitmentConfig::default(),
}, },
json_rpc_url: Self::default_json_rpc_url(), json_rpc_url: Self::default_json_rpc_url(),
websocket_url: Self::default_websocket_url(), websocket_url: Self::default_websocket_url(),
@@ -612,6 +622,7 @@ pub fn parse_command(
}), }),
("epoch", Some(matches)) => parse_get_epoch(matches), ("epoch", Some(matches)) => parse_get_epoch(matches),
("slot", Some(matches)) => parse_get_slot(matches), ("slot", Some(matches)) => parse_get_slot(matches),
("supply", Some(matches)) => parse_supply(matches),
("total-supply", Some(matches)) => parse_total_supply(matches), ("total-supply", Some(matches)) => parse_total_supply(matches),
("transaction-count", Some(matches)) => parse_get_transaction_count(matches), ("transaction-count", Some(matches)) => parse_get_transaction_count(matches),
("leader-schedule", Some(_matches)) => Ok(CliCommandInfo { ("leader-schedule", Some(_matches)) => Ok(CliCommandInfo {
@@ -782,6 +793,7 @@ pub fn parse_command(
} }
("balance", Some(matches)) => { ("balance", Some(matches)) => {
let pubkey = pubkey_of_signer(matches, "pubkey", wallet_manager)?; 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() { let signers = if pubkey.is_some() {
vec![] vec![]
} else { } else {
@@ -796,6 +808,7 @@ pub fn parse_command(
command: CliCommand::Balance { command: CliCommand::Balance {
pubkey, pubkey,
use_lamports_unit: matches.is_present("lamports"), use_lamports_unit: matches.is_present("lamports"),
commitment_config,
}, },
signers, signers,
}) })
@@ -1178,19 +1191,17 @@ fn process_balance(
config: &CliConfig, config: &CliConfig,
pubkey: &Option<Pubkey>, pubkey: &Option<Pubkey>,
use_lamports_unit: bool, use_lamports_unit: bool,
commitment_config: CommitmentConfig,
) -> ProcessResult { ) -> ProcessResult {
let pubkey = if let Some(pubkey) = pubkey { let pubkey = if let Some(pubkey) = pubkey {
*pubkey *pubkey
} else { } else {
config.pubkey()? config.pubkey()?
}; };
let balance = rpc_client.retry_get_balance(&pubkey, 5)?; let balance = rpc_client
match balance { .get_balance_with_commitment(&pubkey, commitment_config)?
Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit, true)), .value;
None => Err( Ok(build_balance_message(balance, use_lamports_unit, true))
CliError::RpcRequestError("Received result of an unexpected type".to_string()).into(),
),
}
} }
fn process_confirm( fn process_confirm(
@@ -1343,8 +1354,7 @@ fn process_deploy(
)?; )?;
trace!("Creating program account"); trace!("Creating program account");
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&create_account_tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut create_account_tx, &signers);
log_instruction_custom_error::<SystemError>(result, &config).map_err(|_| { log_instruction_custom_error::<SystemError>(result, &config).map_err(|_| {
CliError::DynamicProgramError("Program account allocation failed".to_string()) CliError::DynamicProgramError("Program account allocation failed".to_string())
})?; })?;
@@ -1354,7 +1364,7 @@ fn process_deploy(
trace!("Finalizing program account"); trace!("Finalizing program account");
rpc_client rpc_client
.send_and_confirm_transaction_with_spinner(&mut finalize_tx, &signers) .send_and_confirm_transaction_with_spinner(&finalize_tx)
.map_err(|e| { .map_err(|e| {
CliError::DynamicProgramError(format!("Program finalize transaction failed: {}", e)) CliError::DynamicProgramError(format!("Program finalize transaction failed: {}", e))
})?; })?;
@@ -1419,8 +1429,7 @@ fn process_pay(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
log_instruction_custom_error::<SystemError>(result, &config) log_instruction_custom_error::<SystemError>(result, &config)
} }
} else if *witnesses == None { } else if *witnesses == None {
@@ -1455,10 +1464,7 @@ fn process_pay(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = rpc_client.send_and_confirm_transaction_with_spinner( let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
&mut tx,
&[config.signers[0], &contract_state],
);
let signature = log_instruction_custom_error::<BudgetError>(result, &config)?; let signature = log_instruction_custom_error::<BudgetError>(result, &config)?;
Ok(json!({ Ok(json!({
"signature": signature, "signature": signature,
@@ -1494,10 +1500,7 @@ fn process_pay(
return_signers(&tx, &config) return_signers(&tx, &config)
} else { } else {
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?; tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner( let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
&mut tx,
&[config.signers[0], &contract_state],
);
check_account_for_fee( check_account_for_fee(
rpc_client, rpc_client,
&config.signers[0].pubkey(), &config.signers[0].pubkey(),
@@ -1532,8 +1535,7 @@ fn process_cancel(rpc_client: &RpcClient, config: &CliConfig, pubkey: &Pubkey) -
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
log_instruction_custom_error::<BudgetError>(result, &config) log_instruction_custom_error::<BudgetError>(result, &config)
} }
@@ -1556,8 +1558,7 @@ fn process_time_elapsed(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
log_instruction_custom_error::<BudgetError>(result, &config) log_instruction_custom_error::<BudgetError>(result, &config)
} }
@@ -1619,7 +1620,7 @@ fn process_transfer(
let result = if no_wait { let result = if no_wait {
rpc_client.send_transaction(&tx) rpc_client.send_transaction(&tx)
} else { } 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) log_instruction_custom_error::<SystemError>(result, &config)
} }
@@ -1643,8 +1644,7 @@ fn process_witness(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
log_instruction_custom_error::<BudgetError>(result, &config) log_instruction_custom_error::<BudgetError>(result, &config)
} }
@@ -1703,6 +1703,10 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::GetSlot { commitment_config } => { CliCommand::GetSlot { commitment_config } => {
process_get_slot(&rpc_client, *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 } => { CliCommand::TotalSupply { commitment_config } => {
process_total_supply(&rpc_client, *commitment_config) process_total_supply(&rpc_client, *commitment_config)
} }
@@ -2133,7 +2137,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::Balance { CliCommand::Balance {
pubkey, pubkey,
use_lamports_unit, 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 // Cancel a contract by contract Pubkey
CliCommand::Cancel(pubkey) => process_cancel(&rpc_client, config, &pubkey), CliCommand::Cancel(pubkey) => process_cancel(&rpc_client, config, &pubkey),
// Confirm the last client transaction by signature // Confirm the last client transaction by signature
@@ -2275,8 +2286,8 @@ pub fn request_and_confirm_airdrop(
sleep(Duration::from_secs(1)); sleep(Duration::from_secs(1));
} }
}?; }?;
let mut tx = keypair.airdrop_transaction(); let tx = keypair.airdrop_transaction();
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[&keypair]); let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, &config) 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") .long("lamports")
.takes_value(false) .takes_value(false)
.help("Display balance in lamports instead of SOL"), .help("Display balance in lamports instead of SOL"),
), )
.arg(commitment_arg_with_default("max")),
) )
.subcommand( .subcommand(
SubCommand::with_name("cancel") SubCommand::with_name("cancel")
@@ -2813,7 +2825,8 @@ mod tests {
CliCommandInfo { CliCommandInfo {
command: CliCommand::Balance { command: CliCommand::Balance {
pubkey: Some(keypair.pubkey()), pubkey: Some(keypair.pubkey()),
use_lamports_unit: false use_lamports_unit: false,
commitment_config: CommitmentConfig::default(),
}, },
signers: vec![], signers: vec![],
} }
@@ -2829,7 +2842,8 @@ mod tests {
CliCommandInfo { CliCommandInfo {
command: CliCommand::Balance { command: CliCommand::Balance {
pubkey: Some(keypair.pubkey()), pubkey: Some(keypair.pubkey()),
use_lamports_unit: true use_lamports_unit: true,
commitment_config: CommitmentConfig::default(),
}, },
signers: vec![], signers: vec![],
} }
@@ -2843,7 +2857,8 @@ mod tests {
CliCommandInfo { CliCommandInfo {
command: CliCommand::Balance { command: CliCommand::Balance {
pubkey: None, pubkey: None,
use_lamports_unit: true use_lamports_unit: true,
commitment_config: CommitmentConfig::default(),
}, },
signers: vec![read_keypair_file(&keypair_file).unwrap().into()], signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
} }
@@ -3313,12 +3328,14 @@ mod tests {
config.command = CliCommand::Balance { config.command = CliCommand::Balance {
pubkey: None, pubkey: None,
use_lamports_unit: true, use_lamports_unit: true,
commitment_config: CommitmentConfig::default(),
}; };
assert_eq!(process_command(&config).unwrap(), "50 lamports"); assert_eq!(process_command(&config).unwrap(), "50 lamports");
config.command = CliCommand::Balance { config.command = CliCommand::Balance {
pubkey: None, pubkey: None,
use_lamports_unit: false, use_lamports_unit: false,
commitment_config: CommitmentConfig::default(),
}; };
assert_eq!(process_command(&config).unwrap(), "0.00000005 SOL"); assert_eq!(process_command(&config).unwrap(), "0.00000005 SOL");
@@ -3552,6 +3569,7 @@ mod tests {
config.command = CliCommand::Balance { config.command = CliCommand::Balance {
pubkey: None, pubkey: None,
use_lamports_unit: false, use_lamports_unit: false,
commitment_config: CommitmentConfig::default(),
}; };
assert!(process_command(&config).is_err()); assert!(process_command(&config).is_err());

View File

@@ -4,9 +4,10 @@ use console::{style, Emoji};
use inflector::cases::titlecase::to_title_case; use inflector::cases::titlecase::to_title_case;
use serde::Serialize; use serde::Serialize;
use serde_json::{Map, Value}; 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::{ use solana_sdk::{
clock::{self, Epoch, Slot, UnixTimestamp}, clock::{self, Epoch, Slot, UnixTimestamp},
native_token::lamports_to_sol,
stake_history::StakeHistoryEntry, stake_history::StakeHistoryEntry,
}; };
use solana_stake_program::stake_state::{Authorized, Lockup}; use solana_stake_program::stake_state::{Authorized, Lockup};
@@ -907,3 +908,49 @@ impl fmt::Display for CliSignature {
Ok(()) 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(())
}
}

View File

@@ -3,7 +3,7 @@ use crate::{
cli_output::*, cli_output::*,
display::println_name_value, 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 console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle}; use indicatif::{ProgressBar, ProgressStyle};
use solana_clap_utils::{ use solana_clap_utils::{
@@ -121,8 +121,19 @@ impl ClusterQuerySubCommands for App<'_, '_> {
SubCommand::with_name("epoch").about("Get current epoch") SubCommand::with_name("epoch").about("Get current epoch")
.arg(commitment_arg()), .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(
SubCommand::with_name("total-supply").about("Get total number of SOL") SubCommand::with_name("total-supply").about("Get total number of SOL")
.setting(AppSettings::Hidden)
.arg(commitment_arg()), .arg(commitment_arg()),
) )
.subcommand( .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> { pub fn parse_total_supply(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let commitment_config = commitment_of(matches, COMMITMENT_ARG.long).unwrap(); let commitment_config = commitment_of(matches, COMMITMENT_ARG.long).unwrap();
Ok(CliCommandInfo { Ok(CliCommandInfo {
@@ -653,7 +676,7 @@ pub fn process_show_block_production(
slot_limit: Option<u64>, slot_limit: Option<u64>,
) -> ProcessResult { ) -> ProcessResult {
let epoch_schedule = rpc_client.get_epoch_schedule()?; 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); let epoch = epoch.unwrap_or(epoch_info.epoch);
if epoch > 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)); progress_bar.set_message(&format!("Fetching leader schedule for epoch {}...", epoch));
let leader_schedule = rpc_client 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() { if leader_schedule.is_none() {
return Err(format!("Unable to fetch leader schedule for slot {}", start_slot).into()); 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)) 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( pub fn process_total_supply(
rpc_client: &RpcClient, rpc_client: &RpcClient,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,

View File

@@ -462,7 +462,7 @@ pub fn process_authorize_nonce_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<NonceError>(result, &config)
} }
@@ -539,7 +539,7 @@ pub fn process_create_nonce_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<SystemError>(result, &config)
} }
@@ -580,8 +580,7 @@ pub fn process_new_nonce(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = rpc_client let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0], nonce_authority]);
log_instruction_custom_error::<SystemError>(result, &config) log_instruction_custom_error::<SystemError>(result, &config)
} }
@@ -640,7 +639,7 @@ pub fn process_withdraw_from_nonce_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<NonceError>(result, &config)
} }

View File

@@ -894,7 +894,7 @@ pub fn process_create_stake_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<SystemError>(result, &config)
} }
} }
@@ -959,7 +959,7 @@ pub fn process_stake_authorize(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<StakeError>(result, &config)
} }
} }
@@ -1013,7 +1013,7 @@ pub fn process_deactivate_stake_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<StakeError>(result, &config)
} }
} }
@@ -1076,7 +1076,7 @@ pub fn process_withdraw_stake(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<SystemError>(result, &config)
} }
} }
@@ -1210,7 +1210,7 @@ pub fn process_split_stake(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<StakeError>(result, &config)
} }
} }
@@ -1267,7 +1267,7 @@ pub fn process_stake_set_lockup(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<StakeError>(result, &config)
} }
} }
@@ -1475,7 +1475,7 @@ pub fn process_delegate_stake(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<StakeError>(result, &config)
} }
} }

View File

@@ -242,7 +242,7 @@ pub fn process_create_storage_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<SystemError>(result, &config)
} }
@@ -266,7 +266,7 @@ pub fn process_claim_storage_reward(
&fee_calculator, &fee_calculator,
&tx.message, &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()) Ok(signature.to_string())
} }

View File

@@ -367,7 +367,7 @@ pub fn process_set_validator_info(
&fee_calculator, &fee_calculator,
&tx.message, &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!("Success! Validator info published at: {:?}", info_pubkey);
println!("{}", signature_str); println!("{}", signature_str);

View File

@@ -457,7 +457,7 @@ pub fn process_create_vote_account(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<SystemError>(result, &config)
} }
@@ -497,8 +497,7 @@ pub fn process_vote_authorize(
&fee_calculator, &fee_calculator,
&tx.message, &tx.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &[config.signers[0]]);
log_instruction_custom_error::<VoteError>(result, &config) log_instruction_custom_error::<VoteError>(result, &config)
} }
@@ -531,7 +530,7 @@ pub fn process_vote_update_validator(
&fee_calculator, &fee_calculator,
&tx.message, &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) log_instruction_custom_error::<VoteError>(result, &config)
} }
@@ -636,8 +635,7 @@ pub fn process_withdraw_from_vote_account(
&fee_calculator, &fee_calculator,
&transaction.message, &transaction.message,
)?; )?;
let result = let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
rpc_client.send_and_confirm_transaction_with_spinner(&mut transaction, &config.signers);
log_instruction_custom_error::<VoteError>(result, &config) log_instruction_custom_error::<VoteError>(result, &config)
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-client" name = "solana-client"
version = "1.1.10" version = "1.1.11"
description = "Solana Client" description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" 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 = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.48" serde_json = "1.0.48"
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" } solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
thiserror = "1.0" thiserror = "1.0"
tungstenite = "0.10.1" tungstenite = "0.10.1"
url = "2.1.1" url = "2.1.1"
@@ -31,7 +31,7 @@ url = "2.1.1"
assert_matches = "1.3.0" assert_matches = "1.3.0"
jsonrpc-core = "14.0.5" jsonrpc-core = "14.0.5"
jsonrpc-http-server = "14.0.6" 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] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -50,28 +50,29 @@ impl Into<TransportError> for ClientErrorKind {
#[derive(Error, Debug)] #[derive(Error, Debug)]
#[error("{kind}")] #[error("{kind}")]
pub struct ClientError { pub struct ClientError {
command: Option<&'static str>, request: Option<rpc_request::RpcRequest>,
#[source] #[source]
kind: ClientErrorKind, kind: ClientErrorKind,
} }
impl ClientError { 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 { Self {
command: Some(command), request: Some(request),
kind, kind,
} }
} }
pub fn into_with_command(self, command: &'static str) -> Self { pub fn into_with_request(self, request: rpc_request::RpcRequest) -> Self {
Self { Self {
command: Some(command), request: Some(request),
..self ..self
} }
} }
pub fn command(&self) -> Option<&'static str> { pub fn request(&self) -> Option<&rpc_request::RpcRequest> {
self.command self.request.as_ref()
} }
pub fn kind(&self) -> &ClientErrorKind { pub fn kind(&self) -> &ClientErrorKind {
@@ -82,7 +83,7 @@ impl ClientError {
impl From<ClientErrorKind> for ClientError { impl From<ClientErrorKind> for ClientError {
fn from(kind: ClientErrorKind) -> Self { fn from(kind: ClientErrorKind) -> Self {
Self { Self {
command: None, request: None,
kind, kind,
} }
} }
@@ -91,7 +92,7 @@ impl From<ClientErrorKind> for ClientError {
impl From<TransportError> for ClientError { impl From<TransportError> for ClientError {
fn from(err: TransportError) -> Self { fn from(err: TransportError) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -106,7 +107,7 @@ impl Into<TransportError> for ClientError {
impl From<std::io::Error> for ClientError { impl From<std::io::Error> for ClientError {
fn from(err: std::io::Error) -> Self { fn from(err: std::io::Error) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -115,7 +116,7 @@ impl From<std::io::Error> for ClientError {
impl From<reqwest::Error> for ClientError { impl From<reqwest::Error> for ClientError {
fn from(err: reqwest::Error) -> Self { fn from(err: reqwest::Error) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -124,7 +125,7 @@ impl From<reqwest::Error> for ClientError {
impl From<rpc_request::RpcError> for ClientError { impl From<rpc_request::RpcError> for ClientError {
fn from(err: rpc_request::RpcError) -> Self { fn from(err: rpc_request::RpcError) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -133,7 +134,7 @@ impl From<rpc_request::RpcError> for ClientError {
impl From<serde_json::error::Error> for ClientError { impl From<serde_json::error::Error> for ClientError {
fn from(err: serde_json::error::Error) -> Self { fn from(err: serde_json::error::Error) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -142,7 +143,7 @@ impl From<serde_json::error::Error> for ClientError {
impl From<SignerError> for ClientError { impl From<SignerError> for ClientError {
fn from(err: SignerError) -> Self { fn from(err: SignerError) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }
@@ -151,7 +152,7 @@ impl From<SignerError> for ClientError {
impl From<TransactionError> for ClientError { impl From<TransactionError> for ClientError {
fn from(err: TransactionError) -> Self { fn from(err: TransactionError) -> Self {
Self { Self {
command: None, request: None,
kind: err.into(), kind: err.into(),
} }
} }

View File

@@ -3,7 +3,7 @@ use crate::{client_error::Result, rpc_request::RpcRequest};
pub(crate) trait GenericRpcClientRequest { pub(crate) trait GenericRpcClientRequest {
fn send( fn send(
&self, &self,
request: &RpcRequest, request: RpcRequest,
params: serde_json::Value, params: serde_json::Value,
retries: usize, retries: usize,
) -> Result<serde_json::Value>; ) -> Result<serde_json::Value>;

View File

@@ -40,11 +40,11 @@ impl MockRpcClientRequest {
impl GenericRpcClientRequest for MockRpcClientRequest { impl GenericRpcClientRequest for MockRpcClientRequest {
fn send( fn send(
&self, &self,
request: &RpcRequest, request: RpcRequest,
params: serde_json::Value, params: serde_json::Value,
_retries: usize, _retries: usize,
) -> Result<serde_json::Value> { ) -> 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); return Ok(value);
} }
if self.url == "fails" { if self.url == "fails" {

View File

@@ -24,7 +24,7 @@ use solana_sdk::{
pubkey::Pubkey, pubkey::Pubkey,
signature::Signature, signature::Signature,
signers::Signers, signers::Signers,
transaction::{self, Transaction, TransactionError}, transaction::{self, Transaction},
}; };
use solana_transaction_status::{ use solana_transaction_status::{
ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus, ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus,
@@ -96,32 +96,25 @@ impl RpcClient {
pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<Signature> { pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<Signature> {
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string(); 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() { let signature_base58_str: String =
None => { self.send(RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
Err(RpcError::ForUser("Received result of an unexpected type".to_string()).into())
} let signature = signature_base58_str
Some(signature_base58_str) => { .parse::<Signature>()
let signature = signature_base58_str.parse::<Signature>().map_err(|err| { .map_err(|err| Into::<ClientError>::into(RpcError::ParseError(err.to_string())))?;
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
// A mismatching RPC response signature indicates an issue with the RPC node, and // not have been submitted to the cluster, so callers should verify the success of
// should not be passed along to confirmation methods. The transaction may or may // the correct transaction signature independently.
// not have been submitted to the cluster, so callers should verify the success of if signature != transaction.signatures[0] {
// the correct transaction signature independently. Err(RpcError::RpcRequestError(format!(
if signature != transaction.signatures[0] { "RPC node returned mismatched signature {:?}, expected {:?}",
Err(RpcError::RpcRequestError(format!( signature, transaction.signatures[0]
"RPC node returned mismatched signature {:?}, expected {:?}", ))
signature, transaction.signatures[0] .into())
)) } else {
.into()) Ok(transaction.signatures[0])
} else {
Ok(transaction.signatures[0])
}
}
} }
} }
@@ -137,11 +130,7 @@ impl RpcClient {
signatures: &[Signature], signatures: &[Signature],
) -> RpcResult<Vec<Option<TransactionStatus>>> { ) -> RpcResult<Vec<Option<TransactionStatus>>> {
let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect(); let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
let signature_status = self.send(RpcRequest::GetSignatureStatuses, json!([signatures]), 5)
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"))?)
} }
pub fn get_signature_status_with_commitment( pub fn get_signature_status_with_commitment(
@@ -149,14 +138,11 @@ impl RpcClient {
signature: &Signature, signature: &Signature,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<Option<transaction::Result<()>>> { ) -> ClientResult<Option<transaction::Result<()>>> {
let signature_status = self.client.send( let result: Response<Vec<Option<TransactionStatus>>> = self.send(
&RpcRequest::GetSignatureStatuses, RpcRequest::GetSignatureStatuses,
json!([[signature.to_string()]]), json!([[signature.to_string()]]),
5, 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] Ok(result.value[0]
.clone() .clone()
.filter(|result| result.satisfies_commitment(commitment_config)) .filter(|result| result.satisfies_commitment(commitment_config))
@@ -169,16 +155,13 @@ impl RpcClient {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
search_transaction_history: bool, search_transaction_history: bool,
) -> ClientResult<Option<transaction::Result<()>>> { ) -> ClientResult<Option<transaction::Result<()>>> {
let signature_status = self.client.send( let result: Response<Vec<Option<TransactionStatus>>> = self.send(
&RpcRequest::GetSignatureStatuses, RpcRequest::GetSignatureStatuses,
json!([[signature.to_string()], { json!([[signature.to_string()], {
"searchTransactionHistory": search_transaction_history "searchTransactionHistory": search_transaction_history
}]), }]),
5, 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] Ok(result.value[0]
.clone() .clone()
.filter(|result| result.satisfies_commitment(commitment_config)) .filter(|result| result.satisfies_commitment(commitment_config))
@@ -193,13 +176,14 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<Slot> { ) -> ClientResult<Slot> {
let response = self self.send(RpcRequest::GetSlot, json!([commitment_config]), 0)
.client }
.send(&RpcRequest::GetSlot, json!([commitment_config]), 0)
.map_err(|err| err.into_with_command("GetSlot"))?;
serde_json::from_value(response) pub fn supply_with_commitment(
.map_err(|err| ClientError::new_with_command(err.into(), "GetSlot")) &self,
commitment_config: CommitmentConfig,
) -> RpcResult<RpcSupply> {
self.send(RpcRequest::GetSupply, json!([commitment_config]), 0)
} }
pub fn total_supply(&self) -> ClientResult<u64> { pub fn total_supply(&self) -> ClientResult<u64> {
@@ -210,13 +194,7 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<u64> { ) -> ClientResult<u64> {
let response = self self.send(RpcRequest::GetTotalSupply, json!([commitment_config]), 0)
.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"))
} }
pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> { pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
@@ -227,23 +205,11 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<RpcVoteAccountStatus> { ) -> ClientResult<RpcVoteAccountStatus> {
let response = self self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]), 0)
.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"))
} }
pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> { pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
let response = self self.send(RpcRequest::GetClusterNodes, Value::Null, 0)
.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"))
} }
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> { pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
@@ -255,13 +221,7 @@ impl RpcClient {
slot: Slot, slot: Slot,
encoding: TransactionEncoding, encoding: TransactionEncoding,
) -> ClientResult<ConfirmedBlock> { ) -> ClientResult<ConfirmedBlock> {
let response = self self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]), 0)
.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"))
} }
pub fn get_confirmed_blocks( pub fn get_confirmed_blocks(
@@ -269,17 +229,11 @@ impl RpcClient {
start_slot: Slot, start_slot: Slot,
end_slot: Option<Slot>, end_slot: Option<Slot>,
) -> ClientResult<Vec<Slot>> { ) -> ClientResult<Vec<Slot>> {
let response = self self.send(
.client RpcRequest::GetConfirmedBlocks,
.send( json!([start_slot, end_slot]),
&RpcRequest::GetConfirmedBlocks, 0,
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"))
} }
pub fn get_confirmed_signatures_for_address( pub fn get_confirmed_signatures_for_address(
@@ -288,19 +242,11 @@ impl RpcClient {
start_slot: Slot, start_slot: Slot,
end_slot: Slot, end_slot: Slot,
) -> ClientResult<Vec<Signature>> { ) -> ClientResult<Vec<Signature>> {
let response = self let signatures_base58_str: Vec<String> = self.send(
.client RpcRequest::GetConfirmedSignaturesForAddress,
.send( json!([address.to_string(), start_slot, end_slot]),
&RpcRequest::GetConfirmedSignaturesForAddress, 0,
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 mut signatures = vec![]; let mut signatures = vec![];
for signature_base58_str in signatures_base58_str { for signature_base58_str in signatures_base58_str {
@@ -318,23 +264,16 @@ impl RpcClient {
signature: &Signature, signature: &Signature,
encoding: TransactionEncoding, encoding: TransactionEncoding,
) -> ClientResult<ConfirmedTransaction> { ) -> ClientResult<ConfirmedTransaction> {
let response = self self.send(
.client RpcRequest::GetConfirmedTransaction,
.send( json!([signature.to_string(), encoding]),
&RpcRequest::GetConfirmedTransaction, 0,
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"))
} }
pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> { pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
let response = self let request = RpcRequest::GetBlockTime;
.client let response = self.client.send(request, json!([slot]), 0);
.send(&RpcRequest::GetBlockTime, json!([slot]), 0);
response response
.map(|result_json| { .map(|result_json| {
@@ -342,11 +281,11 @@ impl RpcClient {
return Err(RpcError::ForUser(format!("Block Not Found: slot={}", slot)).into()); return Err(RpcError::ForUser(format!("Block Not Found: slot={}", slot)).into());
} }
let result = serde_json::from_value(result_json) 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); trace!("Response block timestamp {:?} {:?}", slot, result);
Ok(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> { pub fn get_epoch_info(&self) -> ClientResult<RpcEpochInfo> {
@@ -357,13 +296,7 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<RpcEpochInfo> { ) -> ClientResult<RpcEpochInfo> {
let response = self self.send(RpcRequest::GetEpochInfo, json!([commitment_config]), 0)
.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"))
} }
pub fn get_leader_schedule( pub fn get_leader_schedule(
@@ -378,81 +311,43 @@ impl RpcClient {
slot: Option<Slot>, slot: Option<Slot>,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<Option<RpcLeaderSchedule>> { ) -> ClientResult<Option<RpcLeaderSchedule>> {
let response = self self.send(
.client RpcRequest::GetLeaderSchedule,
.send( json!([slot, commitment_config]),
&RpcRequest::GetLeaderSchedule, 0,
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"))
} }
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> { pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
let response = self self.send(RpcRequest::GetEpochSchedule, Value::Null, 0)
.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"))
} }
pub fn get_identity(&self) -> ClientResult<Pubkey> { pub fn get_identity(&self) -> ClientResult<Pubkey> {
let response = self let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null, 0)?;
.client
.send(&RpcRequest::GetIdentity, Value::Null, 0)
.map_err(|err| err.into_with_command("GetIdentity"))?;
serde_json::from_value(response) rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
.map_err(|err| ClientError::new_with_command(err.into(), "GetIdentity")) ClientError::new_with_request(
.and_then(|rpc_identity: RpcIdentity| { RpcError::ParseError("Pubkey".to_string()).into(),
rpc_identity.identity.parse::<Pubkey>().map_err(|_| { RpcRequest::GetIdentity,
ClientError::new_with_command( )
RpcError::ParseError("Pubkey".to_string()).into(), })
"GetIdentity",
)
})
})
} }
pub fn get_inflation(&self) -> ClientResult<Inflation> { pub fn get_inflation(&self) -> ClientResult<Inflation> {
let response = self self.send(RpcRequest::GetInflation, Value::Null, 0)
.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"))
} }
pub fn get_version(&self) -> ClientResult<RpcVersionInfo> { pub fn get_version(&self) -> ClientResult<RpcVersionInfo> {
let response = self self.send(RpcRequest::GetVersion, Value::Null, 0)
.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"))
} }
pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> { pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
let response = self self.send(RpcRequest::MinimumLedgerSlot, Value::Null, 0)
.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"))
} }
pub fn send_and_confirm_transaction<T: Signers>( pub fn send_and_confirm_transaction(
&self, &self,
transaction: &mut Transaction, transaction: &Transaction,
signer_keys: &T,
) -> ClientResult<Signature> { ) -> ClientResult<Signature> {
let mut send_retries = 20; let mut send_retries = 20;
loop { loop {
@@ -476,11 +371,6 @@ impl RpcClient {
send_retries = if let Some(result) = status.clone() { send_retries = if let Some(result) = status.clone() {
match result { match result {
Ok(_) => return Ok(signature), 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, Err(_) => 0,
} }
} else { } else {
@@ -491,7 +381,9 @@ impl RpcClient {
return Err(err.unwrap_err().into()); return Err(err.unwrap_err().into());
} else { } else {
return Err( 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, pubkey: &Pubkey,
retries: usize, retries: usize,
) -> Result<Option<u64>, Box<dyn error::Error>> { ) -> Result<Option<u64>, Box<dyn error::Error>> {
let request = RpcRequest::GetBalance;
let balance_json = self let balance_json = self
.client .client
.send( .send(request, json!([pubkey.to_string()]), retries)
&RpcRequest::GetBalance, .map_err(|err| err.into_with_request(request))?;
json!([pubkey.to_string()]),
retries,
)
.map_err(|err| err.into_with_command("RetryGetBalance"))?;
Ok(Some( Ok(Some(
serde_json::from_value::<Response<u64>>(balance_json) 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, .value,
)) ))
} }
@@ -610,7 +499,7 @@ impl RpcClient {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> RpcResult<Option<Account>> { ) -> RpcResult<Option<Account>> {
let response = self.client.send( let response = self.client.send(
&RpcRequest::GetAccountInfo, RpcRequest::GetAccountInfo,
json!([pubkey.to_string(), commitment_config]), json!([pubkey.to_string(), commitment_config]),
0, 0,
); );
@@ -646,18 +535,14 @@ impl RpcClient {
} }
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult<u64> { pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult<u64> {
let request = RpcRequest::GetMinimumBalanceForRentExemption;
let minimum_balance_json = self let minimum_balance_json = self
.client .client
.send( .send(request, json!([data_len]), 0)
&RpcRequest::GetMinimumBalanceForRentExemption, .map_err(|err| err.into_with_request(request))?;
json!([data_len]),
0,
)
.map_err(|err| err.into_with_command("GetMinimumBalanceForRentExemption"))?;
let minimum_balance: u64 = serde_json::from_value(minimum_balance_json).map_err(|err| { let minimum_balance: u64 = serde_json::from_value(minimum_balance_json)
ClientError::new_with_command(err.into(), "GetMinimumBalanceForRentExemption") .map_err(|err| ClientError::new_with_request(err.into(), request))?;
})?;
trace!( trace!(
"Response minimum balance {:?} {:?}", "Response minimum balance {:?} {:?}",
data_len, data_len,
@@ -678,39 +563,25 @@ impl RpcClient {
pubkey: &Pubkey, pubkey: &Pubkey,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> RpcResult<u64> { ) -> RpcResult<u64> {
let balance_json = self self.send(
.client RpcRequest::GetBalance,
.send( json!([pubkey.to_string(), commitment_config]),
&RpcRequest::GetBalance, 0,
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"))
} }
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> { pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> {
let response = self let accounts: Vec<RpcKeyedAccount> = self.send(
.client RpcRequest::GetProgramAccounts,
.send( json!([pubkey.to_string()]),
&RpcRequest::GetProgramAccounts, 0,
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 mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new(); let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new();
for RpcKeyedAccount { pubkey, account } in accounts.into_iter() { for RpcKeyedAccount { pubkey, account } in accounts.into_iter() {
let pubkey = pubkey.parse().map_err(|_| { let pubkey = pubkey.parse().map_err(|_| {
ClientError::new_with_command( ClientError::new_with_request(
RpcError::ParseError("Pubkey".to_string()).into(), RpcError::ParseError("Pubkey".to_string()).into(),
"GetProgramAccounts", RpcRequest::GetProgramAccounts,
) )
})?; })?;
pubkey_accounts.push((pubkey, account.decode().unwrap())); pubkey_accounts.push((pubkey, account.decode().unwrap()));
@@ -727,17 +598,11 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> ClientResult<u64> { ) -> ClientResult<u64> {
let response = self self.send(
.client RpcRequest::GetTransactionCount,
.send( json!([commitment_config]),
&RpcRequest::GetTransactionCount, 0,
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"))
} }
pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> { pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> {
@@ -750,15 +615,6 @@ impl RpcClient {
&self, &self,
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
) -> RpcResult<(Hash, FeeCalculator)> { ) -> RpcResult<(Hash, FeeCalculator)> {
let response = self
.client
.send(
&RpcRequest::GetRecentBlockhash,
json!([commitment_config]),
0,
)
.map_err(|err| err.into_with_command("GetRecentBlockhash"))?;
let Response { let Response {
context, context,
value: value:
@@ -766,12 +622,16 @@ impl RpcClient {
blockhash, blockhash,
fee_calculator, fee_calculator,
}, },
} = serde_json::from_value::<Response<RpcBlockhashFeeCalculator>>(response) } = self.send::<Response<RpcBlockhashFeeCalculator>>(
.map_err(|err| ClientError::new_with_command(err.into(), "GetRecentBlockhash"))?; RpcRequest::GetRecentBlockhash,
json!([commitment_config]),
0,
)?;
let blockhash = blockhash.parse().map_err(|_| { let blockhash = blockhash.parse().map_err(|_| {
ClientError::new_with_command( ClientError::new_with_request(
RpcError::ParseError("Hash".to_string()).into(), RpcError::ParseError("Hash".to_string()).into(),
"GetRecentBlockhash", RpcRequest::GetRecentBlockhash,
) )
})?; })?;
Ok(Response { Ok(Response {
@@ -784,31 +644,25 @@ impl RpcClient {
&self, &self,
blockhash: &Hash, blockhash: &Hash,
) -> ClientResult<Option<FeeCalculator>> { ) -> ClientResult<Option<FeeCalculator>> {
let response = self let Response { value, .. } = self.send::<Response<Option<RpcFeeCalculator>>>(
.client RpcRequest::GetFeeCalculatorForBlockhash,
.send( json!([blockhash.to_string()]),
&RpcRequest::GetFeeCalculatorForBlockhash, 0,
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"))?;
Ok(value.map(|rf| rf.fee_calculator)) Ok(value.map(|rf| rf.fee_calculator))
} }
pub fn get_fee_rate_governor(&self) -> RpcResult<FeeRateGovernor> { 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 { let Response {
context, context,
value: RpcFeeRateGovernor { fee_rate_governor }, value: RpcFeeRateGovernor { fee_rate_governor },
} = serde_json::from_value::<Response<RpcFeeRateGovernor>>(response) } = self.send::<Response<RpcFeeRateGovernor>>(
.map_err(|e| ClientError::new_with_command(e.into(), "GetFeeRateGovernor"))?; RpcRequest::GetFeeRateGovernor,
Value::Null,
0,
)?;
Ok(Response { Ok(Response {
context, context,
value: fee_rate_governor, value: fee_rate_governor,
@@ -842,18 +696,11 @@ impl RpcClient {
} }
pub fn get_genesis_hash(&self) -> ClientResult<Hash> { pub fn get_genesis_hash(&self) -> ClientResult<Hash> {
let response = self let hash_str: String = self.send(RpcRequest::GetGenesisHash, Value::Null, 0)?;
.client let hash = hash_str.parse().map_err(|_| {
.send(&RpcRequest::GetGenesisHash, Value::Null, 0) ClientError::new_with_request(
.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(
RpcError::ParseError("Hash".to_string()).into(), RpcError::ParseError("Hash".to_string()).into(),
"GetGenesisHash", RpcRequest::GetGenesisHash,
) )
})?; })?;
Ok(hash) Ok(hash)
@@ -909,7 +756,7 @@ impl RpcClient {
return balance_result.ok(); return balance_result.ok();
} }
trace!( trace!(
"retry_get_balance[{}] {:?} {:?}", "wait_for_balance_with_commitment [{}] {:?} {:?}",
run, run,
balance_result, balance_result,
expected_balance expected_balance
@@ -1042,23 +889,18 @@ impl RpcClient {
&self, &self,
signature: &Signature, signature: &Signature,
) -> ClientResult<usize> { ) -> ClientResult<usize> {
let response = self let result: Response<Vec<Option<TransactionStatus>>> = self.send(
.client RpcRequest::GetSignatureStatuses,
.send( json!([[signature.to_string()]]),
&RpcRequest::GetSignatureStatuses, 5,
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 confirmations = result.value[0] let confirmations = result.value[0]
.clone() .clone()
.ok_or_else(|| { .ok_or_else(|| {
ClientError::new_with_command( ClientError::new_with_request(
ClientErrorKind::Custom("signature not found".to_string()), ClientErrorKind::Custom("signature not found".to_string()),
"GetSignatureStatuses", RpcRequest::GetSignatureStatuses,
) )
})? })?
.confirmations .confirmations
@@ -1066,10 +908,9 @@ impl RpcClient {
Ok(confirmations) Ok(confirmations)
} }
pub fn send_and_confirm_transaction_with_spinner<T: Signers>( pub fn send_and_confirm_transaction_with_spinner(
&self, &self,
transaction: &mut Transaction, transaction: &Transaction,
signer_keys: &T,
) -> ClientResult<Signature> { ) -> ClientResult<Signature> {
let mut confirmations = 0; let mut confirmations = 0;
@@ -1106,11 +947,6 @@ impl RpcClient {
send_retries = if let Some(result) = status.clone() { send_retries = if let Some(result) = status.clone() {
match result { match result {
Ok(_) => 0, 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 // If transaction errors, return right away; no point in counting confirmations
Err(_) => 0, Err(_) => 0,
} }
@@ -1128,9 +964,13 @@ impl RpcClient {
} }
} }
} else { } else {
return Err( return Err(RpcError::ForUser(
RpcError::ForUser("unable to confirm transaction. This can happen in situations such as transaction expiration and insufficient fee-payer funds".to_string()).into(), "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); .unwrap_or(confirmations);
if now.elapsed().as_secs() >= MAX_HASH_AGE_IN_SECONDS as u64 { if now.elapsed().as_secs() >= MAX_HASH_AGE_IN_SECONDS as u64 {
return Err( 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> { pub fn validator_exit(&self) -> ClientResult<bool> {
let response = self self.send(RpcRequest::ValidatorExit, Value::Null, 0)
.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"))
} }
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()); 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_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(rpc_addr); let rpc_client = RpcClient::new_socket(rpc_addr);
let balance = rpc_client.send( let balance: u64 = rpc_client
&RpcRequest::GetBalance, .send(
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]), RpcRequest::GetBalance,
0, json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
); 0,
assert_eq!(balance.unwrap().as_u64().unwrap(), 50); )
.unwrap();
assert_eq!(balance, 50);
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, Value::Null, 0); let blockhash: String = rpc_client
assert_eq!( .send(RpcRequest::GetRecentBlockhash, Value::Null, 0)
blockhash.unwrap().as_str().unwrap(), .unwrap();
"deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx" assert_eq!(blockhash, "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
);
// Send erroneous parameter // 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); assert_eq!(blockhash.is_err(), true);
} }
@@ -1290,12 +1137,14 @@ mod tests {
let rpc_addr = receiver.recv().unwrap(); let rpc_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(rpc_addr); let rpc_client = RpcClient::new_socket(rpc_addr);
let balance = rpc_client.send( let balance: u64 = rpc_client
&RpcRequest::GetBalance, .send(
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]), RpcRequest::GetBalance,
10, json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]),
); 10,
assert_eq!(balance.unwrap().as_u64().unwrap(), 5); )
.unwrap();
assert_eq!(balance, 5);
} }
#[test] #[test]
@@ -1358,17 +1207,16 @@ mod tests {
let key = Keypair::new(); let key = Keypair::new();
let to = Pubkey::new_rand(); let to = Pubkey::new_rand();
let blockhash = Hash::default(); let blockhash = Hash::default();
let mut tx = system_transaction::transfer(&key, &to, 50, blockhash); let tx = system_transaction::transfer(&key, &to, 50, blockhash);
let result = rpc_client.send_and_confirm_transaction(&tx);
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&key]);
result.unwrap(); result.unwrap();
let rpc_client = RpcClient::new_mock("account_in_use".to_string()); 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()); assert!(result.is_err());
let rpc_client = RpcClient::new_mock("instruction_error".to_string()); 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!( assert_matches!(
result.unwrap_err().kind(), result.unwrap_err().kind(),
ClientErrorKind::TransactionError(TransactionError::InstructionError( ClientErrorKind::TransactionError(TransactionError::InstructionError(
@@ -1378,7 +1226,7 @@ mod tests {
); );
let rpc_client = RpcClient::new_mock("sig_not_found".to_string()); 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() { if let ClientErrorKind::Io(err) = result.unwrap_err().kind() {
assert_eq!(err.kind(), io::ErrorKind::Other); assert_eq!(err.kind(), io::ErrorKind::Other);
} }

View File

@@ -31,7 +31,7 @@ impl RpcClientRequest {
impl GenericRpcClientRequest for RpcClientRequest { impl GenericRpcClientRequest for RpcClientRequest {
fn send( fn send(
&self, &self,
request: &RpcRequest, request: RpcRequest,
params: serde_json::Value, params: serde_json::Value,
mut retries: usize, mut retries: usize,
) -> Result<serde_json::Value> { ) -> Result<serde_json::Value> {

View File

@@ -1,7 +1,8 @@
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::fmt;
use thiserror::Error; use thiserror::Error;
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum RpcRequest { pub enum RpcRequest {
DeregisterNode, DeregisterNode,
ValidatorExit, ValidatorExit,
@@ -30,6 +31,7 @@ pub enum RpcRequest {
GetStorageTurnRate, GetStorageTurnRate,
GetSlotsPerSegment, GetSlotsPerSegment,
GetStoragePubkeysForSlot, GetStoragePubkeysForSlot,
GetSupply,
GetTotalSupply, GetTotalSupply,
GetTransactionCount, GetTransactionCount,
GetVersion, GetVersion,
@@ -42,12 +44,8 @@ pub enum RpcRequest {
MinimumLedgerSlot, MinimumLedgerSlot,
} }
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256; impl fmt::Display for RpcRequest {
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000; fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl RpcRequest {
pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value {
let jsonrpc = "2.0";
let method = match self { let method = match self {
RpcRequest::DeregisterNode => "deregisterNode", RpcRequest::DeregisterNode => "deregisterNode",
RpcRequest::ValidatorExit => "validatorExit", RpcRequest::ValidatorExit => "validatorExit",
@@ -76,6 +74,7 @@ impl RpcRequest {
RpcRequest::GetStorageTurnRate => "getStorageTurnRate", RpcRequest::GetStorageTurnRate => "getStorageTurnRate",
RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment", RpcRequest::GetSlotsPerSegment => "getSlotsPerSegment",
RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot", RpcRequest::GetStoragePubkeysForSlot => "getStoragePubkeysForSlot",
RpcRequest::GetSupply => "getSupply",
RpcRequest::GetTotalSupply => "getTotalSupply", RpcRequest::GetTotalSupply => "getTotalSupply",
RpcRequest::GetTransactionCount => "getTransactionCount", RpcRequest::GetTransactionCount => "getTransactionCount",
RpcRequest::GetVersion => "getVersion", RpcRequest::GetVersion => "getVersion",
@@ -87,10 +86,21 @@ impl RpcRequest {
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption", RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
RpcRequest::MinimumLedgerSlot => "minimumLedgerSlot", 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!({ json!({
"jsonrpc": jsonrpc, "jsonrpc": jsonrpc,
"id": id, "id": id,
"method": method, "method": format!("{}", self),
"params": params, "params": params,
}) })
} }

View File

@@ -108,6 +108,8 @@ pub struct RpcContactInfo {
pub tpu: Option<SocketAddr>, pub tpu: Option<SocketAddr>,
/// JSON RPC port /// JSON RPC port
pub rpc: Option<SocketAddr>, 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 /// 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 address: String,
pub lamports: u64, 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>,
}

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "solana-core" name = "solana-core"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
documentation = "https://docs.rs/solana" documentation = "https://docs.rs/solana"
homepage = "https://solana.com/" homepage = "https://solana.com/"
readme = "../README.md" readme = "../README.md"
@@ -41,36 +41,37 @@ regex = "1.3.6"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.48" serde_json = "1.0.48"
solana-bpf-loader-program = { path = "../programs/bpf_loader", 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.10" } solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" } solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
solana-faucet = { path = "../faucet", version = "1.1.10" } solana-faucet = { path = "../faucet", version = "1.1.11" }
ed25519-dalek = "=1.0.0-pre.3" ed25519-dalek = "=1.0.0-pre.3"
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.10" } solana-merkle-tree = { path = "../merkle-tree", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
solana-measure = { path = "../measure", version = "1.1.10" } solana-measure = { path = "../measure", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-chacha-cuda = { path = "../chacha-cuda", version = "1.1.10" } solana-chacha-cuda = { path = "../chacha-cuda", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
solana-streamer = { path = "../streamer", version = "1.1.10" } solana-streamer = { path = "../streamer", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-version = { path = "../version", version = "1.1.11" }
solana-vote-signer = { path = "../vote-signer", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
solana-sys-tuner = { path = "../sys-tuner", version = "1.1.10" } solana-vote-signer = { path = "../vote-signer", version = "1.1.11" }
solana-sys-tuner = { path = "../sys-tuner", version = "1.1.11" }
tempfile = "3.1.0" tempfile = "3.1.0"
thiserror = "1.0" thiserror = "1.0"
tokio = "0.1" tokio = "0.1"
tokio-codec = "0.1" tokio-codec = "0.1"
tokio-fs = "0.1" tokio-fs = "0.1"
tokio-io = "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" trees = "0.2.1"
[dev-dependencies] [dev-dependencies]

View File

@@ -18,8 +18,8 @@ use crate::{
crds_gossip_error::CrdsGossipError, crds_gossip_error::CrdsGossipError,
crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS}, crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
crds_value::{ crds_value::{
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash, Vote, self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, SnapshotHash,
MAX_WALLCLOCK, Version, Vote, MAX_WALLCLOCK,
}, },
epoch_slots::EpochSlots, epoch_slots::EpochSlots,
result::{Error, Result}, result::{Error, Result},
@@ -378,6 +378,7 @@ impl ClusterInfo {
archivers += 1; 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) { if my_shred_version != 0 && (node.shred_version != 0 && node.shred_version != my_shred_version) {
different_shred_nodes += 1; different_shred_nodes += 1;
None None
@@ -393,10 +394,9 @@ impl ClusterInfo {
"none".to_string() "none".to_string()
} }
} }
let ip_addr = node.gossip.ip(); let ip_addr = node.gossip.ip();
Some(format!( 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) { if ContactInfo::is_valid_address(&node.gossip) {
ip_addr.to_string() ip_addr.to_string()
} else { } else {
@@ -405,6 +405,11 @@ impl ClusterInfo {
if node.id == my_pubkey { "me" } else { "" }.to_string(), if node.id == my_pubkey { "me" } else { "" }.to_string(),
now.saturating_sub(last_updated), now.saturating_sub(last_updated),
node.id.to_string(), 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.gossip),
addr_to_string(&ip_addr, &node.tpu), addr_to_string(&ip_addr, &node.tpu),
addr_to_string(&ip_addr, &node.tpu_forwards), 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.tvu_forwards),
addr_to_string(&ip_addr, &node.repair), addr_to_string(&ip_addr, &node.repair),
addr_to_string(&ip_addr, &node.serve_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),
addr_to_string(&ip_addr, &node.rpc_pubsub), addr_to_string(&ip_addr, &node.rpc_pubsub),
node.shred_version, node.shred_version,
@@ -423,9 +427,9 @@ impl ClusterInfo {
format!( format!(
"IP Address |Age(ms)| Node identifier \ "IP Address |Age(ms)| Node identifier \
|Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR|Storag| RPC |PubSub|ShredVer\n\ | Version |Gossip| TPU |TPUfwd| TVU |TVUfwd|Repair|ServeR| RPC |PubSub|ShredVer\n\
------------------+-------+----------------------------------------------+\ ------------------+-------+----------------------------------------------+---------------+\
------+------+------+------+------+------+------+------+------+------+--------\n\ ------+------+------+------+------+------+------+------+------+--------\n\
{}\ {}\
Nodes: {}{}{}{}", Nodes: {}{}{}{}",
nodes.join(""), nodes.join(""),
@@ -440,7 +444,7 @@ impl ClusterInfo {
} else { } else {
"".to_string() "".to_string()
}, },
if spy_nodes > 0 { if different_shred_nodes > 0 {
format!( format!(
"\nNodes with different shred version: {}", "\nNodes with different shred version: {}",
different_shred_nodes different_shred_nodes
@@ -703,6 +707,18 @@ impl ClusterInfo {
(vec, max) (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`. /// all validators that have a valid rpc port regardless of `shred_version`.
pub fn all_rpc_peers(&self) -> Vec<ContactInfo> { pub fn all_rpc_peers(&self) -> Vec<ContactInfo> {
self.gossip self.gossip
@@ -1313,6 +1329,9 @@ impl ClusterInfo {
let mut last_contact_info_trace = timestamp(); let mut last_contact_info_trace = timestamp();
let mut adopt_shred_version = obj.my_shred_version() == 0; let mut adopt_shred_version = obj.my_shred_version() == 0;
let recycler = PacketsRecycler::default(); let recycler = PacketsRecycler::default();
let message = CrdsData::Version(Version::new(obj.id()));
obj.push_message(CrdsValue::new_signed(message, &obj.keypair));
loop { loop {
let start = timestamp(); let start = timestamp();
thread_mem_usage::datapoint("solana-gossip"); thread_mem_usage::datapoint("solana-gossip");

View File

@@ -75,6 +75,7 @@ pub enum CrdsData {
SnapshotHashes(SnapshotHash), SnapshotHashes(SnapshotHash),
AccountsHashes(SnapshotHash), AccountsHashes(SnapshotHash),
EpochSlots(EpochSlotsIndex, EpochSlots), EpochSlots(EpochSlotsIndex, EpochSlots),
Version(Version),
} }
impl Sanitize for CrdsData { impl Sanitize for CrdsData {
@@ -101,6 +102,7 @@ impl Sanitize for CrdsData {
} }
val.sanitize() 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 /// Type of the replicated value
/// These are labels for values in a record that is associated with `Pubkey` /// These are labels for values in a record that is associated with `Pubkey`
#[derive(PartialEq, Hash, Eq, Clone, Debug)] #[derive(PartialEq, Hash, Eq, Clone, Debug)]
@@ -216,6 +245,7 @@ pub enum CrdsValueLabel {
SnapshotHashes(Pubkey), SnapshotHashes(Pubkey),
EpochSlots(EpochSlotsIndex, Pubkey), EpochSlots(EpochSlotsIndex, Pubkey),
AccountsHashes(Pubkey), AccountsHashes(Pubkey),
Version(Pubkey),
} }
impl fmt::Display for CrdsValueLabel { impl fmt::Display for CrdsValueLabel {
@@ -227,6 +257,7 @@ impl fmt::Display for CrdsValueLabel {
CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()), CrdsValueLabel::SnapshotHashes(_) => write!(f, "SnapshotHash({})", self.pubkey()),
CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()), CrdsValueLabel::EpochSlots(ix, _) => write!(f, "EpochSlots({}, {})", ix, self.pubkey()),
CrdsValueLabel::AccountsHashes(_) => write!(f, "AccountsHashes({})", 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::SnapshotHashes(p) => *p,
CrdsValueLabel::EpochSlots(_, p) => *p, CrdsValueLabel::EpochSlots(_, p) => *p,
CrdsValueLabel::AccountsHashes(p) => *p, CrdsValueLabel::AccountsHashes(p) => *p,
CrdsValueLabel::Version(p) => *p,
} }
} }
} }
@@ -257,7 +289,7 @@ impl CrdsValue {
value.sign(keypair); value.sign(keypair);
value 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. /// Latest wallclock is always picked.
/// This is used to time out push messages. /// This is used to time out push messages.
pub fn wallclock(&self) -> u64 { pub fn wallclock(&self) -> u64 {
@@ -268,6 +300,7 @@ impl CrdsValue {
CrdsData::SnapshotHashes(hash) => hash.wallclock, CrdsData::SnapshotHashes(hash) => hash.wallclock,
CrdsData::AccountsHashes(hash) => hash.wallclock, CrdsData::AccountsHashes(hash) => hash.wallclock,
CrdsData::EpochSlots(_, p) => p.wallclock, CrdsData::EpochSlots(_, p) => p.wallclock,
CrdsData::Version(version) => version.wallclock,
} }
} }
pub fn pubkey(&self) -> Pubkey { pub fn pubkey(&self) -> Pubkey {
@@ -278,6 +311,7 @@ impl CrdsValue {
CrdsData::SnapshotHashes(hash) => hash.from, CrdsData::SnapshotHashes(hash) => hash.from,
CrdsData::AccountsHashes(hash) => hash.from, CrdsData::AccountsHashes(hash) => hash.from,
CrdsData::EpochSlots(_, p) => p.from, CrdsData::EpochSlots(_, p) => p.from,
CrdsData::Version(version) => version.from,
} }
} }
pub fn label(&self) -> CrdsValueLabel { pub fn label(&self) -> CrdsValueLabel {
@@ -288,6 +322,7 @@ impl CrdsValue {
CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()), CrdsData::SnapshotHashes(_) => CrdsValueLabel::SnapshotHashes(self.pubkey()),
CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()), CrdsData::AccountsHashes(_) => CrdsValueLabel::AccountsHashes(self.pubkey()),
CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()), CrdsData::EpochSlots(ix, _) => CrdsValueLabel::EpochSlots(*ix, self.pubkey()),
CrdsData::Version(_) => CrdsValueLabel::Version(self.pubkey()),
} }
} }
pub fn contact_info(&self) -> Option<&ContactInfo> { 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. /// Return all the possible labels for a record identified by Pubkey.
pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> { pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> {
let mut labels = vec![ let mut labels = vec![
@@ -345,6 +387,7 @@ impl CrdsValue {
CrdsValueLabel::LowestSlot(*key), CrdsValueLabel::LowestSlot(*key),
CrdsValueLabel::SnapshotHashes(*key), CrdsValueLabel::SnapshotHashes(*key),
CrdsValueLabel::AccountsHashes(*key), CrdsValueLabel::AccountsHashes(*key),
CrdsValueLabel::Version(*key),
]; ];
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key))); labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
labels.extend((0..MAX_EPOCH_SLOTS).map(|ix| CrdsValueLabel::EpochSlots(ix, *key))); labels.extend((0..MAX_EPOCH_SLOTS).map(|ix| CrdsValueLabel::EpochSlots(ix, *key)));
@@ -395,7 +438,7 @@ mod test {
#[test] #[test]
fn test_labels() { 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 // this method should cover all the possible labels
for v in &CrdsValue::record_labels(&Pubkey::default()) { for v in &CrdsValue::record_labels(&Pubkey::default()) {
match v { match v {
@@ -403,9 +446,10 @@ mod test {
CrdsValueLabel::LowestSlot(_) => hits[1] = true, CrdsValueLabel::LowestSlot(_) => hits[1] = true,
CrdsValueLabel::SnapshotHashes(_) => hits[2] = true, CrdsValueLabel::SnapshotHashes(_) => hits[2] = true,
CrdsValueLabel::AccountsHashes(_) => hits[3] = 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, _) => { CrdsValueLabel::EpochSlots(ix, _) => {
hits[*ix as usize + MAX_VOTES as usize + 4] = true hits[*ix as usize + MAX_VOTES as usize + 5] = true
} }
} }
} }

View File

@@ -30,6 +30,7 @@ pub mod gen_keys;
pub mod gossip_service; pub mod gossip_service;
pub mod ledger_cleanup_service; pub mod ledger_cleanup_service;
pub mod local_vote_signer_service; pub mod local_vote_signer_service;
pub mod non_circulating_supply;
pub mod poh_recorder; pub mod poh_recorder;
pub mod poh_service; pub mod poh_service;
pub mod progress_map; pub mod progress_map;
@@ -39,6 +40,7 @@ mod result;
pub mod retransmit_stage; pub mod retransmit_stage;
pub mod rewards_recorder_service; pub mod rewards_recorder_service;
pub mod rpc; pub mod rpc;
pub mod rpc_error;
pub mod rpc_pubsub; pub mod rpc_pubsub;
pub mod rpc_pubsub_service; pub mod rpc_pubsub_service;
pub mod rpc_service; pub mod rpc_service;

View 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
);
}
}

View File

@@ -17,12 +17,15 @@ use solana_ledger::{
use solana_measure::measure::Measure; use solana_measure::measure::Measure;
use solana_metrics::inc_new_counter_error; use solana_metrics::inc_new_counter_error;
use solana_perf::packet::Packets; use solana_perf::packet::Packets;
use solana_sdk::clock::Slot;
use solana_sdk::epoch_schedule::EpochSchedule; use solana_sdk::epoch_schedule::EpochSchedule;
use solana_sdk::timing::timestamp;
use solana_streamer::streamer::PacketReceiver; use solana_streamer::streamer::PacketReceiver;
use std::{ use std::{
cmp, cmp,
collections::{BTreeMap, HashMap},
net::UdpSocket, net::UdpSocket,
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, AtomicU64, Ordering},
sync::mpsc::channel, sync::mpsc::channel,
sync::mpsc::RecvTimeoutError, sync::mpsc::RecvTimeoutError,
sync::Mutex, sync::Mutex,
@@ -35,6 +38,115 @@ use std::{
// it doesn't pull up too much work. // it doesn't pull up too much work.
const MAX_PACKET_BATCH_SIZE: usize = 100; 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( fn retransmit(
bank_forks: &Arc<RwLock<BankForks>>, bank_forks: &Arc<RwLock<BankForks>>,
leader_schedule_cache: &Arc<LeaderScheduleCache>, leader_schedule_cache: &Arc<LeaderScheduleCache>,
@@ -42,6 +154,7 @@ fn retransmit(
r: &Arc<Mutex<PacketReceiver>>, r: &Arc<Mutex<PacketReceiver>>,
sock: &UdpSocket, sock: &UdpSocket,
id: u32, id: u32,
stats: &Arc<RetransmitStats>,
) -> Result<()> { ) -> Result<()> {
let timer = Duration::new(1, 0); let timer = Duration::new(1, 0);
let r_lock = r.lock().unwrap(); let r_lock = r.lock().unwrap();
@@ -69,6 +182,8 @@ fn retransmit(
let mut repair_total = 0; let mut repair_total = 0;
let mut retransmit_total = 0; let mut retransmit_total = 0;
let mut compute_turbine_peers_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 mut packets in packet_v {
for packet in packets.packets.iter_mut() { for packet in packets.packets.iter_mut() {
// skip discarded packets and repair packets // skip discarded packets and repair packets
@@ -103,7 +218,12 @@ fn retransmit(
let neighbors: Vec<_> = neighbors.into_iter().map(|index| &peers[index]).collect(); let neighbors: Vec<_> = neighbors.into_iter().map(|index| &peers[index]).collect();
let children: Vec<_> = children.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.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 = let leader =
leader_schedule_cache.slot_leader_at(packet.meta.slot, Some(r_bank.as_ref())); 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)?; ClusterInfo::retransmit_to(&children, packet, leader, sock, true)?;
} }
retransmit_time.stop(); retransmit_time.stop();
retransmit_total += retransmit_time.as_ms(); retransmit_total += retransmit_time.as_us();
} }
} }
timer_start.stop(); timer_start.stop();
@@ -126,16 +246,19 @@ fn retransmit(
retransmit_total, retransmit_total,
id, id,
); );
datapoint_debug!("cluster_info-num_nodes", ("count", peers_len, i64)); update_retransmit_stats(
datapoint_debug!( stats,
"retransmit-stage", timer_start.as_us(),
("total_time", timer_start.as_ms() as i64, i64), total_packets,
("total_packets", total_packets as i64, i64), retransmit_total,
("retransmit_total", retransmit_total as i64, i64), discard_total,
("compute_turbine", compute_turbine_peers_total as i64, i64), repair_total,
("repair_total", i64::from(repair_total), i64), compute_turbine_peers_total,
("discard_total", i64::from(discard_total), i64), peers_len,
packets_by_slot,
packets_by_source,
); );
Ok(()) Ok(())
} }
@@ -154,6 +277,7 @@ pub fn retransmitter(
cluster_info: Arc<ClusterInfo>, cluster_info: Arc<ClusterInfo>,
r: Arc<Mutex<PacketReceiver>>, r: Arc<Mutex<PacketReceiver>>,
) -> Vec<JoinHandle<()>> { ) -> Vec<JoinHandle<()>> {
let stats = Arc::new(RetransmitStats::default());
(0..sockets.len()) (0..sockets.len())
.map(|s| { .map(|s| {
let sockets = sockets.clone(); let sockets = sockets.clone();
@@ -161,6 +285,7 @@ pub fn retransmitter(
let leader_schedule_cache = leader_schedule_cache.clone(); let leader_schedule_cache = leader_schedule_cache.clone();
let r = r.clone(); let r = r.clone();
let cluster_info = cluster_info.clone(); let cluster_info = cluster_info.clone();
let stats = stats.clone();
Builder::new() Builder::new()
.name("solana-retransmitter".to_string()) .name("solana-retransmitter".to_string())
@@ -174,6 +299,7 @@ pub fn retransmitter(
&r, &r,
&sockets[s], &sockets[s],
s as u32, s as u32,
&stats,
) { ) {
match e { match e {
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break, Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,

View File

@@ -4,11 +4,13 @@ use crate::{
cluster_info::ClusterInfo, cluster_info::ClusterInfo,
commitment::{BlockCommitmentArray, BlockCommitmentCache}, commitment::{BlockCommitmentArray, BlockCommitmentCache},
contact_info::ContactInfo, contact_info::ContactInfo,
non_circulating_supply::calculate_non_circulating_supply,
rpc_error::RpcCustomError,
storage_stage::StorageState, storage_stage::StorageState,
validator::ValidatorExit, validator::ValidatorExit,
}; };
use bincode::serialize; use bincode::serialize;
use jsonrpc_core::{Error, ErrorCode, Metadata, Result}; use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc; use jsonrpc_derive::rpc;
use solana_client::{ use solana_client::{
rpc_request::{ rpc_request::{
@@ -17,7 +19,9 @@ use solana_client::{
rpc_response::*, rpc_response::*,
}; };
use solana_faucet::faucet::request_airdrop_transaction; 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_perf::packet::PACKET_DATA_SIZE;
use solana_runtime::{accounts::AccountAddressFilter, bank::Bank}; use solana_runtime::{accounts::AccountAddressFilter, bank::Bank};
use solana_sdk::{ use solana_sdk::{
@@ -45,7 +49,6 @@ use std::{
time::{Duration, Instant}, time::{Duration, Instant},
}; };
const JSON_RPC_SERVER_ERROR_0: i64 = -32000;
const NUM_LARGEST_ACCOUNTS: usize = 20; const NUM_LARGEST_ACCOUNTS: usize = 20;
type RpcResponse<T> = Result<Response<T>>; type RpcResponse<T> = Result<Response<T>>;
@@ -102,18 +105,13 @@ impl JsonRpcRequestProcessor {
.unwrap() .unwrap()
.largest_confirmed_root(); .largest_confirmed_root();
debug!("RPC using block: {:?}", cluster_root); debug!("RPC using block: {:?}", cluster_root);
r_bank_forks r_bank_forks.get(cluster_root).cloned().ok_or_else(|| {
.get(cluster_root) RpcCustomError::NonexistentClusterRoot {
.cloned() cluster_root,
.ok_or_else(|| Error { node_root: r_bank_forks.root(),
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_0), }
message: format!( .into()
"Cluster largest_confirmed_root {} does not exist on node. Node root: {}", })
cluster_root,
r_bank_forks.root(),
),
data: None,
})
} }
} }
@@ -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( fn get_vote_accounts(
&self, &self,
commitment: Option<CommitmentConfig>, 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( pub fn get_confirmed_block(
&self, &self,
slot: Slot, slot: Slot,
@@ -417,7 +457,9 @@ impl JsonRpcRequestProcessor {
.unwrap() .unwrap()
.largest_confirmed_root() .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 { } else {
Ok(None) Ok(None)
} }
@@ -465,11 +507,9 @@ impl JsonRpcRequestProcessor {
let stakes = HashMap::new(); let stakes = HashMap::new();
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes); let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);
Ok(self let result = self.blockstore.get_block_time(slot, slot_duration, stakes);
.blockstore self.check_slot_cleaned_up(&result, slot)?;
.get_block_time(slot, slot_duration, stakes) Ok(result.ok().unwrap_or(None))
.ok()
.unwrap_or(None))
} else { } else {
Ok(None) Ok(None)
} }
@@ -795,6 +835,7 @@ pub trait RpcSol {
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> Result<u64>; ) -> Result<u64>;
// DEPRECATED
#[rpc(meta, name = "getTotalSupply")] #[rpc(meta, name = "getTotalSupply")]
fn get_total_supply( fn get_total_supply(
&self, &self,
@@ -809,6 +850,13 @@ pub trait RpcSol {
commitment: Option<CommitmentConfig>, commitment: Option<CommitmentConfig>,
) -> RpcResponse<Vec<RpcAccountBalance>>; ) -> RpcResponse<Vec<RpcAccountBalance>>;
#[rpc(meta, name = "getSupply")]
fn get_supply(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> RpcResponse<RpcSupply>;
#[rpc(meta, name = "requestAirdrop")] #[rpc(meta, name = "requestAirdrop")]
fn request_airdrop( fn request_airdrop(
&self, &self,
@@ -1024,6 +1072,9 @@ impl RpcSol for RpcSolImpl {
gossip: Some(contact_info.gossip), gossip: Some(contact_info.gossip),
tpu: valid_address_or_none(&contact_info.tpu), tpu: valid_address_or_none(&contact_info.tpu),
rpc: valid_address_or_none(&contact_info.rpc), rpc: valid_address_or_none(&contact_info.rpc),
version: cluster_info
.get_node_version(&contact_info.id)
.map(|v| v.to_string()),
}) })
} else { } else {
None // Exclude spy nodes None // Exclude spy nodes
@@ -1222,6 +1273,18 @@ impl RpcSol for RpcSolImpl {
.get_largest_accounts(commitment) .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( fn request_airdrop(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
@@ -1414,7 +1477,7 @@ impl RpcSol for RpcSolImpl {
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> { fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
Ok(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"); .expect("actual response deserialization");
let expected = format!( 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, leader_pubkey,
rpc_port::DEFAULT_RPC_PORT rpc_port::DEFAULT_RPC_PORT
); );
@@ -2577,7 +2640,7 @@ pub mod tests {
let expected = json!({ let expected = json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"result": { "result": {
"solana-core": solana_clap_utils::version!().to_string() "solana-core": solana_version::version!().to_string()
}, },
"id": 1 "id": 1
}); });

45
core/src/rpc_error.rs Normal file
View 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,
},
}
}
}

View File

@@ -22,12 +22,23 @@ use std::time::Instant;
pub type ShredsReceived = HashMap<Slot, BitVec<u64>>; 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 { pub struct ShredFetchStage {
thread_hdls: Vec<JoinHandle<()>>, thread_hdls: Vec<JoinHandle<()>>,
} }
impl ShredFetchStage { 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_start = OFFSET_OF_SHRED_INDEX;
let index_end = index_start + SIZE_OF_SHRED_INDEX; let index_end = index_start + SIZE_OF_SHRED_INDEX;
let slot_start = OFFSET_OF_SHRED_SLOT; 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 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]) { if let Ok(slot) = limited_deserialize::<Slot>(&p.data[slot_start..slot_end]) {
return Some((slot, index)); return Some((slot, index));
} else {
stats.slot_bad_deserialize += 1;
} }
} else {
stats.index_out_of_bounds += 1;
} }
} else {
stats.index_bad_deserialize += 1;
} }
} else { } else {
*index_overrun += 1; stats.index_overrun += 1;
} }
None None
} }
@@ -50,7 +67,7 @@ impl ShredFetchStage {
fn process_packet<F>( fn process_packet<F>(
p: &mut Packet, p: &mut Packet,
shreds_received: &mut ShredsReceived, shreds_received: &mut ShredsReceived,
index_overrun: &mut usize, stats: &mut ShredFetchStats,
last_root: Slot, last_root: Slot,
last_slot: Slot, last_slot: Slot,
slots_per_epoch: u64, slots_per_epoch: u64,
@@ -59,7 +76,7 @@ impl ShredFetchStage {
F: Fn(&mut Packet), F: Fn(&mut Packet),
{ {
p.meta.discard = true; 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 // Seems reasonable to limit shreds to 2 epochs away
if slot > last_root && slot < (last_slot + 2 * slots_per_epoch) { if slot > last_root && slot < (last_slot + 2 * slots_per_epoch) {
// Shred filter // Shred filter
@@ -70,7 +87,11 @@ impl ShredFetchStage {
p.meta.discard = false; p.meta.discard = false;
modify(p); modify(p);
slot_received.set(index.into(), true); 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, recvr: PacketReceiver,
sendr: PacketSender, sendr: PacketSender,
bank_forks: Option<Arc<RwLock<BankForks>>>, bank_forks: Option<Arc<RwLock<BankForks>>>,
name: &'static str,
modify: F, modify: F,
) where ) where
F: Fn(&mut Packet), F: Fn(&mut Packet),
@@ -92,6 +114,9 @@ impl ShredFetchStage {
let mut last_slot = std::u64::MAX; let mut last_slot = std::u64::MAX;
let mut slots_per_epoch = 0; 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() { while let Some(mut p) = recvr.iter().next() {
if last_cleared.elapsed().as_millis() > 200 { if last_cleared.elapsed().as_millis() > 200 {
shreds_received.clear(); shreds_received.clear();
@@ -105,22 +130,32 @@ impl ShredFetchStage {
slots_per_epoch = root_bank.get_slots_in_epoch(root_bank.epoch()); slots_per_epoch = root_bank.get_slots_in_epoch(root_bank.epoch());
} }
} }
let mut index_overrun = 0; stats.shred_count += p.packets.len();
let mut shred_count = 0;
p.packets.iter_mut().for_each(|mut packet| { p.packets.iter_mut().for_each(|mut packet| {
shred_count += 1;
Self::process_packet( Self::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
&modify, &modify,
); );
}); });
inc_new_counter_warn!("shred_fetch_stage-shred_index_overrun", index_overrun); if last_stats.elapsed().as_millis() > 1000 {
inc_new_counter_info!("shred_fetch_stage-shred_count", shred_count); 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() { if sendr.send(p).is_err() {
break; break;
} }
@@ -133,6 +168,7 @@ impl ShredFetchStage {
sender: PacketSender, sender: PacketSender,
recycler: Recycler<PinnedVec<Packet>>, recycler: Recycler<PinnedVec<Packet>>,
bank_forks: Option<Arc<RwLock<BankForks>>>, bank_forks: Option<Arc<RwLock<BankForks>>>,
name: &'static str,
modify: F, modify: F,
) -> (Vec<JoinHandle<()>>, JoinHandle<()>) ) -> (Vec<JoinHandle<()>>, JoinHandle<()>)
where where
@@ -154,7 +190,7 @@ impl ShredFetchStage {
let modifier_hdl = Builder::new() let modifier_hdl = Builder::new()
.name("solana-tvu-fetch-stage-packet-modifier".to_string()) .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(); .unwrap();
(streamers, modifier_hdl) (streamers, modifier_hdl)
} }
@@ -185,6 +221,7 @@ impl ShredFetchStage {
sender.clone(), sender.clone(),
recycler.clone(), recycler.clone(),
bank_forks.clone(), bank_forks.clone(),
"shred_fetch_tvu_forwards",
|p| p.meta.forward = true, |p| p.meta.forward = true,
); );
@@ -194,6 +231,7 @@ impl ShredFetchStage {
sender.clone(), sender.clone(),
recycler.clone(), recycler.clone(),
bank_forks, bank_forks,
"shred_fetch_repair",
|p| p.meta.repair = true, |p| p.meta.repair = true,
); );
@@ -225,7 +263,7 @@ mod tests {
solana_logger::setup(); solana_logger::setup();
let mut shreds_received = ShredsReceived::default(); let mut shreds_received = ShredsReceived::default();
let mut packet = Packet::default(); let mut packet = Packet::default();
let mut index_overrun = 0; let mut stats = ShredFetchStats::default();
let last_root = 0; let last_root = 0;
let last_slot = 100; let last_slot = 100;
let slots_per_epoch = 10; let slots_per_epoch = 10;
@@ -233,13 +271,13 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
&|_p| {}, &|_p| {},
); );
assert_eq!(index_overrun, 1); assert_eq!(stats.index_overrun, 1);
assert!(packet.meta.discard); assert!(packet.meta.discard);
let shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0); let shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0);
shred.copy_to_packet(&mut packet); shred.copy_to_packet(&mut packet);
@@ -248,7 +286,7 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
3, 3,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
@@ -260,7 +298,7 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
@@ -272,7 +310,7 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
@@ -287,7 +325,7 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, slots_per_epoch,
@@ -301,7 +339,7 @@ mod tests {
ShredFetchStage::process_packet( ShredFetchStage::process_packet(
&mut packet, &mut packet,
&mut shreds_received, &mut shreds_received,
&mut index_overrun, &mut stats,
last_root, last_root,
last_slot, last_slot,
slots_per_epoch, 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 shred = Shred::new_from_data(1, 3, 0, None, true, true, 0, 0, 0);
let mut packet = Packet::default(); let mut packet = Packet::default();
shred.copy_to_packet(&mut packet); shred.copy_to_packet(&mut packet);
let mut index_overrun = 0; let mut stats = ShredFetchStats::default();
assert_eq!( assert_eq!(
Some((1, 3)), Some((1, 3)),
ShredFetchStage::get_slot_index(&packet, &mut index_overrun) ShredFetchStage::get_slot_index(&packet, &mut stats)
); );
} }
} }

View File

@@ -46,7 +46,7 @@ fn test_rpc_client() {
assert_eq!( assert_eq!(
client.get_version().unwrap().solana_core, client.get_version().unwrap().solana_core,
solana_clap_utils::version!() solana_version::version!()
); );
assert!(client.get_account(&bob_pubkey).is_err()); assert!(client.get_account(&bob_pubkey).is_err());

View File

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

View File

@@ -43,8 +43,8 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getStoragePubkeysForSlot](jsonrpc-api.md#getstoragepubkeysforslot) * [getStoragePubkeysForSlot](jsonrpc-api.md#getstoragepubkeysforslot)
* [getStorageTurn](jsonrpc-api.md#getstorageturn) * [getStorageTurn](jsonrpc-api.md#getstorageturn)
* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate) * [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
* [getSupply](jsonrpc-api.md#getsupply)
* [getTransactionCount](jsonrpc-api.md#gettransactioncount) * [getTransactionCount](jsonrpc-api.md#gettransactioncount)
* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
* [getVersion](jsonrpc-api.md#getversion) * [getVersion](jsonrpc-api.md#getversion)
* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts) * [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
* [minimumLedgerSlot](jsonrpc-api.md#minimumledgerslot) * [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 * `pubkey: <string>` - Node public key, as base-58 encoded string
* `gossip: <string>` - Gossip network address for the node * `gossip: <string>` - Gossip network address for the node
* `tpu: <string>` - TPU 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: #### 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 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' http://localhost:8899
// Result // 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 ### 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} {"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 ### getTransactionCount
Returns the current Transaction count from the ledger 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} {"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 ### getVersion
Returns the current solana versions running on the node 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 // Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899 curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
// Result // Result
{"jsonrpc":"2.0","result":{"solana-core": "1.1.10"},"id":1} {"jsonrpc":"2.0","result":{"solana-core": "1.1.11"},"id":1}
``` ```
### getVoteAccounts ### getVoteAccounts

View File

@@ -1,6 +1,18 @@
# Install the Solana Tool Suite # 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 [LATEST_SOLANA_RELEASE_VERSION](https://github.com/solana-labs/solana/releases/tag/LATEST_SOLANA_RELEASE_VERSION) on your
machine by running: 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 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 release tag matching the software version of your desired testnet, or replace it
with the named channel `stable`, `beta`, or `edge`. with the named channel `stable`, `beta`, or `edge`.
The following output indicates a successful update: - The following output indicates a successful update:
```text ```text
looking for latest release looking for latest release
@@ -24,8 +36,59 @@ Active release directory: /home/solana/.local/share/solana/install/active_releas
Update successful Update successful
``` ```
After a successful install, `solana-install update` may be used to easily update - Depending on your system, the end of the installer messaging may prompt you
the cluster software to a newer version at any time. 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 ## Download Prebuilt Binaries
@@ -45,7 +108,7 @@ cd solana-release/
export PATH=$PWD/bin:$PATH export PATH=$PWD/bin:$PATH
``` ```
### macOS ### MacOS
Download the binaries by navigating to Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), [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 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 ## Build From Source
If you are unable to use the prebuilt binaries or prefer to build it yourself If you are unable to use the prebuilt binaries or prefer to build it yourself

View File

@@ -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. 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 ## Relationship to VDFs

View File

@@ -6,9 +6,9 @@ Solana is an open source project implementing a new, high-performance, permissio
## Why Solana? ## 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. 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.

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-dos" name = "solana-dos"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -13,10 +13,10 @@ clap = "2.33.0"
log = "0.4.8" log = "0.4.8"
rand = "0.7.0" rand = "0.7.0"
rayon = "1.3.0" rayon = "1.3.0"
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-net-utils = { path = "../net-utils", version = "1.1.10" } solana-net-utils = { path = "../net-utils", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
[package.metadata.docs.rs] [package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"] targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-download-utils" name = "solana-download-utils"
version = "1.1.10" version = "1.1.11"
description = "Solana Download Utils" description = "Solana Download Utils"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -14,8 +14,8 @@ console = "0.10.0"
indicatif = "0.14.0" indicatif = "0.14.0"
log = "0.4.8" log = "0.4.8"
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] } 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" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
tar = "0.4.26" tar = "0.4.26"
[lib] [lib]

View File

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

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-genesis-programs" name = "solana-genesis-programs"
version = "1.1.10" version = "1.1.11"
description = "Solana genesis programs" description = "Solana genesis programs"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -10,13 +10,13 @@ edition = "2018"
[dependencies] [dependencies]
log = { version = "0.4.8" } log = { version = "0.4.8" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", 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.10" } solana-budget-program = { path = "../programs/budget", version = "1.1.11" }
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" } solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
solana-vest-program = { path = "../programs/vest", version = "1.1.10" } solana-vest-program = { path = "../programs/vest", version = "1.1.11" }
[lib] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-genesis" name = "solana-genesis"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -15,13 +15,13 @@ chrono = "0.4"
serde = "1.0.105" serde = "1.0.105"
serde_json = "1.0.48" serde_json = "1.0.48"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" } solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
tempfile = "3.1.0" tempfile = "3.1.0"
[[bin]] [[bin]]

View File

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

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-install" name = "solana-install"
description = "The solana cluster software installer" description = "The solana cluster software installer"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -24,11 +24,11 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-config-program = { path = "../programs/config", version = "1.1.10" } solana-config-program = { path = "../programs/config", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
semver = "0.9.0" semver = "0.9.0"
tar = "0.4.26" tar = "0.4.26"
tempdir = "0.3.7" tempdir = "0.3.7"

View File

@@ -221,8 +221,7 @@ fn new_update_manifest(
let mut transaction = Transaction::new_unsigned_instructions(new_account); let mut transaction = Transaction::new_unsigned_instructions(new_account);
let signers = [from_keypair, update_manifest_keypair]; let signers = [from_keypair, update_manifest_keypair];
transaction.sign(&signers, recent_blockhash); transaction.sign(&signers, recent_blockhash);
rpc_client.send_and_confirm_transaction(&transaction)?;
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?;
} }
Ok(()) Ok(())
} }
@@ -245,8 +244,8 @@ fn store_update_manifest(
); );
let message = Message::new_with_payer(&[instruction], Some(&from_keypair.pubkey())); let message = Message::new_with_payer(&[instruction], Some(&from_keypair.pubkey()));
let mut transaction = Transaction::new(&signers, message, recent_blockhash); let transaction = Transaction::new(&signers, message, recent_blockhash);
rpc_client.send_and_confirm_transaction(&mut transaction, &[from_keypair])?; rpc_client.send_and_confirm_transaction(&transaction)?;
Ok(()) Ok(())
} }

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-keygen" name = "solana-keygen"
version = "1.1.10" version = "1.1.11"
description = "Solana key generation utility" description = "Solana key generation utility"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -13,10 +13,10 @@ bs58 = "0.3.0"
clap = "2.33" clap = "2.33"
dirs = "2.0.2" dirs = "2.0.2"
num_cpus = "1.12.0" num_cpus = "1.12.0"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-cli-config = { path = "../cli-config", version = "1.1.10" } solana-cli-config = { path = "../cli-config", version = "1.1.11" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.10" } solana-remote-wallet = { path = "../remote-wallet", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
tiny-bip39 = "0.7.0" tiny-bip39 = "0.7.0"
[[bin]] [[bin]]

View File

@@ -75,7 +75,7 @@ fn output_keypair(
write_keypair(&keypair, &mut stdout)?; write_keypair(&keypair, &mut stdout)?;
} else { } else {
write_keypair_file(&keypair, outfile)?; write_keypair_file(&keypair, outfile)?;
eprintln!("Wrote {} keypair to {}", source, outfile); println!("Wrote {} keypair to {}", source, outfile);
} }
Ok(()) Ok(())
} }
@@ -443,7 +443,7 @@ fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
let passphrase = if matches.is_present("no_passphrase") { let passphrase = if matches.is_present("no_passphrase") {
NO_PASSPHRASE.to_string() NO_PASSPHRASE.to_string()
} else { } else {
eprintln!("Generating a new keypair"); println!("Generating a new keypair");
prompt_passphrase( prompt_passphrase(
"For added security, enter a passphrase (empty for no 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 { if !silent {
let phrase: &str = mnemonic.phrase(); let phrase: &str = mnemonic.phrase();
let divider = String::from_utf8(vec![b'='; phrase.len()]).unwrap(); 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{}", "{}\npubkey: {}\n{}\nSave this seed phrase to recover your new keypair:\n{}\n{}",
&divider, keypair.pubkey(), &divider, phrase, &divider &divider, keypair.pubkey(), &divider, phrase, &divider
); );

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-ledger-tool" name = "solana-ledger-tool"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -14,15 +14,15 @@ clap = "2.33.0"
histogram = "*" histogram = "*"
serde_json = "1.0.48" serde_json = "1.0.48"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-cli = { path = "../cli", version = "1.1.10" } solana-cli = { path = "../cli", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" } solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
tempfile = "3.1.0" tempfile = "3.1.0"
[dev-dependencies] [dev-dependencies]

View File

@@ -726,6 +726,13 @@ fn main() {
.takes_value(false) .takes_value(false)
.help("Include sysvars too"), .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(
SubCommand::with_name("prune") SubCommand::with_name("prune")
.about("Prune the ledger at the block height") .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)) => { ("purge", Some(arg_matches)) => {
let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot); let start_slot = value_t_or_exit!(arg_matches, "start_slot", Slot);
let end_slot = value_t!(arg_matches, "end_slot", Slot); let end_slot = value_t!(arg_matches, "end_slot", Slot);

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-ledger" name = "solana-ledger"
version = "1.1.10" version = "1.1.11"
description = "Solana ledger" description = "Solana ledger"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" 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" regex = "1.3.6"
serde = "1.0.105" serde = "1.0.105"
serde_bytes = "0.11.3" serde_bytes = "0.11.3"
solana-transaction-status = { path = "../transaction-status", version = "1.1.10" } solana-transaction-status = { path = "../transaction-status", version = "1.1.11" }
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" } solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-measure = { path = "../measure", version = "1.1.10" } solana-measure = { path = "../measure", version = "1.1.11" }
solana-merkle-tree = { path = "../merkle-tree", version = "1.1.10" } solana-merkle-tree = { path = "../merkle-tree", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
solana-perf = { path = "../perf", version = "1.1.10" } solana-perf = { path = "../perf", version = "1.1.11" }
ed25519-dalek = "1.0.0-pre.3" ed25519-dalek = "1.0.0-pre.3"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.10" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
symlink = "0.1.0" symlink = "0.1.0"
tar = "0.4.26" tar = "0.4.26"
thiserror = "1.0" thiserror = "1.0"
@@ -57,7 +57,7 @@ features = ["lz4"]
[dev-dependencies] [dev-dependencies]
assert_matches = "1.3.0" assert_matches = "1.3.0"
matches = "0.1.6" 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] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@@ -913,14 +913,14 @@ impl Blockstore {
// ToDo: This is a potential slashing condition // ToDo: This is a potential slashing condition
warn!("Received multiple erasure configs for the same erasure set!!!"); warn!("Received multiple erasure configs for the same erasure set!!!");
warn!( warn!(
"Stored config: {:#?}, new config: {:#?}", "Slot: {}, shred index: {}, set_index: {}, is_duplicate: {}, stored config: {:#?}, new config: {:#?}",
erasure_meta.config, erasure_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 // Should be safe to modify index_meta here. Two cases
// 1) Recovery happens: Then all inserted erasure metas are removed // 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 // `check_insert_coding_shred`, so the coding index meta will not be
// committed // committed
index_meta.coding_mut().set_present(shred_index, true); index_meta.coding_mut().set_present(shred_index, true);

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-local-cluster" name = "solana-local-cluster"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -12,24 +12,24 @@ homepage = "https://solana.com/"
itertools = "0.9.0" itertools = "0.9.0"
log = "0.4.8" log = "0.4.8"
rand = "0.7.0" rand = "0.7.0"
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.10" } solana-archiver-lib = { path = "../archiver-lib", version = "1.1.11" }
solana-config-program = { path = "../programs/config", version = "1.1.10" } solana-config-program = { path = "../programs/config", version = "1.1.11" }
solana-core = { path = "../core", version = "1.1.10" } solana-core = { path = "../core", version = "1.1.11" }
solana-client = { path = "../client", version = "1.1.10" } solana-client = { path = "../client", version = "1.1.11" }
solana-download-utils = { path = "../download-utils", version = "1.1.10" } solana-download-utils = { path = "../download-utils", version = "1.1.11" }
solana-faucet = { path = "../faucet", version = "1.1.10" } solana-faucet = { path = "../faucet", version = "1.1.11" }
solana-exchange-program = { path = "../programs/exchange", version = "1.1.10" } solana-exchange-program = { path = "../programs/exchange", version = "1.1.11" }
solana-genesis-programs = { path = "../genesis-programs", version = "1.1.10" } solana-genesis-programs = { path = "../genesis-programs", version = "1.1.11" }
solana-ledger = { path = "../ledger", version = "1.1.10" } solana-ledger = { path = "../ledger", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
solana-runtime = { path = "../runtime", version = "1.1.10" } solana-runtime = { path = "../runtime", version = "1.1.11" }
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-stake-program = { path = "../programs/stake", version = "1.1.10" } solana-stake-program = { path = "../programs/stake", version = "1.1.11" }
solana-storage-program = { path = "../programs/storage", version = "1.1.10" } solana-storage-program = { path = "../programs/storage", version = "1.1.11" }
solana-vest-program = { path = "../programs/vest", version = "1.1.10" } solana-vest-program = { path = "../programs/vest", version = "1.1.11" }
solana-vote-program = { path = "../programs/vote", version = "1.1.10" } solana-vote-program = { path = "../programs/vote", version = "1.1.11" }
tempfile = "3.1.0" 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] [dev-dependencies]
assert_matches = "1.3.0" assert_matches = "1.3.0"

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-log-analyzer" name = "solana-log-analyzer"
description = "The solana cluster network analysis tool" description = "The solana cluster network analysis tool"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -14,8 +14,8 @@ byte-unit = "3.0.3"
clap = "2.33.0" clap = "2.33.0"
serde = "1.0.105" serde = "1.0.105"
serde_json = "1.0.48" serde_json = "1.0.48"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
[[bin]] [[bin]]
name = "solana-log-analyzer" name = "solana-log-analyzer"

View File

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

View File

@@ -1,7 +1,7 @@
[package] [package]
name = "solana-measure" name = "solana-measure"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "1.1.10" version = "1.1.11"
documentation = "https://docs.rs/solana" documentation = "https://docs.rs/solana"
homepage = "https://solana.com/" homepage = "https://solana.com/"
readme = "../README.md" readme = "../README.md"
@@ -12,8 +12,8 @@ edition = "2018"
[dependencies] [dependencies]
log = "0.4.8" log = "0.4.8"
solana-sdk = { path = "../sdk", version = "1.1.10" } solana-sdk = { path = "../sdk", version = "1.1.11" }
solana-metrics = { path = "../metrics", version = "1.1.10" } solana-metrics = { path = "../metrics", version = "1.1.11" }
[target."cfg(unix)".dependencies] [target."cfg(unix)".dependencies]
jemallocator = "0.3.2" jemallocator = "0.3.2"

View File

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

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-metrics" name = "solana-metrics"
version = "1.1.10" version = "1.1.11"
description = "Solana Metrics" description = "Solana Metrics"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -14,7 +14,7 @@ gethostname = "0.2.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.8" log = "0.4.8"
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] } 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] [dev-dependencies]
rand = "0.7.0" rand = "0.7.0"

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-net-shaper" name = "solana-net-shaper"
description = "The solana cluster network shaping tool" description = "The solana cluster network shaping tool"
version = "1.1.10" version = "1.1.11"
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0" license = "Apache-2.0"
homepage = "https://solana.com/" homepage = "https://solana.com/"
@@ -13,8 +13,8 @@ publish = false
clap = "2.33.0" clap = "2.33.0"
serde = "1.0.105" serde = "1.0.105"
serde_json = "1.0.48" serde_json = "1.0.48"
solana-clap-utils = { path = "../clap-utils", version = "1.1.10" } solana-clap-utils = { path = "../clap-utils", version = "1.1.11" }
solana-logger = { path = "../logger", version = "1.1.10" } solana-logger = { path = "../logger", version = "1.1.11" }
rand = "0.7.0" rand = "0.7.0"
[[bin]] [[bin]]

View File

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

View File

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

597
programs/bpf/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-128bit-dep" name = "solana-bpf-rust-128bit-dep"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-alloc" name = "solana-bpf-rust-alloc"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

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

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-dup-accounts" name = "solana-bpf-rust-dup-accounts"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-error-handling" name = "solana-bpf-rust-error-handling"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -14,11 +14,11 @@ edition = "2018"
[dependencies] [dependencies]
num-derive = "0.2" num-derive = "0.2"
num-traits = "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" thiserror = "1.0"
[dev_dependencies] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-external-spend" name = "solana-bpf-rust-external-spend"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-iter" name = "solana-bpf-rust-iter"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

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

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-many-args-dep" name = "solana-bpf-rust-many-args-dep"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-noop" name = "solana-bpf-rust-noop"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-panic" name = "solana-bpf-rust-panic"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

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

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-param-passing-dep" name = "solana-bpf-rust-param-passing-dep"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF program written in Rust" description = "Solana BPF program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-sysval" name = "solana-bpf-rust-sysval"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF test program written in Rust" description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
edition = "2018" edition = "2018"
[dependencies] [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] [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] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@@ -92,7 +92,7 @@ mod bpf {
.native_instruction_processors .native_instruction_processors
.push(solana_bpf_loader_program!()); .push(solana_bpf_loader_program!());
let bank = Arc::new(Bank::new(&genesis_config)); 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 = let bank =
Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1); Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1);
let bank_client = BankClient::new(bank); let bank_client = BankClient::new(bank);

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-bpf-loader-program" name = "solana-bpf-loader-program"
version = "1.1.10" version = "1.1.11"
description = "Solana BPF loader" description = "Solana BPF loader"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -15,11 +15,14 @@ libc = "0.2.68"
log = "0.4.8" log = "0.4.8"
num-derive = { version = "0.3" } num-derive = { version = "0.3" }
num-traits = { version = "0.2" } num-traits = { version = "0.2" }
solana-logger = { path = "../../logger", version = "1.1.10" } solana-logger = { path = "../../logger", version = "1.1.11" }
solana-sdk = { path = "../../sdk", version = "1.1.10" } solana-sdk = { path = "../../sdk", version = "1.1.11" }
solana_rbpf = "=0.1.25" solana_rbpf = "=0.1.27"
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies]
rand = "0.7.3"
[lib] [lib]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]
name = "solana_bpf_loader_program" name = "solana_bpf_loader_program"

View File

@@ -25,7 +25,7 @@ impl BPFAllocator {
impl Alloc for BPFAllocator { impl Alloc for BPFAllocator {
fn alloc(&mut self, layout: Layout) -> Result<u64, AllocErr> { 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; let addr = self.start + self.pos;
self.pos += layout.size() as u64; self.pos += layout.size() as u64;
Ok(addr) Ok(addr)

View File

@@ -2,36 +2,56 @@ use crate::BPFError;
use solana_rbpf::ebpf; use solana_rbpf::ebpf;
use thiserror::Error; use thiserror::Error;
/// Error definitions
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum VerifierError { pub enum VerifierError {
/// ProgramLengthNotMultiple
#[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)] #[error("program length must be a multiple of {} octets", ebpf::INSN_SIZE)]
ProgramLengthNotMultiple, ProgramLengthNotMultiple,
/// ProgramTooLarge
#[error("program too big, max {}, is {}", ebpf::PROG_MAX_INSNS, .0)] #[error("program too big, max {}, is {}", ebpf::PROG_MAX_INSNS, .0)]
ProgramTooLarge(usize), ProgramTooLarge(usize),
/// NoProgram
#[error("no program set, call prog_set() to load one")] #[error("no program set, call prog_set() to load one")]
NoProgram, NoProgram,
#[error("division by 0 (insn #{0})")] #[error("division by 0 (insn #{0})")]
DivisionByZero(usize), DivisionByZero(usize),
/// UnsupportedLEBEArgument
#[error("unsupported argument for LE/BE (insn #{0})")] #[error("unsupported argument for LE/BE (insn #{0})")]
UnsupportedLEBEArgument(usize), UnsupportedLEBEArgument(usize),
/// LDDWCannotBeLast
#[error("LD_DW instruction cannot be last in program")] #[error("LD_DW instruction cannot be last in program")]
LDDWCannotBeLast, LDDWCannotBeLast,
/// IncompleteLDDW
#[error("incomplete LD_DW instruction (insn #{0})")] #[error("incomplete LD_DW instruction (insn #{0})")]
IncompleteLDDW(usize), IncompleteLDDW(usize),
/// InfiniteLoop
#[error("infinite loop (insn #{0})")] #[error("infinite loop (insn #{0})")]
InfiniteLoop(usize), InfiniteLoop(usize),
/// JumpOutOfCode
#[error("jump out of code to #{0} (insn #{1})")] #[error("jump out of code to #{0} (insn #{1})")]
JumpOutOfCode(usize, usize), JumpOutOfCode(usize, usize),
/// JumpToMiddleOfLDDW
#[error("jump to middle of LD_DW at #{0} (insn #{1})")] #[error("jump to middle of LD_DW at #{0} (insn #{1})")]
JumpToMiddleOfLDDW(usize, usize), JumpToMiddleOfLDDW(usize, usize),
/// InvalidSourceRegister
#[error("invalid source register (insn #{0})")] #[error("invalid source register (insn #{0})")]
InvalidSourceRegister(usize), InvalidSourceRegister(usize),
/// CannotWriteR10
#[error("cannot write into register r10 (insn #{0})")] #[error("cannot write into register r10 (insn #{0})")]
CannotWriteR10(usize), CannotWriteR10(usize),
/// InvalidDestinationRegister
#[error("invalid destination register (insn #{0})")] #[error("invalid destination register (insn #{0})")]
InvalidDestinationRegister(usize), InvalidDestinationRegister(usize),
/// UnknownOpCode
#[error("unknown eBPF opcode {0:#2x} (insn #{1:?})")] #[error("unknown eBPF opcode {0:#2x} (insn #{1:?})")]
UnknownOpCode(u8, usize), 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> { 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> { pub fn check(prog: &[u8]) -> Result<(), BPFError> {
check_prog_len(prog)?; check_prog_len(prog)?;
@@ -111,189 +148,126 @@ pub fn check(prog: &[u8]) -> Result<(), BPFError> {
let mut store = false; let mut store = false;
match insn.opc { 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; store = true;
check_load_dw(prog, insn_ptr)?; check_load_dw(prog, insn_ptr)?;
insn_ptr += 1; insn_ptr += 1;
} },
// BPF_LDX class // BPF_LDX class
ebpf::LD_B_REG => {} ebpf::LD_B_REG => {},
ebpf::LD_H_REG => {} ebpf::LD_H_REG => {},
ebpf::LD_W_REG => {} ebpf::LD_W_REG => {},
ebpf::LD_DW_REG => {} ebpf::LD_DW_REG => {},
// BPF_ST class // BPF_ST class
ebpf::ST_B_IMM => store = true, ebpf::ST_B_IMM => store = true,
ebpf::ST_H_IMM => store = true, ebpf::ST_H_IMM => store = true,
ebpf::ST_W_IMM => store = true, ebpf::ST_W_IMM => store = true,
ebpf::ST_DW_IMM => store = true, ebpf::ST_DW_IMM => store = true,
// BPF_STX class // BPF_STX class
ebpf::ST_B_REG => store = true, ebpf::ST_B_REG => store = true,
ebpf::ST_H_REG => store = true, ebpf::ST_H_REG => store = true,
ebpf::ST_W_REG => store = true, ebpf::ST_W_REG => store = true,
ebpf::ST_DW_REG => store = true, ebpf::ST_DW_REG => store = true,
ebpf::ST_W_XADD => {
unimplemented!();
}
ebpf::ST_DW_XADD => {
unimplemented!();
}
// BPF_ALU class // BPF_ALU class
ebpf::ADD32_IMM => {} ebpf::ADD32_IMM => {},
ebpf::ADD32_REG => {} ebpf::ADD32_REG => {},
ebpf::SUB32_IMM => {} ebpf::SUB32_IMM => {},
ebpf::SUB32_REG => {} ebpf::SUB32_REG => {},
ebpf::MUL32_IMM => {} ebpf::MUL32_IMM => {},
ebpf::MUL32_REG => {} ebpf::MUL32_REG => {},
ebpf::DIV32_IMM => { ebpf::DIV32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
check_imm_nonzero(&insn, insn_ptr)?; ebpf::DIV32_REG => {},
} ebpf::OR32_IMM => {},
ebpf::DIV32_REG => {} ebpf::OR32_REG => {},
ebpf::OR32_IMM => {} ebpf::AND32_IMM => {},
ebpf::OR32_REG => {} ebpf::AND32_REG => {},
ebpf::AND32_IMM => {} ebpf::LSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::AND32_REG => {} ebpf::LSH32_REG => {},
ebpf::LSH32_IMM => {} ebpf::RSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::LSH32_REG => {} ebpf::RSH32_REG => {},
ebpf::RSH32_IMM => {} ebpf::NEG32 => {},
ebpf::RSH32_REG => {} ebpf::MOD32_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
ebpf::NEG32 => {} ebpf::MOD32_REG => {},
ebpf::MOD32_IMM => { ebpf::XOR32_IMM => {},
check_imm_nonzero(&insn, insn_ptr)?; ebpf::XOR32_REG => {},
} ebpf::MOV32_IMM => {},
ebpf::MOD32_REG => {} ebpf::MOV32_REG => {},
ebpf::XOR32_IMM => {} ebpf::ARSH32_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::XOR32_REG => {} ebpf::ARSH32_REG => {},
ebpf::MOV32_IMM => {} ebpf::LE => { check_imm_endian(&insn, insn_ptr)?; },
ebpf::MOV32_REG => {} ebpf::BE => { check_imm_endian(&insn, insn_ptr)?; },
ebpf::ARSH32_IMM => {}
ebpf::ARSH32_REG => {}
ebpf::LE => {
check_imm_endian(&insn, insn_ptr)?;
}
ebpf::BE => {
check_imm_endian(&insn, insn_ptr)?;
}
// BPF_ALU64 class // BPF_ALU64 class
ebpf::ADD64_IMM => {} ebpf::ADD64_IMM => {},
ebpf::ADD64_REG => {} ebpf::ADD64_REG => {},
ebpf::SUB64_IMM => {} ebpf::SUB64_IMM => {},
ebpf::SUB64_REG => {} ebpf::SUB64_REG => {},
ebpf::MUL64_IMM => { ebpf::MUL64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
check_imm_nonzero(&insn, insn_ptr)?; ebpf::MUL64_REG => {},
} ebpf::DIV64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
ebpf::MUL64_REG => {} ebpf::DIV64_REG => {},
ebpf::DIV64_IMM => { ebpf::OR64_IMM => {},
check_imm_nonzero(&insn, insn_ptr)?; ebpf::OR64_REG => {},
} ebpf::AND64_IMM => {},
ebpf::DIV64_REG => {} ebpf::AND64_REG => {},
ebpf::OR64_IMM => {} ebpf::LSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::OR64_REG => {} ebpf::LSH64_REG => {},
ebpf::AND64_IMM => {} ebpf::RSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::AND64_REG => {} ebpf::RSH64_REG => {},
ebpf::LSH64_IMM => {} ebpf::NEG64 => {},
ebpf::LSH64_REG => {} ebpf::MOD64_IMM => { check_imm_nonzero(&insn, insn_ptr)?; },
ebpf::RSH64_IMM => {} ebpf::MOD64_REG => {},
ebpf::RSH64_REG => {} ebpf::XOR64_IMM => {},
ebpf::NEG64 => {} ebpf::XOR64_REG => {},
ebpf::MOD64_IMM => {} ebpf::MOV64_IMM => {},
ebpf::MOD64_REG => {} ebpf::MOV64_REG => {},
ebpf::XOR64_IMM => {} ebpf::ARSH64_IMM => { check_imm_shift(&insn, insn_ptr)?; },
ebpf::XOR64_REG => {} ebpf::ARSH64_REG => {},
ebpf::MOV64_IMM => {}
ebpf::MOV64_REG => {}
ebpf::ARSH64_IMM => {}
ebpf::ARSH64_REG => {}
// BPF_JMP class // BPF_JMP class
ebpf::JA => { ebpf::JA => { check_jmp_offset(prog, insn_ptr)?; },
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::JEQ_IMM => { ebpf::JGT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
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::JEQ_REG => { ebpf::JGE_REG => { check_jmp_offset(prog, insn_ptr)?; },
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::JGT_IMM => { ebpf::JLE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
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::JGT_REG => { ebpf::JSET_REG => { check_jmp_offset(prog, insn_ptr)?; },
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::JGE_IMM => { ebpf::JSGT_IMM => { check_jmp_offset(prog, insn_ptr)?; },
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::JGE_REG => { ebpf::JSGE_REG => { check_jmp_offset(prog, insn_ptr)?; },
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::JLT_IMM => { ebpf::JSLE_IMM => { check_jmp_offset(prog, insn_ptr)?; },
check_jmp_offset(prog, insn_ptr)?; ebpf::JSLE_REG => { check_jmp_offset(prog, insn_ptr)?; },
} ebpf::CALL_IMM => {},
ebpf::JLT_REG => { ebpf::CALL_REG => { check_imm_register(&insn, insn_ptr)?; },
check_jmp_offset(prog, insn_ptr)?; ebpf::EXIT => {},
}
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 => {}
_ => { _ => {
return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr).into()); return Err(VerifierError::UnknownOpCode(insn.opc, insn_ptr).into());
} }
} }

View File

@@ -1,9 +1,9 @@
pub mod alloc; pub mod alloc;
pub mod allocator_bump; pub mod allocator_bump;
pub mod bpf_verifier; 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 byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use log::*; use log::*;
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
@@ -50,7 +50,7 @@ pub enum BPFError {
#[error("{0}")] #[error("{0}")]
VerifierError(#[from] VerifierError), VerifierError(#[from] VerifierError),
#[error("{0}")] #[error("{0}")]
HelperError(#[from] HelperError), SyscallError(#[from] SyscallError),
} }
impl UserDefinedError for BPFError {} 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_max_instruction_count(100_000)?;
vm.set_elf(&prog)?; vm.set_elf(&prog)?;
let heap_region = helpers::register_helpers(&mut vm)?; let heap_region = syscalls::register_syscalls(&mut vm)?;
Ok((vm, heap_region)) Ok((vm, heap_region))
} }
@@ -197,8 +197,8 @@ pub fn process_instruction(
Err(error) => { Err(error) => {
warn!("BPF program failed: {}", error); warn!("BPF program failed: {}", error);
return match error { return match error {
EbpfError::UserError(BPFError::HelperError( EbpfError::UserError(BPFError::SyscallError(
HelperError::InstructionError(error), SyscallError::InstructionError(error),
)) => Err(error), )) => Err(error),
_ => Err(BPFLoaderError::VirtualMachineFailedToRunProgram.into()), _ => Err(BPFLoaderError::VirtualMachineFailedToRunProgram.into()),
}; };
@@ -250,8 +250,9 @@ pub fn process_instruction(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use rand::Rng;
use solana_sdk::{account::Account, rent::Rent}; use solana_sdk::{account::Account, rent::Rent};
use std::{fs::File, io::Read}; use std::{fs::File, io::Read, ops::Range};
#[test] #[test]
#[should_panic(expected = "ExceededMaxInstructions(10)")] #[should_panic(expected = "ExceededMaxInstructions(10)")]
@@ -416,4 +417,61 @@ mod tests {
process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]) 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, &parameter_account),
];
let _result = process_instruction(&bpf_loader::id(), &keyed_accounts, &vec![]);
},
);
}
} }

View File

@@ -2,7 +2,7 @@ use crate::{alloc, BPFError};
use alloc::Alloc; use alloc::Alloc;
use log::*; use log::*;
use solana_rbpf::{ 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}, memory_region::{translate_addr, MemoryRegion},
EbpfVm, EbpfVm,
}; };
@@ -17,7 +17,7 @@ use thiserror::Error as ThisError;
/// Error definitions /// Error definitions
#[derive(Debug, ThisError)] #[derive(Debug, ThisError)]
pub enum HelperError { pub enum SyscallError {
#[error("{0}: {1:?}")] #[error("{0}: {1:?}")]
InvalidString(Utf8Error, Vec<u8>), InvalidString(Utf8Error, Vec<u8>),
#[error("BPF program called abort()!")] #[error("BPF program called abort()!")]
@@ -27,8 +27,8 @@ pub enum HelperError {
#[error("{0}")] #[error("{0}")]
InstructionError(InstructionError), InstructionError(InstructionError),
} }
impl From<HelperError> for EbpfError<BPFError> { impl From<SyscallError> for EbpfError<BPFError> {
fn from(error: HelperError) -> Self { fn from(error: SyscallError) -> Self {
EbpfError::UserError(error.into()) EbpfError::UserError(error.into())
} }
} }
@@ -45,21 +45,21 @@ use crate::allocator_bump::BPFAllocator;
/// are expected to enforce this /// are expected to enforce this
const DEFAULT_HEAP_SIZE: usize = 32 * 1024; const DEFAULT_HEAP_SIZE: usize = 32 * 1024;
pub fn register_helpers<'a>( pub fn register_syscalls<'a>(
vm: &mut EbpfVm<'a, BPFError>, vm: &mut EbpfVm<'a, BPFError>,
) -> Result<MemoryRegion, EbpfError<BPFError>> { ) -> Result<MemoryRegion, EbpfError<BPFError>> {
// Helper function common across languages // Helper function common across languages
vm.register_helper_ex("abort", helper_abort)?; vm.register_syscall_ex("abort", syscall_abort)?;
vm.register_helper_ex("sol_panic_", helper_sol_panic)?; vm.register_syscall_ex("sol_panic_", syscall_sol_panic)?;
vm.register_helper_ex("sol_log_", helper_sol_log)?; vm.register_syscall_ex("sol_log_", syscall_sol_log)?;
vm.register_helper_ex("sol_log_64_", helper_sol_log_u64)?; vm.register_syscall_ex("sol_log_64_", syscall_sol_log_u64)?;
// Memory allocator // Memory allocator
let heap = vec![0_u8; DEFAULT_HEAP_SIZE]; let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START); 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_", "sol_alloc_free_",
Box::new(HelperSolAllocFree { Box::new(SyscallSolAllocFree {
allocator: BPFAllocator::new(heap, MM_HEAP_START), allocator: BPFAllocator::new(heap, MM_HEAP_START),
}), }),
)?; )?;
@@ -136,15 +136,14 @@ fn translate_string_and_do(
}; };
match from_utf8(&buf[..i]) { match from_utf8(&buf[..i]) {
Ok(message) => work(message), 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()` /// Abort syscall functions, called when the BPF program calls `abort()`
/// LLVM will insert calls to `abort()` if it detects an untenable situation, /// The verify function returns an error which will cause the BPF program
/// `abort()` is not intended to be called explicitly by the program. /// to be halted immediately
/// Causes the BPF program to be halted immediately pub fn syscall_abort(
pub fn helper_abort(
_arg1: u64, _arg1: u64,
_arg2: u64, _arg2: u64,
_arg3: u64, _arg3: u64,
@@ -153,12 +152,13 @@ pub fn helper_abort(
_ro_regions: &[MemoryRegion], _ro_regions: &[MemoryRegion],
_rw_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> { ) -> Result<u64, EbpfError<BPFError>> {
Err(HelperError::Abort.into()) Err(SyscallError::Abort.into())
} }
/// Panic helper function, called when the BPF program calls 'sol_panic_()` /// Panic syscall functions, called when the BPF program calls 'sol_panic_()`
/// Causes the BPF program to be halted immediately /// The verify function returns an error which will cause the BPF program
pub fn helper_sol_panic( /// to be halted immediately
pub fn syscall_sol_panic(
file: u64, file: u64,
len: u64, len: u64,
line: u64, line: u64,
@@ -168,12 +168,12 @@ pub fn helper_sol_panic(
_rw_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion],
) -> Result<u64, EbpfError<BPFError>> { ) -> Result<u64, EbpfError<BPFError>> {
translate_string_and_do(file, len, ro_regions, &|string: &str| { 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 /// Log a user's info message
pub fn helper_sol_log( pub fn syscall_sol_log(
addr: u64, addr: u64,
len: u64, len: u64,
_arg3: u64, _arg3: u64,
@@ -191,8 +191,8 @@ pub fn helper_sol_log(
Ok(0) Ok(0)
} }
/// Log 5 64-bit values /// Log 5 u64 values
pub fn helper_sol_log_u64( pub fn syscall_sol_log_u64(
arg1: u64, arg1: u64,
arg2: u64, arg2: u64,
arg3: u64, arg3: u64,
@@ -210,16 +210,16 @@ pub fn helper_sol_log_u64(
Ok(0) 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 /// `sol_alloc_free_()`. The allocator is expected to allocate/free
/// from/to a given chunk of memory and enforce size restrictions. The /// from/to a given chunk of memory and enforce size restrictions. The
/// memory chunk is given to the allocator during allocator creation and /// memory chunk is given to the allocator during allocator creation and
/// information about that memory (start address and size) is passed /// information about that memory (start address and size) is passed
/// to the VM to use for enforcement. /// to the VM to use for enforcement.
pub struct HelperSolAllocFree { pub struct SyscallSolAllocFree {
allocator: BPFAllocator, allocator: BPFAllocator,
} }
impl HelperObject<BPFError> for HelperSolAllocFree { impl SyscallObject<BPFError> for SyscallSolAllocFree {
fn call( fn call(
&mut self, &mut self,
size: u64, size: u64,

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-btc-spv-program" name = "solana-btc-spv-program"
version = "1.1.10" version = "1.1.11"
description = "Solana Bitcoin spv parsing program" description = "Solana Bitcoin spv parsing program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -15,7 +15,7 @@ num-derive = "0.3"
num-traits = "0.2" num-traits = "0.2"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" 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" hex = "0.4.2"
[lib] [lib]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "btc_spv_bin" name = "btc_spv_bin"
version = "1.1.10" version = "1.1.11"
description = "Solana Bitcoin spv parsing program" description = "Solana Bitcoin spv parsing program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-budget-program" name = "solana-budget-program"
version = "1.1.10" version = "1.1.11"
description = "Solana Budget program" description = "Solana Budget program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -16,11 +16,11 @@ num-derive = "0.3"
num-traits = "0.2" num-traits = "0.2"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-sdk = { path = "../../sdk", version = "1.1.10" } solana-sdk = { path = "../../sdk", version = "1.1.11" }
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies] [dev-dependencies]
solana-runtime = { path = "../../runtime", version = "1.1.10" } solana-runtime = { path = "../../runtime", version = "1.1.11" }
[lib] [lib]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-config-program" name = "solana-config-program"
version = "1.1.10" version = "1.1.11"
description = "Solana Config program" description = "Solana Config program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -14,10 +14,10 @@ chrono = { version = "0.4.11", features = ["serde"] }
log = "0.4.8" log = "0.4.8"
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-sdk = { path = "../../sdk", version = "1.1.10" } solana-sdk = { path = "../../sdk", version = "1.1.11" }
[dev-dependencies] [dev-dependencies]
solana-logger = { path = "../../logger", version = "1.1.10" } solana-logger = { path = "../../logger", version = "1.1.11" }
[lib] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "solana-exchange-program" name = "solana-exchange-program"
version = "1.1.10" version = "1.1.11"
description = "Solana Exchange program" description = "Solana Exchange program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@@ -15,13 +15,13 @@ num-derive = { version = "0.3" }
num-traits = { version = "0.2" } num-traits = { version = "0.2" }
serde = "1.0.105" serde = "1.0.105"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-logger = { path = "../../logger", version = "1.1.10" } solana-logger = { path = "../../logger", version = "1.1.11" }
solana-metrics = { path = "../../metrics", version = "1.1.10" } solana-metrics = { path = "../../metrics", version = "1.1.11" }
solana-sdk = { path = "../../sdk", version = "1.1.10" } solana-sdk = { path = "../../sdk", version = "1.1.11" }
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies] [dev-dependencies]
solana-runtime = { path = "../../runtime", version = "1.1.10" } solana-runtime = { path = "../../runtime", version = "1.1.11" }
[lib] [lib]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]

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