Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a4ebbc9f55 | ||
|
bf7c2f79c1 | ||
|
d401c3f5ab | ||
|
83d08223fd | ||
|
6bb63f9abf | ||
|
d8293abc64 | ||
|
4d074a6716 | ||
|
3eee222667 | ||
|
a78c3c07f2 | ||
|
53f8e58300 | ||
|
b4fdce9443 | ||
|
39fe52fc06 | ||
|
db65b4e641 | ||
|
fe1c20c689 | ||
|
6566a0f6c8 | ||
|
3606de56f7 | ||
|
9a005855dc | ||
|
70bdcf06b4 | ||
|
f53f273585 | ||
|
e0584b77c5 | ||
|
39a5431790 | ||
|
715c5e64c4 | ||
|
7956f04fa5 | ||
|
2825f82bee | ||
|
45e3cd373b | ||
|
2b4b260c71 | ||
|
866fd22fde | ||
|
d23df85410 | ||
|
839cdecfd2 | ||
|
cc6296b1fa | ||
|
0c2a85a903 | ||
|
011fe72aa2 | ||
|
40fc14471d | ||
|
7fc85b8c9b | ||
|
4d77ac1688 | ||
|
77bdb45d4a | ||
|
3539849a7f | ||
|
8c28f9b63e | ||
|
3346843a87 | ||
|
007c49ff2b | ||
|
bbd386884d | ||
|
ba8426e0fd |
958
Cargo.lock
generated
958
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-account-decoder"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana account decoder"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -19,10 +19,10 @@ lazy_static = "1.4.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0"
|
||||
zstd = "0.5.1"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-bench"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -11,11 +11,11 @@ publish = false
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
rand = "0.7.0"
|
||||
clap = "2.33.1"
|
||||
crossbeam-channel = "0.4"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-accounts-cluster-bench"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,22 +13,22 @@ clap = "2.33.1"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.4.1"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.19" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-banking-bench"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,16 +14,16 @@ crossbeam-channel = "0.4"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.19" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.24" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-client"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana banks client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,16 +15,16 @@ borsh = "0.9.0"
|
||||
borsh-derive = "0.9.0"
|
||||
futures = "0.3"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.19" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.24" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-interface"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana banks RPC interface"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,7 +12,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
mio = "0.7.6"
|
||||
serde = { version = "1.0.122", features = ["derive"] }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-banks-server"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana banks server"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,10 +14,10 @@ bincode = "1.3.1"
|
||||
futures = "0.3"
|
||||
log = "0.4.11"
|
||||
mio = "0.7.6"
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-banks-interface = { path = "../banks-interface", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
tarpc = { version = "0.24.1", features = ["full"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-serde = { version = "0.8", features = ["bincode"] }
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-exchange"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -18,21 +18,21 @@ rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.19" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-streamer"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,11 +10,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-bench-tps"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -15,22 +15,22 @@ log = "0.4.11"
|
||||
rayon = "1.5.0"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-genesis = { path = "../genesis", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "0.4.0"
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.19" }
|
||||
solana-local-cluster = { path = "../local-cluster", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -28,16 +28,29 @@ cargo_audit_ignores=(
|
||||
# Blocked on multiple crates updating `time` to >= 0.2.23
|
||||
--ignore RUSTSEC-2020-0071
|
||||
|
||||
# difference is unmaintained
|
||||
#
|
||||
# Blocked on predicates v1.0.6 removing its dependency on `difference`
|
||||
--ignore RUSTSEC-2020-0095
|
||||
|
||||
# generic-array: arr! macro erases lifetimes
|
||||
#
|
||||
# Blocked on libsecp256k1 releasing with upgraded dependencies
|
||||
# https://github.com/paritytech/libsecp256k1/issues/66
|
||||
--ignore RUSTSEC-2020-0146
|
||||
|
||||
# hyper: Lenient `hyper` header parsing of `Content-Length` could allow request smuggling
|
||||
#
|
||||
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
|
||||
# https://github.com/paritytech/jsonrpc/issues/605
|
||||
--ignore RUSTSEC-2021-0078
|
||||
|
||||
# hyper: Integer overflow in `hyper`'s parsing of the `Transfer-Encoding` header leads to data loss
|
||||
#
|
||||
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
|
||||
# https://github.com/paritytech/jsonrpc/issues/605
|
||||
--ignore RUSTSEC-2021-0079
|
||||
|
||||
# tar: Links in archive can create arbitrary directories
|
||||
#
|
||||
# Blocked on `tar` releasing safe upgrade
|
||||
# https://github.com/alexcrichton/tar-rs/issues/238
|
||||
--ignore RUSTSEC-2021-0080
|
||||
|
||||
)
|
||||
scripts/cargo-for-all-lock-files.sh stable audit "${cargo_audit_ignores[@]}"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-clap-utils"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana utilities for the clap"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,8 +12,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.8.0"
|
||||
uriparse = "0.6.3"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-config"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli-output"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -19,13 +19,13 @@ indicatif = "0.15.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -140,7 +140,7 @@ fn format_account_mode(message: &Message, index: usize) -> String {
|
||||
} else {
|
||||
"-"
|
||||
},
|
||||
if message.is_writable(index, /*demote_sysvar_write_locks=*/ true) {
|
||||
if message.is_writable(index) {
|
||||
"w" // comment for consistent rust fmt (no joking; lol)
|
||||
} else {
|
||||
"-"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-cli"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -29,30 +29,30 @@ reqwest = { version = "0.11.2", default-features = false, features = ["blocking"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.19" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.24" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana_rbpf = "=0.2.9"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0.21"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-client"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Client"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,7 +15,7 @@ bincode = "1.3.1"
|
||||
bs58 = "0.3.1"
|
||||
clap = "2.33.0"
|
||||
indicatif = "0.15.0"
|
||||
jsonrpc-core = "17.0.0"
|
||||
jsonrpc-core = "18.0.0"
|
||||
log = "0.4.11"
|
||||
net2 = "0.2.37"
|
||||
rayon = "1.5.0"
|
||||
@@ -24,14 +24,14 @@ semver = "0.11.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tungstenite = "0.10.1"
|
||||
@@ -39,8 +39,8 @@ url = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
jsonrpc-http-server = "17.0.0"
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
jsonrpc-http-server = "18.0.0"
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -21,6 +21,7 @@ pub struct RpcSendTransactionConfig {
|
||||
pub skip_preflight: bool,
|
||||
pub preflight_commitment: Option<CommitmentLevel>,
|
||||
pub encoding: Option<UiTransactionEncoding>,
|
||||
pub max_retries: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-core"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-core"
|
||||
readme = "../README.md"
|
||||
@@ -29,12 +29,12 @@ fs_extra = "1.2.0"
|
||||
flate2 = "1.0"
|
||||
indexmap = { version = "1.5", features = ["rayon"] }
|
||||
itertools = "0.9.0"
|
||||
jsonrpc-core = "17.1.0"
|
||||
jsonrpc-core-client = { version = "17.1.0", features = ["ipc", "ws"] }
|
||||
jsonrpc-derive = "17.1.0"
|
||||
jsonrpc-http-server = "17.1.0"
|
||||
jsonrpc-pubsub = "17.1.0"
|
||||
jsonrpc-ws-server = "17.1.0"
|
||||
jsonrpc-core = "18.0.0"
|
||||
jsonrpc-core-client = { version = "18.0.0", features = ["ipc", "ws"] }
|
||||
jsonrpc-derive = "18.0.0"
|
||||
jsonrpc-http-server = "18.0.0"
|
||||
jsonrpc-pubsub = "18.0.0"
|
||||
jsonrpc-ws-server = "18.0.0"
|
||||
libc = "0.2.81"
|
||||
log = "0.4.11"
|
||||
lru = "0.6.1"
|
||||
@@ -52,37 +52,36 @@ serde = "1.0.122"
|
||||
serde_bytes = "0.11"
|
||||
serde_derive = "1.0.103"
|
||||
serde_json = "1.0.56"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.19" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.19" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.19" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.19" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.24" }
|
||||
solana-program-test = { path = "../program-test", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.24" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.24" }
|
||||
solana-streamer = { path = "../streamer", version = "=1.6.24" }
|
||||
solana-sys-tuner = { path = "../sys-tuner", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
spl-token-v2-0 = { package = "spl-token", version = "=3.1.1", features = ["no-entrypoint"] }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio_02 = { version = "0.2", package = "tokio", features = ["full"] }
|
||||
tokio-util = { version = "0.3", features = ["codec"] } # This crate needs to stay in sync with tokio_02, until that dependency can be removed
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.19" }
|
||||
tokio-util = { version = "0.6", features = ["codec"] }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.24" }
|
||||
trees = "0.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@@ -3,6 +3,7 @@
|
||||
//! can do its processing in parallel with signature verification on the GPU.
|
||||
use crate::{
|
||||
cluster_info::ClusterInfo,
|
||||
data_budget::DataBudget,
|
||||
packet_hasher::PacketHasher,
|
||||
poh_recorder::{PohRecorder, PohRecorderError, TransactionRecorder, WorkingBankEntry},
|
||||
poh_service::{self, PohService},
|
||||
@@ -260,6 +261,7 @@ impl BankingStage {
|
||||
LruCache::new(DEFAULT_LRU_SIZE),
|
||||
PacketHasher::default(),
|
||||
)));
|
||||
let data_budget = Arc::new(DataBudget::default());
|
||||
// Many banks that process transactions in parallel.
|
||||
let bank_thread_hdls: Vec<JoinHandle<()>> = (0..num_threads)
|
||||
.map(|i| {
|
||||
@@ -276,6 +278,7 @@ impl BankingStage {
|
||||
let transaction_status_sender = transaction_status_sender.clone();
|
||||
let gossip_vote_sender = gossip_vote_sender.clone();
|
||||
let duplicates = duplicates.clone();
|
||||
let data_budget = data_budget.clone();
|
||||
Builder::new()
|
||||
.name("solana-banking-stage-tx".to_string())
|
||||
.spawn(move || {
|
||||
@@ -292,6 +295,7 @@ impl BankingStage {
|
||||
transaction_status_sender,
|
||||
gossip_vote_sender,
|
||||
&duplicates,
|
||||
&data_budget,
|
||||
);
|
||||
})
|
||||
.unwrap()
|
||||
@@ -315,11 +319,21 @@ impl BankingStage {
|
||||
socket: &std::net::UdpSocket,
|
||||
tpu_forwards: &std::net::SocketAddr,
|
||||
unprocessed_packets: &UnprocessedPackets,
|
||||
data_budget: &DataBudget,
|
||||
) -> std::io::Result<()> {
|
||||
let packets = Self::filter_valid_packets_for_forwarding(unprocessed_packets.iter());
|
||||
inc_new_counter_info!("banking_stage-forwarded_packets", packets.len());
|
||||
const INTERVAL_MS: u64 = 100;
|
||||
const MAX_BYTES_PER_SECOND: usize = 10_000 * 1200;
|
||||
const MAX_BYTES_PER_INTERVAL: usize = MAX_BYTES_PER_SECOND * INTERVAL_MS as usize / 1000;
|
||||
const MAX_BYTES_BUDGET: usize = MAX_BYTES_PER_INTERVAL * 5;
|
||||
data_budget.update(INTERVAL_MS, |bytes| {
|
||||
std::cmp::min(bytes + MAX_BYTES_PER_INTERVAL, MAX_BYTES_BUDGET)
|
||||
});
|
||||
for p in packets {
|
||||
socket.send_to(&p.data[..p.meta.size], &tpu_forwards)?;
|
||||
if data_budget.take(p.meta.size) {
|
||||
socket.send_to(&p.data[..p.meta.size], &tpu_forwards)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -486,6 +500,7 @@ impl BankingStage {
|
||||
gossip_vote_sender: &ReplayVoteSender,
|
||||
banking_stage_stats: &BankingStageStats,
|
||||
recorder: &TransactionRecorder,
|
||||
data_budget: &DataBudget,
|
||||
) -> BufferedPacketsDecision {
|
||||
let bank_start;
|
||||
let (
|
||||
@@ -536,6 +551,7 @@ impl BankingStage {
|
||||
poh_recorder,
|
||||
socket,
|
||||
false,
|
||||
&data_budget,
|
||||
);
|
||||
}
|
||||
BufferedPacketsDecision::ForwardAndHold => {
|
||||
@@ -546,6 +562,7 @@ impl BankingStage {
|
||||
poh_recorder,
|
||||
socket,
|
||||
true,
|
||||
&data_budget,
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
@@ -560,6 +577,7 @@ impl BankingStage {
|
||||
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
||||
socket: &UdpSocket,
|
||||
hold: bool,
|
||||
data_budget: &DataBudget,
|
||||
) {
|
||||
if !enable_forwarding {
|
||||
if !hold {
|
||||
@@ -572,7 +590,7 @@ impl BankingStage {
|
||||
Some(addr) => addr,
|
||||
None => return,
|
||||
};
|
||||
let _ = Self::forward_buffered_packets(socket, &addr, buffered_packets);
|
||||
let _ = Self::forward_buffered_packets(socket, &addr, buffered_packets, data_budget);
|
||||
if hold {
|
||||
buffered_packets.retain(|(_, index, _)| !index.is_empty());
|
||||
for (_, _, forwarded) in buffered_packets.iter_mut() {
|
||||
@@ -596,6 +614,7 @@ impl BankingStage {
|
||||
transaction_status_sender: Option<TransactionStatusSender>,
|
||||
gossip_vote_sender: ReplayVoteSender,
|
||||
duplicates: &Arc<Mutex<(LruCache<u64, ()>, PacketHasher)>>,
|
||||
data_budget: &DataBudget,
|
||||
) {
|
||||
let recorder = poh_recorder.lock().unwrap().recorder();
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
@@ -614,6 +633,7 @@ impl BankingStage {
|
||||
&gossip_vote_sender,
|
||||
&banking_stage_stats,
|
||||
&recorder,
|
||||
&data_budget,
|
||||
);
|
||||
if matches!(decision, BufferedPacketsDecision::Hold)
|
||||
|| matches!(decision, BufferedPacketsDecision::ForwardAndHold)
|
||||
@@ -2694,6 +2714,55 @@ mod tests {
|
||||
Blockstore::destroy(&ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_forwarder_budget() {
|
||||
solana_logger::setup();
|
||||
// Create `Packets` with 1 unprocessed element
|
||||
let single_element_packets = Packets::new(vec![Packet::default()]);
|
||||
let mut unprocessed_packets: UnprocessedPackets =
|
||||
vec![(single_element_packets, vec![0], false)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
||||
|
||||
let genesis_config_info = create_slow_genesis_config(10_000);
|
||||
let GenesisConfigInfo { genesis_config, .. } = &genesis_config_info;
|
||||
|
||||
let bank = Arc::new(Bank::new_no_wallclock_throttle(&genesis_config));
|
||||
let ledger_path = get_tmp_ledger_path!();
|
||||
{
|
||||
let blockstore = Arc::new(
|
||||
Blockstore::open(&ledger_path)
|
||||
.expect("Expected to be able to open database ledger"),
|
||||
);
|
||||
let poh_config = PohConfig {
|
||||
// limit tick count to avoid clearing working_bank at
|
||||
// PohRecord then PohRecorderError(MaxHeightReached) at BankingStage
|
||||
target_tick_count: Some(bank.max_tick_height() - 1),
|
||||
..PohConfig::default()
|
||||
};
|
||||
|
||||
let (exit, poh_recorder, poh_service, _entry_receiver) =
|
||||
create_test_recorder(&bank, &blockstore, Some(poh_config));
|
||||
|
||||
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let data_budget = DataBudget::default();
|
||||
BankingStage::handle_forwarding(
|
||||
true,
|
||||
&cluster_info,
|
||||
&mut unprocessed_packets,
|
||||
&poh_recorder,
|
||||
&socket,
|
||||
false,
|
||||
&data_budget,
|
||||
);
|
||||
exit.store(true, Ordering::Relaxed);
|
||||
poh_service.join().unwrap();
|
||||
}
|
||||
Blockstore::destroy(&ledger_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_unprocessed_batch_limit() {
|
||||
solana_logger::setup();
|
||||
|
@@ -351,7 +351,7 @@ impl StandardBroadcastRun {
|
||||
if now - last > BROADCAST_PEER_UPDATE_INTERVAL_MS
|
||||
&& self
|
||||
.last_peer_update
|
||||
.compare_and_swap(now, last, Ordering::Relaxed)
|
||||
.compare_and_swap(last, now, Ordering::Relaxed)
|
||||
== last
|
||||
{
|
||||
let mut w_broadcast_peer_cache = self.broadcast_peer_cache.write().unwrap();
|
||||
|
@@ -12,77 +12,79 @@
|
||||
//! * layer 2 - Everyone else, if layer 1 is `2^10`, layer 2 should be able to fit `2^20` number of nodes.
|
||||
//!
|
||||
//! Bank needs to provide an interface for us to query the stake weight
|
||||
use crate::{
|
||||
cluster_info_metrics::{submit_gossip_stats, Counter, GossipStats, ScopedTimer},
|
||||
contact_info::ContactInfo,
|
||||
crds::Cursor,
|
||||
crds_gossip::CrdsGossip,
|
||||
crds_gossip_error::CrdsGossipError,
|
||||
crds_gossip_pull::{CrdsFilter, ProcessPullStats, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
|
||||
crds_value::{
|
||||
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, NodeInstance,
|
||||
SnapshotHash, Version, Vote, MAX_WALLCLOCK,
|
||||
use {
|
||||
crate::{
|
||||
cluster_info_metrics::{submit_gossip_stats, Counter, GossipStats, ScopedTimer},
|
||||
contact_info::ContactInfo,
|
||||
crds::Cursor,
|
||||
crds_gossip::CrdsGossip,
|
||||
crds_gossip_error::CrdsGossipError,
|
||||
crds_gossip_pull::{CrdsFilter, ProcessPullStats, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
|
||||
crds_value::{
|
||||
self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlotsIndex, LowestSlot, NodeInstance,
|
||||
SnapshotHash, Version, Vote, MAX_WALLCLOCK,
|
||||
},
|
||||
data_budget::DataBudget,
|
||||
epoch_slots::EpochSlots,
|
||||
ping_pong::{self, PingCache, Pong},
|
||||
result::{Error, Result},
|
||||
weighted_shuffle::weighted_shuffle,
|
||||
},
|
||||
data_budget::DataBudget,
|
||||
epoch_slots::EpochSlots,
|
||||
ping_pong::{self, PingCache, Pong},
|
||||
result::{Error, Result},
|
||||
weighted_shuffle::weighted_shuffle,
|
||||
};
|
||||
use rand::{seq::SliceRandom, CryptoRng, Rng};
|
||||
use solana_ledger::shred::Shred;
|
||||
use solana_sdk::sanitize::{Sanitize, SanitizeError};
|
||||
|
||||
use bincode::{serialize, serialized_size};
|
||||
use itertools::Itertools;
|
||||
use rand::thread_rng;
|
||||
use rayon::prelude::*;
|
||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||
use serde::ser::Serialize;
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_measure::thread_mem_usage;
|
||||
use solana_metrics::{inc_new_counter_debug, inc_new_counter_error};
|
||||
use solana_net_utils::{
|
||||
bind_common, bind_common_in_range, bind_in_range, find_available_port_in_range,
|
||||
multi_bind_in_range, PortRange,
|
||||
};
|
||||
use solana_perf::packet::{
|
||||
limited_deserialize, to_packets_with_destination, Packet, Packets, PacketsRecycler,
|
||||
PACKET_DATA_SIZE,
|
||||
};
|
||||
use solana_rayon_threadlimit::get_thread_count;
|
||||
use solana_runtime::bank_forks::BankForks;
|
||||
use solana_sdk::{
|
||||
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
|
||||
feature_set::{self, FeatureSet},
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signable, Signature, Signer},
|
||||
timing::timestamp,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_streamer::{
|
||||
sendmmsg::multicast,
|
||||
socket::is_global,
|
||||
streamer::{PacketReceiver, PacketSender},
|
||||
};
|
||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::{hash_map::Entry, HashMap, HashSet, VecDeque},
|
||||
fmt::Debug,
|
||||
fs::{self, File},
|
||||
io::BufReader,
|
||||
iter::repeat,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, UdpSocket},
|
||||
ops::{Deref, DerefMut, Div},
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
bincode::{serialize, serialized_size},
|
||||
itertools::Itertools,
|
||||
rand::thread_rng,
|
||||
rand::{seq::SliceRandom, CryptoRng, Rng},
|
||||
rayon::prelude::*,
|
||||
rayon::{ThreadPool, ThreadPoolBuilder},
|
||||
serde::ser::Serialize,
|
||||
solana_ledger::shred::Shred,
|
||||
solana_measure::measure::Measure,
|
||||
solana_measure::thread_mem_usage,
|
||||
solana_metrics::{inc_new_counter_debug, inc_new_counter_error},
|
||||
solana_net_utils::{
|
||||
bind_common, bind_common_in_range, bind_in_range, find_available_port_in_range,
|
||||
multi_bind_in_range, PortRange,
|
||||
},
|
||||
solana_perf::packet::{
|
||||
limited_deserialize, to_packets_with_destination, Packet, Packets, PacketsRecycler,
|
||||
PACKET_DATA_SIZE,
|
||||
},
|
||||
solana_rayon_threadlimit::get_thread_count,
|
||||
solana_runtime::bank_forks::BankForks,
|
||||
solana_sdk::{
|
||||
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_SLOTS_PER_EPOCH},
|
||||
feature_set::{self, FeatureSet},
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
sanitize::{Sanitize, SanitizeError},
|
||||
signature::{Keypair, Signable, Signature, Signer},
|
||||
timing::timestamp,
|
||||
transaction::Transaction,
|
||||
},
|
||||
solana_streamer::{
|
||||
sendmmsg::multicast,
|
||||
socket::is_global,
|
||||
streamer::{PacketReceiver, PacketSender},
|
||||
},
|
||||
solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY,
|
||||
std::{
|
||||
borrow::Cow,
|
||||
collections::{hash_map::Entry, HashMap, HashSet, VecDeque},
|
||||
fmt::Debug,
|
||||
fs::{self, File},
|
||||
io::BufReader,
|
||||
iter::repeat,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener, UdpSocket},
|
||||
ops::{Deref, DerefMut, Div},
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{Receiver, RecvTimeoutError, Sender},
|
||||
{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
},
|
||||
thread::{sleep, Builder, JoinHandle},
|
||||
time::{Duration, Instant},
|
||||
},
|
||||
thread::{sleep, Builder, JoinHandle},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub const VALIDATOR_PORT_RANGE: PortRange = (8000, 10_000);
|
||||
@@ -235,7 +237,7 @@ impl Default for ClusterInfo {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, AbiExample)]
|
||||
struct PruneData {
|
||||
pub(crate) struct PruneData {
|
||||
/// Pubkey of the node that sent this prune data
|
||||
pubkey: Pubkey,
|
||||
/// Pubkeys of nodes that should be pruned
|
||||
@@ -329,7 +331,7 @@ pub(crate) type Ping = ping_pong::Ping<[u8; GOSSIP_PING_TOKEN_SIZE]>;
|
||||
#[frozen_abi(digest = "CH5BWuhAyvUiUQYgu2Lcwu7eoiW6bQitvtLS1yFsdmrE")]
|
||||
#[derive(Serialize, Deserialize, Debug, AbiEnumVisitor, AbiExample)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Protocol {
|
||||
pub(crate) enum Protocol {
|
||||
/// Gossip protocol messages
|
||||
PullRequest(CrdsFilter, CrdsValue),
|
||||
PullResponse(Pubkey, Vec<CrdsValue>),
|
||||
@@ -897,29 +899,24 @@ impl ClusterInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_epoch_slots(&self, update: &[Slot]) {
|
||||
let mut num = 0;
|
||||
let mut current_slots: Vec<_> = (0..crds_value::MAX_EPOCH_SLOTS)
|
||||
.filter_map(|ix| {
|
||||
Some((
|
||||
self.time_gossip_read_lock(
|
||||
"lookup_epoch_slots",
|
||||
&self.stats.epoch_slots_lookup,
|
||||
)
|
||||
.crds
|
||||
.get(&CrdsValueLabel::EpochSlots(ix, self.id()))
|
||||
.and_then(|v| v.value.epoch_slots())
|
||||
.and_then(|x| Some((x.wallclock, x.first_slot()?)))?,
|
||||
ix,
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
current_slots.sort_unstable();
|
||||
pub(crate) fn push_epoch_slots(&self, mut update: &[Slot]) {
|
||||
let current_slots: Vec<_> = {
|
||||
let gossip =
|
||||
self.time_gossip_read_lock("lookup_epoch_slots", &self.stats.epoch_slots_lookup);
|
||||
(0..crds_value::MAX_EPOCH_SLOTS)
|
||||
.filter_map(|ix| {
|
||||
let label = CrdsValueLabel::EpochSlots(ix, self.id());
|
||||
let epoch_slots = gossip.crds.get(&label)?.value.epoch_slots()?;
|
||||
let first_slot = epoch_slots.first_slot()?;
|
||||
Some((epoch_slots.wallclock, first_slot, ix))
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
let min_slot: Slot = current_slots
|
||||
.iter()
|
||||
.map(|((_, s), _)| *s)
|
||||
.map(|(_wallclock, slot, _index)| *slot)
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
.unwrap_or_default();
|
||||
let max_slot: Slot = update.iter().max().cloned().unwrap_or(0);
|
||||
let total_slots = max_slot as isize - min_slot as isize;
|
||||
// WARN if CRDS is not storing at least a full epoch worth of slots
|
||||
@@ -934,8 +931,11 @@ impl ClusterInfo {
|
||||
);
|
||||
}
|
||||
let mut reset = false;
|
||||
let mut epoch_slot_index = current_slots.last().map(|(_, x)| *x).unwrap_or(0);
|
||||
while num < update.len() {
|
||||
let mut epoch_slot_index = match current_slots.iter().max() {
|
||||
Some((_wallclock, _slot, index)) => *index,
|
||||
None => 0,
|
||||
};
|
||||
while !update.is_empty() {
|
||||
let ix = (epoch_slot_index % crds_value::MAX_EPOCH_SLOTS) as u8;
|
||||
let now = timestamp();
|
||||
let mut slots = if !reset {
|
||||
@@ -943,7 +943,8 @@ impl ClusterInfo {
|
||||
} else {
|
||||
EpochSlots::new(self.id(), now)
|
||||
};
|
||||
let n = slots.fill(&update[num..], now);
|
||||
let n = slots.fill(update, now);
|
||||
update = &update[n..];
|
||||
if n > 0 {
|
||||
let entry = CrdsValue::new_signed(CrdsData::EpochSlots(ix, slots), &self.keypair);
|
||||
self.local_message_pending_push_queue
|
||||
@@ -951,11 +952,8 @@ impl ClusterInfo {
|
||||
.unwrap()
|
||||
.push(entry);
|
||||
}
|
||||
num += n;
|
||||
if num < update.len() {
|
||||
epoch_slot_index += 1;
|
||||
reset = true;
|
||||
}
|
||||
epoch_slot_index += 1;
|
||||
reset = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,10 +1159,19 @@ impl ClusterInfo {
|
||||
.map(map)
|
||||
}
|
||||
|
||||
/// Returns epoch-slots inserted since the given cursor.
|
||||
/// Excludes entries from nodes with unkown or different shred version.
|
||||
pub(crate) fn get_epoch_slots(&self, cursor: &mut Cursor) -> Vec<EpochSlots> {
|
||||
let self_shred_version = self.my_shred_version();
|
||||
let gossip = self.gossip.read().unwrap();
|
||||
let entries = gossip.crds.get_epoch_slots(cursor);
|
||||
entries
|
||||
.filter(
|
||||
|entry| match gossip.crds.get_contact_info(entry.value.pubkey()) {
|
||||
Some(node) => node.shred_version == self_shred_version,
|
||||
None => false,
|
||||
},
|
||||
)
|
||||
.map(|entry| match &entry.value.data {
|
||||
CrdsData::EpochSlots(_, slots) => slots.clone(),
|
||||
_ => panic!("this should not happen!"),
|
||||
@@ -1751,11 +1758,14 @@ impl ClusterInfo {
|
||||
.map(|k| k.id)
|
||||
.chain(std::iter::once(self.id))
|
||||
.collect();
|
||||
self.stats.trim_crds_table.add_relaxed(1);
|
||||
let mut gossip = self.gossip.write().unwrap();
|
||||
match gossip.crds.trim(cap, &keep, stakes, timestamp()) {
|
||||
Err(err) => {
|
||||
self.stats.trim_crds_table_failed.add_relaxed(1);
|
||||
error!("crds table trim failed: {:?}", err);
|
||||
// TODO: Stakes are comming from the root-bank. Debug why/when
|
||||
// they are empty/zero.
|
||||
debug!("crds table trim failed: {:?}", err);
|
||||
}
|
||||
Ok(num_purged) => {
|
||||
self.stats
|
||||
@@ -1771,9 +1781,8 @@ impl ClusterInfo {
|
||||
bank_forks: Option<Arc<RwLock<BankForks>>>,
|
||||
sender: PacketSender,
|
||||
gossip_validators: Option<HashSet<Pubkey>>,
|
||||
exit: &Arc<AtomicBool>,
|
||||
exit: Arc<AtomicBool>,
|
||||
) -> JoinHandle<()> {
|
||||
let exit = exit.clone();
|
||||
let thread_pool = ThreadPoolBuilder::new()
|
||||
.num_threads(std::cmp::min(get_thread_count(), 8))
|
||||
.thread_name(|i| format!("ClusterInfo::gossip-{}", i))
|
||||
@@ -1956,8 +1965,13 @@ impl ClusterInfo {
|
||||
self.stats
|
||||
.pull_requests_count
|
||||
.add_relaxed(requests.len() as u64);
|
||||
let response =
|
||||
self.handle_pull_requests(recycler, requests, stakes, require_stake_for_gossip);
|
||||
let response = self.handle_pull_requests(
|
||||
thread_pool,
|
||||
recycler,
|
||||
requests,
|
||||
stakes,
|
||||
require_stake_for_gossip,
|
||||
);
|
||||
if !response.is_empty() {
|
||||
self.stats
|
||||
.packets_sent_pull_responses_count
|
||||
@@ -2027,6 +2041,7 @@ impl ClusterInfo {
|
||||
// and tries to send back to them the values it detects are missing.
|
||||
fn handle_pull_requests(
|
||||
&self,
|
||||
thread_pool: &ThreadPool,
|
||||
recycler: &PacketsRecycler,
|
||||
requests: Vec<PullData>,
|
||||
stakes: &HashMap<Pubkey, u64>,
|
||||
@@ -2058,7 +2073,7 @@ impl ClusterInfo {
|
||||
"generate_pull_responses",
|
||||
&self.stats.generate_pull_responses,
|
||||
)
|
||||
.generate_pull_responses(&caller_and_filters, output_size_limit, now);
|
||||
.generate_pull_responses(thread_pool, &caller_and_filters, output_size_limit, now);
|
||||
if require_stake_for_gossip {
|
||||
for resp in &mut pull_responses {
|
||||
retain_staked(resp, stakes);
|
||||
@@ -2495,7 +2510,7 @@ impl ClusterInfo {
|
||||
|
||||
fn process_packets(
|
||||
&self,
|
||||
packets: VecDeque<Packet>,
|
||||
packets: VecDeque<(/*from:*/ SocketAddr, Protocol)>,
|
||||
thread_pool: &ThreadPool,
|
||||
recycler: &PacketsRecycler,
|
||||
response_sender: &PacketSender,
|
||||
@@ -2505,24 +2520,6 @@ impl ClusterInfo {
|
||||
should_check_duplicate_instance: bool,
|
||||
) -> Result<()> {
|
||||
let _st = ScopedTimer::from(&self.stats.process_gossip_packets_time);
|
||||
self.stats
|
||||
.packets_received_count
|
||||
.add_relaxed(packets.len() as u64);
|
||||
let packets: Vec<_> = thread_pool.install(|| {
|
||||
packets
|
||||
.into_par_iter()
|
||||
.filter_map(|packet| {
|
||||
let protocol: Protocol =
|
||||
limited_deserialize(&packet.data[..packet.meta.size]).ok()?;
|
||||
protocol.sanitize().ok()?;
|
||||
let protocol = protocol.par_verify()?;
|
||||
Some((packet.meta.addr(), protocol))
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
self.stats
|
||||
.packets_received_verified_count
|
||||
.add_relaxed(packets.len() as u64);
|
||||
// Check if there is a duplicate instance of
|
||||
// this node with more recent timestamp.
|
||||
let check_duplicate_instance = |values: &[CrdsValue]| {
|
||||
@@ -2607,12 +2604,54 @@ impl ClusterInfo {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Consumes packets received from the socket, deserializing, sanitizing and
|
||||
// verifying them and then sending them down the channel for the actual
|
||||
// handling of requests/messages.
|
||||
fn run_socket_consume(
|
||||
&self,
|
||||
receiver: &PacketReceiver,
|
||||
sender: &Sender<Vec<(/*from:*/ SocketAddr, Protocol)>>,
|
||||
thread_pool: &ThreadPool,
|
||||
) -> Result<()> {
|
||||
const RECV_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
let packets: Vec<_> = receiver.recv_timeout(RECV_TIMEOUT)?.packets.into();
|
||||
let mut packets = VecDeque::from(packets);
|
||||
for payload in receiver.try_iter() {
|
||||
packets.extend(payload.packets.iter().cloned());
|
||||
let excess_count = packets.len().saturating_sub(MAX_GOSSIP_TRAFFIC);
|
||||
if excess_count > 0 {
|
||||
packets.drain(0..excess_count);
|
||||
self.stats
|
||||
.gossip_packets_dropped_count
|
||||
.add_relaxed(excess_count as u64);
|
||||
}
|
||||
}
|
||||
self.stats
|
||||
.packets_received_count
|
||||
.add_relaxed(packets.len() as u64);
|
||||
let verify_packet = |packet: Packet| {
|
||||
let data = &packet.data[..packet.meta.size];
|
||||
let protocol: Protocol = limited_deserialize(data).ok()?;
|
||||
protocol.sanitize().ok()?;
|
||||
let protocol = protocol.par_verify()?;
|
||||
Some((packet.meta.addr(), protocol))
|
||||
};
|
||||
let packets: Vec<_> = {
|
||||
let _st = ScopedTimer::from(&self.stats.verify_gossip_packets_time);
|
||||
thread_pool.install(|| packets.into_par_iter().filter_map(verify_packet).collect())
|
||||
};
|
||||
self.stats
|
||||
.packets_received_verified_count
|
||||
.add_relaxed(packets.len() as u64);
|
||||
Ok(sender.send(packets)?)
|
||||
}
|
||||
|
||||
/// Process messages from the network
|
||||
fn run_listen(
|
||||
&self,
|
||||
recycler: &PacketsRecycler,
|
||||
bank_forks: Option<&RwLock<BankForks>>,
|
||||
requests_receiver: &PacketReceiver,
|
||||
receiver: &Receiver<Vec<(/*from:*/ SocketAddr, Protocol)>>,
|
||||
response_sender: &PacketSender,
|
||||
thread_pool: &ThreadPool,
|
||||
last_print: &mut Instant,
|
||||
@@ -2620,10 +2659,9 @@ impl ClusterInfo {
|
||||
) -> Result<()> {
|
||||
const RECV_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
const SUBMIT_GOSSIP_STATS_INTERVAL: Duration = Duration::from_secs(2);
|
||||
let packets: Vec<_> = requests_receiver.recv_timeout(RECV_TIMEOUT)?.packets.into();
|
||||
let mut packets = VecDeque::from(packets);
|
||||
while let Ok(packet) = requests_receiver.try_recv() {
|
||||
packets.extend(packet.packets.into_iter());
|
||||
let mut packets = VecDeque::from(receiver.recv_timeout(RECV_TIMEOUT)?);
|
||||
for payload in receiver.try_iter() {
|
||||
packets.extend(payload);
|
||||
let excess_count = packets.len().saturating_sub(MAX_GOSSIP_TRAFFIC);
|
||||
if excess_count > 0 {
|
||||
packets.drain(0..excess_count);
|
||||
@@ -2660,26 +2698,53 @@ impl ClusterInfo {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn listen(
|
||||
pub(crate) fn start_socket_consume_thread(
|
||||
self: Arc<Self>,
|
||||
receiver: PacketReceiver,
|
||||
sender: Sender<Vec<(/*from:*/ SocketAddr, Protocol)>>,
|
||||
exit: Arc<AtomicBool>,
|
||||
) -> JoinHandle<()> {
|
||||
let thread_pool = ThreadPoolBuilder::new()
|
||||
.num_threads(get_thread_count().min(8))
|
||||
.thread_name(|i| format!("gossip-consume-{}", i))
|
||||
.build()
|
||||
.unwrap();
|
||||
let run_consume = move || {
|
||||
while !exit.load(Ordering::Relaxed) {
|
||||
match self.run_socket_consume(&receiver, &sender, &thread_pool) {
|
||||
Err(Error::RecvTimeoutError(RecvTimeoutError::Disconnected)) => break,
|
||||
Err(Error::RecvTimeoutError(RecvTimeoutError::Timeout)) => (),
|
||||
// A send operation can only fail if the receiving end of a
|
||||
// channel is disconnected.
|
||||
Err(Error::SendError) => break,
|
||||
Err(err) => error!("gossip consume: {}", err),
|
||||
Ok(()) => (),
|
||||
}
|
||||
}
|
||||
};
|
||||
let thread_name = String::from("gossip-consume");
|
||||
Builder::new().name(thread_name).spawn(run_consume).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn listen(
|
||||
self: Arc<Self>,
|
||||
bank_forks: Option<Arc<RwLock<BankForks>>>,
|
||||
requests_receiver: PacketReceiver,
|
||||
requests_receiver: Receiver<Vec<(/*from:*/ SocketAddr, Protocol)>>,
|
||||
response_sender: PacketSender,
|
||||
should_check_duplicate_instance: bool,
|
||||
exit: &Arc<AtomicBool>,
|
||||
exit: Arc<AtomicBool>,
|
||||
) -> JoinHandle<()> {
|
||||
let exit = exit.clone();
|
||||
let recycler =
|
||||
PacketsRecycler::new_without_limit("cluster-info-listen-recycler-shrink-stats");
|
||||
let mut last_print = Instant::now();
|
||||
let thread_pool = ThreadPoolBuilder::new()
|
||||
.num_threads(get_thread_count().min(8))
|
||||
.thread_name(|i| format!("sol-gossip-work-{}", i))
|
||||
.build()
|
||||
.unwrap();
|
||||
Builder::new()
|
||||
.name("solana-listen".to_string())
|
||||
.spawn(move || {
|
||||
let thread_pool = ThreadPoolBuilder::new()
|
||||
.num_threads(std::cmp::min(get_thread_count(), 8))
|
||||
.thread_name(|i| format!("sol-gossip-work-{}", i))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut last_print = Instant::now();
|
||||
while !exit.load(Ordering::Relaxed) {
|
||||
if let Err(err) = self.run_listen(
|
||||
&recycler,
|
||||
@@ -2691,7 +2756,8 @@ impl ClusterInfo {
|
||||
should_check_duplicate_instance,
|
||||
) {
|
||||
match err {
|
||||
Error::RecvTimeoutError(_) => {
|
||||
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
|
||||
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => {
|
||||
let table_size = self.gossip.read().unwrap().crds.len();
|
||||
debug!(
|
||||
"{}: run_listen timeout, table size: {}",
|
||||
@@ -3769,6 +3835,43 @@ mod tests {
|
||||
|
||||
let slots = cluster_info.get_epoch_slots(&mut cursor);
|
||||
assert!(slots.is_empty());
|
||||
|
||||
// Test with different shred versions.
|
||||
let mut rng = rand::thread_rng();
|
||||
let node_pubkey = Pubkey::new_unique();
|
||||
let mut node = ContactInfo::new_rand(&mut rng, Some(node_pubkey));
|
||||
node.shred_version = 42;
|
||||
let epoch_slots = EpochSlots::new_rand(&mut rng, Some(node_pubkey));
|
||||
let entries = vec![
|
||||
CrdsValue::new_unsigned(CrdsData::ContactInfo(node)),
|
||||
CrdsValue::new_unsigned(CrdsData::EpochSlots(0, epoch_slots)),
|
||||
];
|
||||
{
|
||||
let mut gossip = cluster_info.gossip.write().unwrap();
|
||||
for entry in entries {
|
||||
assert!(gossip.crds.insert(entry, /*now=*/ 0).is_ok());
|
||||
}
|
||||
}
|
||||
// Should exclude other node's epoch-slot because of different
|
||||
// shred-version.
|
||||
let slots = cluster_info.get_epoch_slots(&mut Cursor::default());
|
||||
assert_eq!(slots.len(), 1);
|
||||
assert_eq!(slots[0].from, cluster_info.id);
|
||||
// Match shred versions.
|
||||
{
|
||||
let mut node = cluster_info.my_contact_info.write().unwrap();
|
||||
node.shred_version = 42;
|
||||
}
|
||||
cluster_info.push_self(
|
||||
&HashMap::default(), // stakes
|
||||
None, // gossip validators
|
||||
);
|
||||
cluster_info.flush_push_queue();
|
||||
// Should now include both epoch slots.
|
||||
let slots = cluster_info.get_epoch_slots(&mut Cursor::default());
|
||||
assert_eq!(slots.len(), 2);
|
||||
assert_eq!(slots[0].from, cluster_info.id);
|
||||
assert_eq!(slots[1].from, node_pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@@ -113,9 +113,11 @@ pub(crate) struct GossipStats {
|
||||
pub(crate) skip_pull_response_shred_version: Counter,
|
||||
pub(crate) skip_pull_shred_version: Counter,
|
||||
pub(crate) skip_push_message_shred_version: Counter,
|
||||
pub(crate) trim_crds_table: Counter,
|
||||
pub(crate) trim_crds_table_failed: Counter,
|
||||
pub(crate) trim_crds_table_purged_values_count: Counter,
|
||||
pub(crate) tvu_peers: Counter,
|
||||
pub(crate) verify_gossip_packets_time: Counter,
|
||||
}
|
||||
|
||||
pub(crate) fn submit_gossip_stats(
|
||||
@@ -169,6 +171,11 @@ pub(crate) fn submit_gossip_stats(
|
||||
stats.process_gossip_packets_time.clear(),
|
||||
i64
|
||||
),
|
||||
(
|
||||
"verify_gossip_packets_time",
|
||||
stats.verify_gossip_packets_time.clear(),
|
||||
i64
|
||||
),
|
||||
(
|
||||
"handle_batch_ping_messages_time",
|
||||
stats.handle_batch_ping_messages_time.clear(),
|
||||
@@ -390,6 +397,7 @@ pub(crate) fn submit_gossip_stats(
|
||||
stats.require_stake_for_gossip_unknown_stakes.clear(),
|
||||
i64
|
||||
),
|
||||
("trim_crds_table", stats.trim_crds_table.clear(), i64),
|
||||
(
|
||||
"trim_crds_table_failed",
|
||||
stats.trim_crds_table_failed.clear(),
|
||||
|
@@ -136,6 +136,9 @@ impl ClusterSlots {
|
||||
}
|
||||
|
||||
pub fn compute_weights(&self, slot: Slot, repair_peers: &[ContactInfo]) -> Vec<u64> {
|
||||
if repair_peers.is_empty() {
|
||||
return Vec::default();
|
||||
}
|
||||
let stakes = {
|
||||
let validator_stakes = self.validator_stakes.read().unwrap();
|
||||
repair_peers
|
||||
|
@@ -383,22 +383,20 @@ impl Crds {
|
||||
// returns crds labels of old values to be evicted.
|
||||
let evict = |pubkey, index: &IndexSet<usize>| {
|
||||
let timeout = timeouts.get(pubkey).copied().unwrap_or(default_timeout);
|
||||
let local_timestamp = {
|
||||
let origin = CrdsValueLabel::ContactInfo(*pubkey);
|
||||
match self.table.get(&origin) {
|
||||
Some(origin) => origin.local_timestamp,
|
||||
None => 0,
|
||||
// If the origin's contact-info hasn't expired yet then preserve
|
||||
// all associated values.
|
||||
let origin = CrdsValueLabel::ContactInfo(*pubkey);
|
||||
if let Some(origin) = self.table.get(&origin) {
|
||||
if now < origin.local_timestamp.saturating_add(timeout) {
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
}
|
||||
// Otherwise check each value's timestamp individually.
|
||||
index
|
||||
.into_iter()
|
||||
.filter_map(|ix| {
|
||||
let (label, value) = self.table.get_index(*ix).unwrap();
|
||||
let expiry_timestamp = value
|
||||
.local_timestamp
|
||||
.max(local_timestamp)
|
||||
.saturating_add(timeout);
|
||||
if expiry_timestamp <= now {
|
||||
if value.local_timestamp.saturating_add(timeout) <= now {
|
||||
Some(label.clone())
|
||||
} else {
|
||||
None
|
||||
@@ -511,7 +509,7 @@ impl Crds {
|
||||
stakes: &HashMap<Pubkey, u64>,
|
||||
now: u64,
|
||||
) -> Result</*num purged:*/ usize, CrdsError> {
|
||||
if stakes.is_empty() {
|
||||
if stakes.values().all(|&stake| stake == 0) {
|
||||
return Err(CrdsError::UnknownStakes);
|
||||
}
|
||||
let mut keys: Vec<_> = self
|
||||
|
@@ -254,12 +254,13 @@ impl CrdsGossip {
|
||||
|
||||
pub fn generate_pull_responses(
|
||||
&self,
|
||||
thread_pool: &ThreadPool,
|
||||
filters: &[(CrdsValue, CrdsFilter)],
|
||||
output_size_limit: usize, // Limit number of crds values returned.
|
||||
now: u64,
|
||||
) -> Vec<Vec<CrdsValue>> {
|
||||
self.pull
|
||||
.generate_pull_responses(&self.crds, filters, output_size_limit, now)
|
||||
.generate_pull_responses(thread_pool, &self.crds, filters, output_size_limit, now)
|
||||
}
|
||||
|
||||
pub fn filter_pull_responses(
|
||||
|
@@ -9,32 +9,38 @@
|
||||
//! with random hash functions. So each subsequent request will have a different distribution
|
||||
//! of false positives.
|
||||
|
||||
use crate::{
|
||||
cluster_info::{Ping, CRDS_UNIQUE_PUBKEY_CAPACITY},
|
||||
contact_info::ContactInfo,
|
||||
crds::Crds,
|
||||
crds_gossip::{get_stake, get_weight},
|
||||
crds_gossip_error::CrdsGossipError,
|
||||
crds_value::CrdsValue,
|
||||
ping_pong::PingCache,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use lru::LruCache;
|
||||
use rand::distributions::{Distribution, WeightedIndex};
|
||||
use rand::Rng;
|
||||
use rayon::{prelude::*, ThreadPool};
|
||||
use solana_runtime::bloom::{AtomicBloom, Bloom};
|
||||
use solana_sdk::{
|
||||
hash::{hash, Hash},
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
convert::TryInto,
|
||||
net::SocketAddr,
|
||||
sync::Mutex,
|
||||
time::{Duration, Instant},
|
||||
use {
|
||||
crate::{
|
||||
cluster_info::{Ping, CRDS_UNIQUE_PUBKEY_CAPACITY},
|
||||
contact_info::ContactInfo,
|
||||
crds::Crds,
|
||||
crds_gossip::{get_stake, get_weight},
|
||||
crds_gossip_error::CrdsGossipError,
|
||||
crds_value::CrdsValue,
|
||||
ping_pong::PingCache,
|
||||
},
|
||||
lru::LruCache,
|
||||
rand::{
|
||||
distributions::{Distribution, WeightedIndex},
|
||||
Rng,
|
||||
},
|
||||
rayon::{prelude::*, ThreadPool},
|
||||
solana_runtime::bloom::{AtomicBloom, Bloom},
|
||||
solana_sdk::{
|
||||
hash::{hash, Hash},
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
},
|
||||
std::{
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
convert::TryInto,
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicI64, AtomicUsize, Ordering},
|
||||
Mutex,
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
},
|
||||
};
|
||||
|
||||
pub const CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS: u64 = 15000;
|
||||
@@ -333,12 +339,13 @@ impl CrdsGossipPull {
|
||||
/// Create gossip responses to pull requests
|
||||
pub fn generate_pull_responses(
|
||||
&self,
|
||||
thread_pool: &ThreadPool,
|
||||
crds: &Crds,
|
||||
requests: &[(CrdsValue, CrdsFilter)],
|
||||
output_size_limit: usize, // Limit number of crds values returned.
|
||||
now: u64,
|
||||
) -> Vec<Vec<CrdsValue>> {
|
||||
self.filter_crds_values(crds, requests, output_size_limit, now)
|
||||
self.filter_crds_values(thread_pool, crds, requests, output_size_limit, now)
|
||||
}
|
||||
|
||||
// Checks if responses should be inserted and
|
||||
@@ -472,9 +479,10 @@ impl CrdsGossipPull {
|
||||
/// filter values that fail the bloom filter up to max_bytes
|
||||
fn filter_crds_values(
|
||||
&self,
|
||||
thread_pool: &ThreadPool,
|
||||
crds: &Crds,
|
||||
filters: &[(CrdsValue, CrdsFilter)],
|
||||
mut output_size_limit: usize, // Limit number of crds values returned.
|
||||
output_size_limit: usize, // Limit number of crds values returned.
|
||||
now: u64,
|
||||
) -> Vec<Vec<CrdsValue>> {
|
||||
let msg_timeout = CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS;
|
||||
@@ -482,46 +490,53 @@ impl CrdsGossipPull {
|
||||
//skip filters from callers that are too old
|
||||
let caller_wallclock_window =
|
||||
now.saturating_sub(msg_timeout)..now.saturating_add(msg_timeout);
|
||||
let mut dropped_requests = 0;
|
||||
let mut total_skipped = 0;
|
||||
let ret: Vec<_> = filters
|
||||
.iter()
|
||||
.map(|(caller, filter)| {
|
||||
if output_size_limit == 0 {
|
||||
return None;
|
||||
}
|
||||
let caller_wallclock = caller.wallclock();
|
||||
if !caller_wallclock_window.contains(&caller_wallclock) {
|
||||
dropped_requests += 1;
|
||||
return Some(vec![]);
|
||||
}
|
||||
let caller_wallclock = caller_wallclock.checked_add(jitter).unwrap_or(0);
|
||||
let out: Vec<_> = crds
|
||||
.filter_bitmask(filter.mask, filter.mask_bits)
|
||||
.filter_map(|item| {
|
||||
debug_assert!(filter.test_mask(&item.value_hash));
|
||||
//skip values that are too new
|
||||
if item.value.wallclock() > caller_wallclock {
|
||||
total_skipped += 1;
|
||||
None
|
||||
} else if filter.filter_contains(&item.value_hash) {
|
||||
None
|
||||
} else {
|
||||
Some(item.value.clone())
|
||||
}
|
||||
})
|
||||
.take(output_size_limit)
|
||||
.collect();
|
||||
output_size_limit -= out.len();
|
||||
Some(out)
|
||||
})
|
||||
.while_some()
|
||||
.collect();
|
||||
let dropped_requests = AtomicUsize::default();
|
||||
let total_skipped = AtomicUsize::default();
|
||||
let output_size_limit = output_size_limit.try_into().unwrap_or(i64::MAX);
|
||||
let output_size_limit = AtomicI64::new(output_size_limit);
|
||||
let apply_filter = |caller: &CrdsValue, filter: &CrdsFilter| {
|
||||
if output_size_limit.load(Ordering::Relaxed) <= 0 {
|
||||
return Vec::default();
|
||||
}
|
||||
let caller_wallclock = caller.wallclock();
|
||||
if !caller_wallclock_window.contains(&caller_wallclock) {
|
||||
dropped_requests.fetch_add(1, Ordering::Relaxed);
|
||||
return Vec::default();
|
||||
}
|
||||
let caller_wallclock = caller_wallclock.checked_add(jitter).unwrap_or(0);
|
||||
let out: Vec<_> = crds
|
||||
.filter_bitmask(filter.mask, filter.mask_bits)
|
||||
.filter_map(|item| {
|
||||
debug_assert!(filter.test_mask(&item.value_hash));
|
||||
//skip values that are too new
|
||||
if item.value.wallclock() > caller_wallclock {
|
||||
total_skipped.fetch_add(1, Ordering::Relaxed);
|
||||
None
|
||||
} else if filter.filter_contains(&item.value_hash) {
|
||||
None
|
||||
} else {
|
||||
Some(item.value.clone())
|
||||
}
|
||||
})
|
||||
.take(output_size_limit.load(Ordering::Relaxed).max(0) as usize)
|
||||
.collect();
|
||||
output_size_limit.fetch_sub(out.len() as i64, Ordering::Relaxed);
|
||||
out
|
||||
};
|
||||
let ret: Vec<_> = thread_pool.install(|| {
|
||||
filters
|
||||
.par_iter()
|
||||
.map(|(caller, filter)| apply_filter(caller, filter))
|
||||
.collect()
|
||||
});
|
||||
inc_new_counter_info!(
|
||||
"gossip_filter_crds_values-dropped_requests",
|
||||
dropped_requests + filters.len() - ret.len()
|
||||
dropped_requests.into_inner()
|
||||
);
|
||||
inc_new_counter_info!(
|
||||
"gossip_filter_crds_values-dropped_values",
|
||||
total_skipped.into_inner()
|
||||
);
|
||||
inc_new_counter_info!("gossip_filter_crds_values-dropped_values", total_skipped);
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -1098,10 +1113,11 @@ pub(crate) mod tests {
|
||||
let (_, filters) = req.unwrap();
|
||||
let mut filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect();
|
||||
let rsp = dest.generate_pull_responses(
|
||||
&thread_pool,
|
||||
&dest_crds,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
0,
|
||||
usize::MAX, // output_size_limit
|
||||
0, // now
|
||||
);
|
||||
|
||||
assert_eq!(rsp[0].len(), 0);
|
||||
@@ -1116,10 +1132,11 @@ pub(crate) mod tests {
|
||||
|
||||
//should skip new value since caller is to old
|
||||
let rsp = dest.generate_pull_responses(
|
||||
&thread_pool,
|
||||
&dest_crds,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS,
|
||||
usize::MAX, // output_size_limit
|
||||
CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS, // now
|
||||
);
|
||||
assert_eq!(rsp[0].len(), 0);
|
||||
assert_eq!(filters.len(), MIN_NUM_BLOOM_FILTERS);
|
||||
@@ -1134,9 +1151,10 @@ pub(crate) mod tests {
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
let rsp = dest.generate_pull_responses(
|
||||
&thread_pool,
|
||||
&dest_crds,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
usize::MAX, // output_size_limit
|
||||
CRDS_GOSSIP_PULL_MSG_TIMEOUT_MS,
|
||||
);
|
||||
assert_eq!(rsp.len(), 2 * MIN_NUM_BLOOM_FILTERS);
|
||||
@@ -1186,10 +1204,11 @@ pub(crate) mod tests {
|
||||
let (_, filters) = req.unwrap();
|
||||
let filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect();
|
||||
let rsp = dest.generate_pull_responses(
|
||||
&thread_pool,
|
||||
&dest_crds,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
0,
|
||||
usize::MAX, // output_size_limit
|
||||
0, // now
|
||||
);
|
||||
dest.process_pull_requests(
|
||||
&mut dest_crds,
|
||||
@@ -1258,10 +1277,11 @@ pub(crate) mod tests {
|
||||
let (_, filters) = req.unwrap();
|
||||
let filters: Vec<_> = filters.into_iter().map(|f| (caller.clone(), f)).collect();
|
||||
let rsp = dest.generate_pull_responses(
|
||||
&thread_pool,
|
||||
&dest_crds,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
0,
|
||||
usize::MAX, // output_size_limit
|
||||
0, // now
|
||||
);
|
||||
dest.process_pull_requests(
|
||||
&mut dest_crds,
|
||||
|
@@ -51,24 +51,40 @@ impl GossipService {
|
||||
"gossip_receiver",
|
||||
1,
|
||||
);
|
||||
let (response_sender, response_receiver) = channel();
|
||||
let t_responder = streamer::responder("gossip", gossip_socket, response_receiver);
|
||||
let t_listen = ClusterInfo::listen(
|
||||
cluster_info.clone(),
|
||||
bank_forks.clone(),
|
||||
let (consume_sender, listen_receiver) = channel();
|
||||
// https://github.com/rust-lang/rust/issues/39364#issuecomment-634545136
|
||||
let _consume_sender = consume_sender.clone();
|
||||
let t_socket_consume = cluster_info.clone().start_socket_consume_thread(
|
||||
request_receiver,
|
||||
consume_sender,
|
||||
exit.clone(),
|
||||
);
|
||||
let (response_sender, response_receiver) = channel();
|
||||
let t_listen = cluster_info.clone().listen(
|
||||
bank_forks.clone(),
|
||||
listen_receiver,
|
||||
response_sender.clone(),
|
||||
should_check_duplicate_instance,
|
||||
exit,
|
||||
exit.clone(),
|
||||
);
|
||||
let t_gossip = ClusterInfo::gossip(
|
||||
cluster_info.clone(),
|
||||
let t_gossip = cluster_info.clone().gossip(
|
||||
bank_forks,
|
||||
response_sender,
|
||||
gossip_validators,
|
||||
exit,
|
||||
exit.clone(),
|
||||
);
|
||||
let thread_hdls = vec![t_receiver, t_responder, t_listen, t_gossip];
|
||||
// To work around:
|
||||
// https://github.com/rust-lang/rust/issues/54267
|
||||
// responder thread should start after response_sender.clone(). see:
|
||||
// https://github.com/rust-lang/rust/issues/39364#issuecomment-381446873
|
||||
let t_responder = streamer::responder("gossip", gossip_socket, response_receiver);
|
||||
let thread_hdls = vec![
|
||||
t_receiver,
|
||||
t_responder,
|
||||
t_socket_consume,
|
||||
t_listen,
|
||||
t_gossip,
|
||||
];
|
||||
Self { thread_hdls }
|
||||
}
|
||||
|
||||
@@ -229,7 +245,7 @@ fn spy(
|
||||
.into_iter()
|
||||
.map(|x| x.0)
|
||||
.collect::<Vec<_>>();
|
||||
tvu_peers = spy_ref.all_tvu_peers().into_iter().collect::<Vec<_>>();
|
||||
tvu_peers = spy_ref.all_tvu_peers();
|
||||
|
||||
let found_node_by_pubkey = if let Some(pubkey) = find_node_by_pubkey {
|
||||
all_peers.iter().any(|x| x.id == pubkey)
|
||||
|
@@ -83,6 +83,7 @@ pub mod unfrozen_gossip_verified_vote_hashes;
|
||||
pub mod validator;
|
||||
pub mod verified_vote_packets;
|
||||
pub mod vote_stake_tracker;
|
||||
pub mod voting_service;
|
||||
pub mod weighted_shuffle;
|
||||
pub mod window_service;
|
||||
|
||||
|
@@ -64,6 +64,8 @@ impl OptimisticallyConfirmedBankTracker {
|
||||
) -> Self {
|
||||
let exit_ = exit.clone();
|
||||
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let thread_hdl = Builder::new()
|
||||
.name("solana-optimistic-bank-tracker".to_string())
|
||||
.spawn(move || loop {
|
||||
@@ -77,6 +79,8 @@ impl OptimisticallyConfirmedBankTracker {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
) {
|
||||
break;
|
||||
}
|
||||
@@ -91,6 +95,8 @@ impl OptimisticallyConfirmedBankTracker {
|
||||
optimistically_confirmed_bank: &Arc<RwLock<OptimisticallyConfirmedBank>>,
|
||||
subscriptions: &Arc<RpcSubscriptions>,
|
||||
mut pending_optimistically_confirmed_banks: &mut HashSet<Slot>,
|
||||
mut last_notified_confirmed_slot: &mut Slot,
|
||||
mut highest_confirmed_slot: &mut Slot,
|
||||
) -> Result<(), RecvTimeoutError> {
|
||||
let notification = receiver.recv_timeout(Duration::from_secs(1))?;
|
||||
Self::process_notification(
|
||||
@@ -99,31 +105,91 @@ impl OptimisticallyConfirmedBankTracker {
|
||||
optimistically_confirmed_bank,
|
||||
subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn notify_or_defer(
|
||||
subscriptions: &Arc<RpcSubscriptions>,
|
||||
bank_forks: &Arc<RwLock<BankForks>>,
|
||||
bank: &Arc<Bank>,
|
||||
last_notified_confirmed_slot: &mut Slot,
|
||||
pending_optimistically_confirmed_banks: &mut HashSet<Slot>,
|
||||
) {
|
||||
if bank.is_frozen() {
|
||||
if bank.slot() > *last_notified_confirmed_slot {
|
||||
debug!(
|
||||
"notify_or_defer notifying via notify_gossip_subscribers for slot {:?}",
|
||||
bank.slot()
|
||||
);
|
||||
subscriptions.notify_gossip_subscribers(bank.slot());
|
||||
*last_notified_confirmed_slot = bank.slot();
|
||||
}
|
||||
} else if bank.slot() > bank_forks.read().unwrap().root_bank().slot() {
|
||||
pending_optimistically_confirmed_banks.insert(bank.slot());
|
||||
debug!("notify_or_defer defer notifying for slot {:?}", bank.slot());
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_or_defer_confirmed_banks(
|
||||
subscriptions: &Arc<RpcSubscriptions>,
|
||||
bank_forks: &Arc<RwLock<BankForks>>,
|
||||
bank: &Arc<Bank>,
|
||||
slot_threshold: Slot,
|
||||
mut last_notified_confirmed_slot: &mut Slot,
|
||||
mut pending_optimistically_confirmed_banks: &mut HashSet<Slot>,
|
||||
) {
|
||||
for confirmed_bank in bank.clone().parents_inclusive().iter().rev() {
|
||||
if confirmed_bank.slot() > slot_threshold {
|
||||
debug!(
|
||||
"Calling notify_or_defer for confirmed_bank {:?}",
|
||||
confirmed_bank.slot()
|
||||
);
|
||||
Self::notify_or_defer(
|
||||
subscriptions,
|
||||
bank_forks,
|
||||
confirmed_bank,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn process_notification(
|
||||
notification: BankNotification,
|
||||
bank_forks: &Arc<RwLock<BankForks>>,
|
||||
optimistically_confirmed_bank: &Arc<RwLock<OptimisticallyConfirmedBank>>,
|
||||
subscriptions: &Arc<RpcSubscriptions>,
|
||||
pending_optimistically_confirmed_banks: &mut HashSet<Slot>,
|
||||
mut pending_optimistically_confirmed_banks: &mut HashSet<Slot>,
|
||||
mut last_notified_confirmed_slot: &mut Slot,
|
||||
highest_confirmed_slot: &mut Slot,
|
||||
) {
|
||||
debug!("received bank notification: {:?}", notification);
|
||||
match notification {
|
||||
BankNotification::OptimisticallyConfirmed(slot) => {
|
||||
if let Some(bank) = bank_forks
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(slot)
|
||||
.filter(|b| b.is_frozen())
|
||||
{
|
||||
if let Some(bank) = bank_forks.read().unwrap().get(slot) {
|
||||
let mut w_optimistically_confirmed_bank =
|
||||
optimistically_confirmed_bank.write().unwrap();
|
||||
if bank.slot() > w_optimistically_confirmed_bank.bank.slot() {
|
||||
|
||||
if bank.slot() > w_optimistically_confirmed_bank.bank.slot() && bank.is_frozen()
|
||||
{
|
||||
w_optimistically_confirmed_bank.bank = bank.clone();
|
||||
subscriptions.notify_gossip_subscribers(slot);
|
||||
}
|
||||
|
||||
if slot > *highest_confirmed_slot {
|
||||
Self::notify_or_defer_confirmed_banks(
|
||||
subscriptions,
|
||||
bank_forks,
|
||||
bank,
|
||||
*highest_confirmed_slot,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
);
|
||||
|
||||
*highest_confirmed_slot = slot;
|
||||
}
|
||||
drop(w_optimistically_confirmed_bank);
|
||||
} else if slot > bank_forks.read().unwrap().root_bank().slot() {
|
||||
@@ -157,11 +223,24 @@ impl OptimisticallyConfirmedBankTracker {
|
||||
}
|
||||
|
||||
if pending_optimistically_confirmed_banks.remove(&bank.slot()) {
|
||||
debug!(
|
||||
"Calling notify_gossip_subscribers to send deferred notification {:?}",
|
||||
frozen_slot
|
||||
);
|
||||
|
||||
Self::notify_or_defer_confirmed_banks(
|
||||
subscriptions,
|
||||
bank_forks,
|
||||
&bank,
|
||||
*last_notified_confirmed_slot,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
);
|
||||
|
||||
let mut w_optimistically_confirmed_bank =
|
||||
optimistically_confirmed_bank.write().unwrap();
|
||||
if frozen_slot > w_optimistically_confirmed_bank.bank.slot() {
|
||||
w_optimistically_confirmed_bank.bank = bank;
|
||||
subscriptions.notify_gossip_subscribers(frozen_slot);
|
||||
}
|
||||
drop(w_optimistically_confirmed_bank);
|
||||
}
|
||||
@@ -227,14 +306,19 @@ mod tests {
|
||||
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 0);
|
||||
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(2),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 2);
|
||||
assert_eq!(highest_confirmed_slot, 2);
|
||||
|
||||
// Test max optimistically confirmed bank remains in the cache
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
@@ -243,8 +327,11 @@ mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 2);
|
||||
assert_eq!(highest_confirmed_slot, 2);
|
||||
|
||||
// Test bank will only be cached when frozen
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
@@ -253,21 +340,30 @@ mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 2);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.len(), 1);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.contains(&3), true);
|
||||
assert!(pending_optimistically_confirmed_banks.contains(&3));
|
||||
assert_eq!(highest_confirmed_slot, 3);
|
||||
|
||||
// Test bank will only be cached when frozen
|
||||
let bank3 = bank_forks.read().unwrap().get(3).unwrap().clone();
|
||||
bank3.freeze();
|
||||
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::Frozen(bank3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 3);
|
||||
assert_eq!(highest_confirmed_slot, 3);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.len(), 0);
|
||||
|
||||
// Test higher root will be cached and clear pending_optimistically_confirmed_banks
|
||||
let bank3 = bank_forks.read().unwrap().get(3).unwrap().clone();
|
||||
@@ -279,10 +375,13 @@ mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 3);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.len(), 1);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.contains(&4), true);
|
||||
assert!(pending_optimistically_confirmed_banks.contains(&4));
|
||||
assert_eq!(highest_confirmed_slot, 4);
|
||||
|
||||
let bank4 = bank_forks.read().unwrap().get(4).unwrap().clone();
|
||||
let bank5 = Bank::new_from_parent(&bank4, &Pubkey::default(), 5);
|
||||
@@ -294,10 +393,13 @@ mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 5);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.len(), 0);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.contains(&4), false);
|
||||
assert!(!pending_optimistically_confirmed_banks.contains(&4));
|
||||
assert_eq!(highest_confirmed_slot, 4);
|
||||
|
||||
// Banks <= root do not get added to pending list, even if not frozen
|
||||
let bank5 = bank_forks.read().unwrap().get(5).unwrap().clone();
|
||||
@@ -316,9 +418,12 @@ mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
assert_eq!(optimistically_confirmed_bank.read().unwrap().bank.slot(), 5);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.len(), 0);
|
||||
assert_eq!(pending_optimistically_confirmed_banks.contains(&6), false);
|
||||
assert!(!pending_optimistically_confirmed_banks.contains(&6));
|
||||
assert_eq!(highest_confirmed_slot, 4);
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,10 @@ use crate::{
|
||||
cluster_slots::ClusterSlots,
|
||||
repair_weight::RepairWeight,
|
||||
result::Result,
|
||||
serve_repair::{RepairType, ServeRepair, DEFAULT_NONCE},
|
||||
serve_repair::{RepairType, ServeRepair, DEFAULT_NONCE, REPAIR_PEERS_CACHE_CAPACITY},
|
||||
};
|
||||
use crossbeam_channel::{Receiver as CrossbeamReceiver, Sender as CrossbeamSender};
|
||||
use lru::LruCache;
|
||||
use solana_ledger::{
|
||||
blockstore::{Blockstore, SlotMeta},
|
||||
shred::Nonce,
|
||||
@@ -181,6 +182,7 @@ impl RepairService {
|
||||
let mut last_stats = Instant::now();
|
||||
let duplicate_slot_repair_statuses: HashMap<Slot, DuplicateSlotRepairStatus> =
|
||||
HashMap::new();
|
||||
let mut peers_cache = LruCache::new(REPAIR_PEERS_CACHE_CAPACITY);
|
||||
|
||||
loop {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
@@ -259,13 +261,12 @@ impl RepairService {
|
||||
)
|
||||
};
|
||||
|
||||
let mut cache = HashMap::new();
|
||||
let mut send_repairs_elapsed = Measure::start("send_repairs_elapsed");
|
||||
repairs.into_iter().for_each(|repair_request| {
|
||||
if let Ok((to, req)) = serve_repair.repair_request(
|
||||
&cluster_slots,
|
||||
repair_request,
|
||||
&mut cache,
|
||||
&mut peers_cache,
|
||||
&mut repair_stats,
|
||||
&repair_info.repair_validators,
|
||||
) {
|
||||
|
@@ -24,6 +24,7 @@ use crate::{
|
||||
rewards_recorder_service::RewardsRecorderSender,
|
||||
rpc_subscriptions::RpcSubscriptions,
|
||||
unfrozen_gossip_verified_vote_hashes::UnfrozenGossipVerifiedVoteHashes,
|
||||
voting_service::VoteOp,
|
||||
window_service::DuplicateSlotReceiver,
|
||||
};
|
||||
use solana_client::rpc_response::SlotUpdate;
|
||||
@@ -305,6 +306,7 @@ impl ReplayStage {
|
||||
replay_vote_sender: ReplayVoteSender,
|
||||
gossip_duplicate_confirmed_slots_receiver: GossipDuplicateConfirmedSlotsReceiver,
|
||||
gossip_verified_vote_hash_receiver: GossipVerifiedVoteHashReceiver,
|
||||
voting_sender: Sender<VoteOp>,
|
||||
) -> Self {
|
||||
let ReplayStageConfig {
|
||||
my_pubkey,
|
||||
@@ -525,7 +527,7 @@ impl ReplayStage {
|
||||
|
||||
if let Some(heaviest_bank_on_same_voted_fork) = heaviest_bank_on_same_voted_fork.as_ref() {
|
||||
if let Some(my_latest_landed_vote) = progress.my_latest_landed_vote(heaviest_bank_on_same_voted_fork.slot()) {
|
||||
Self::refresh_last_vote(&mut tower, &cluster_info, heaviest_bank_on_same_voted_fork, &poh_recorder, my_latest_landed_vote, &vote_account, &authorized_voter_keypairs.read().unwrap(), &mut voted_signatures, has_new_vote_been_rooted, &mut last_vote_refresh_time);
|
||||
Self::refresh_last_vote(&mut tower, &cluster_info, heaviest_bank_on_same_voted_fork, my_latest_landed_vote, &vote_account, &authorized_voter_keypairs.read().unwrap(), &mut voted_signatures, has_new_vote_been_rooted, &mut last_vote_refresh_time, &voting_sender);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,7 +585,6 @@ impl ReplayStage {
|
||||
|
||||
Self::handle_votable_bank(
|
||||
&vote_bank,
|
||||
&poh_recorder,
|
||||
switch_fork_decision,
|
||||
&bank_forks,
|
||||
&mut tower,
|
||||
@@ -606,6 +607,7 @@ impl ReplayStage {
|
||||
&mut voted_signatures,
|
||||
&mut has_new_vote_been_rooted,
|
||||
&mut replay_timing,
|
||||
&voting_sender,
|
||||
);
|
||||
};
|
||||
voting_time.stop();
|
||||
@@ -1337,7 +1339,6 @@ impl ReplayStage {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn handle_votable_bank(
|
||||
bank: &Arc<Bank>,
|
||||
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
||||
switch_fork_decision: &SwitchForkDecision,
|
||||
bank_forks: &Arc<RwLock<BankForks>>,
|
||||
tower: &mut Tower,
|
||||
@@ -1360,6 +1361,7 @@ impl ReplayStage {
|
||||
vote_signatures: &mut Vec<Signature>,
|
||||
has_new_vote_been_rooted: &mut bool,
|
||||
replay_timing: &mut ReplayTiming,
|
||||
voting_sender: &Sender<VoteOp>,
|
||||
) {
|
||||
if bank.is_empty() {
|
||||
inc_new_counter_info!("replay_stage-voted_empty_bank", 1);
|
||||
@@ -1437,7 +1439,6 @@ impl ReplayStage {
|
||||
Self::push_vote(
|
||||
cluster_info,
|
||||
bank,
|
||||
poh_recorder,
|
||||
vote_account_pubkey,
|
||||
authorized_voter_keypairs,
|
||||
tower,
|
||||
@@ -1445,6 +1446,7 @@ impl ReplayStage {
|
||||
vote_signatures,
|
||||
*has_new_vote_been_rooted,
|
||||
replay_timing,
|
||||
voting_sender,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1538,13 +1540,13 @@ impl ReplayStage {
|
||||
tower: &mut Tower,
|
||||
cluster_info: &ClusterInfo,
|
||||
heaviest_bank_on_same_fork: &Bank,
|
||||
poh_recorder: &Mutex<PohRecorder>,
|
||||
my_latest_landed_vote: Slot,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
authorized_voter_keypairs: &[Arc<Keypair>],
|
||||
vote_signatures: &mut Vec<Signature>,
|
||||
has_new_vote_been_rooted: bool,
|
||||
last_vote_refresh_time: &mut LastVoteRefreshTime,
|
||||
voting_sender: &Sender<VoteOp>,
|
||||
) {
|
||||
let last_voted_slot = tower.last_voted_slot();
|
||||
if last_voted_slot.is_none() {
|
||||
@@ -1596,11 +1598,12 @@ impl ReplayStage {
|
||||
("target_bank_slot", heaviest_bank_on_same_fork.slot(), i64),
|
||||
("target_bank_hash", hash_string, String),
|
||||
);
|
||||
let _ = cluster_info.send_vote(
|
||||
&vote_tx,
|
||||
crate::banking_stage::next_leader_tpu(cluster_info, poh_recorder),
|
||||
);
|
||||
cluster_info.refresh_vote(vote_tx, last_voted_slot);
|
||||
voting_sender
|
||||
.send(VoteOp::RefreshVote {
|
||||
tx: vote_tx,
|
||||
last_voted_slot,
|
||||
})
|
||||
.unwrap_or_else(|err| warn!("Error: {:?}", err));
|
||||
last_vote_refresh_time.last_refresh_time = Instant::now();
|
||||
}
|
||||
}
|
||||
@@ -1609,7 +1612,6 @@ impl ReplayStage {
|
||||
fn push_vote(
|
||||
cluster_info: &ClusterInfo,
|
||||
bank: &Bank,
|
||||
poh_recorder: &Mutex<PohRecorder>,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
authorized_voter_keypairs: &[Arc<Keypair>],
|
||||
tower: &mut Tower,
|
||||
@@ -1617,6 +1619,7 @@ impl ReplayStage {
|
||||
vote_signatures: &mut Vec<Signature>,
|
||||
has_new_vote_been_rooted: bool,
|
||||
replay_timing: &mut ReplayTiming,
|
||||
voting_sender: &Sender<VoteOp>,
|
||||
) {
|
||||
let mut generate_time = Measure::start("generate_vote");
|
||||
let vote_tx = Self::generate_vote_tx(
|
||||
@@ -1633,16 +1636,14 @@ impl ReplayStage {
|
||||
replay_timing.generate_vote_us += generate_time.as_us();
|
||||
if let Some(vote_tx) = vote_tx {
|
||||
tower.refresh_last_vote_tx_blockhash(vote_tx.message.recent_blockhash);
|
||||
let mut send_time = Measure::start("send_vote");
|
||||
let _ = cluster_info.send_vote(
|
||||
&vote_tx,
|
||||
crate::banking_stage::next_leader_tpu(cluster_info, poh_recorder),
|
||||
);
|
||||
send_time.stop();
|
||||
let mut push_time = Measure::start("push_vote");
|
||||
cluster_info.push_vote(&tower.tower_slots(), vote_tx);
|
||||
push_time.stop();
|
||||
replay_timing.vote_push_us += push_time.as_us();
|
||||
|
||||
let tower_slots = tower.tower_slots();
|
||||
voting_sender
|
||||
.send(VoteOp::PushVote {
|
||||
tx: vote_tx,
|
||||
tower_slots,
|
||||
})
|
||||
.unwrap_or_else(|err| warn!("Error: {:?}", err));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2594,6 +2595,7 @@ pub(crate) mod tests {
|
||||
vote_state::{VoteState, VoteStateVersions},
|
||||
vote_transaction,
|
||||
};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{
|
||||
fs::remove_dir_all,
|
||||
iter,
|
||||
@@ -4845,6 +4847,7 @@ pub(crate) mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
let (voting_sender, voting_receiver) = channel();
|
||||
|
||||
// Simulate landing a vote for slot 0 landing in slot 1
|
||||
let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1));
|
||||
@@ -4853,7 +4856,6 @@ pub(crate) mod tests {
|
||||
ReplayStage::push_vote(
|
||||
&cluster_info,
|
||||
&bank0,
|
||||
&poh_recorder,
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut tower,
|
||||
@@ -4861,7 +4863,13 @@ pub(crate) mod tests {
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut ReplayTiming::default(),
|
||||
&voting_sender,
|
||||
);
|
||||
let vote_info = voting_receiver
|
||||
.recv_timeout(Duration::from_secs(1))
|
||||
.unwrap();
|
||||
crate::voting_service::VotingService::handle_vote(&cluster_info, &poh_recorder, vote_info);
|
||||
|
||||
let mut cursor = Cursor::default();
|
||||
let (_, votes) = cluster_info.get_votes(&mut cursor);
|
||||
assert_eq!(votes.len(), 1);
|
||||
@@ -4882,13 +4890,13 @@ pub(crate) mod tests {
|
||||
&mut tower,
|
||||
&cluster_info,
|
||||
refresh_bank,
|
||||
&poh_recorder,
|
||||
Tower::last_voted_slot_in_bank(&refresh_bank, &my_vote_pubkey).unwrap(),
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut last_vote_refresh_time,
|
||||
&voting_sender,
|
||||
);
|
||||
|
||||
// No new votes have been submitted to gossip
|
||||
@@ -4905,7 +4913,6 @@ pub(crate) mod tests {
|
||||
ReplayStage::push_vote(
|
||||
&cluster_info,
|
||||
&bank1,
|
||||
&poh_recorder,
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut tower,
|
||||
@@ -4913,7 +4920,12 @@ pub(crate) mod tests {
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut ReplayTiming::default(),
|
||||
&voting_sender,
|
||||
);
|
||||
let vote_info = voting_receiver
|
||||
.recv_timeout(Duration::from_secs(1))
|
||||
.unwrap();
|
||||
crate::voting_service::VotingService::handle_vote(&cluster_info, &poh_recorder, vote_info);
|
||||
let (_, votes) = cluster_info.get_votes(&mut cursor);
|
||||
assert_eq!(votes.len(), 1);
|
||||
let vote_tx = &votes[0];
|
||||
@@ -4927,14 +4939,15 @@ pub(crate) mod tests {
|
||||
&mut tower,
|
||||
&cluster_info,
|
||||
&bank2,
|
||||
&poh_recorder,
|
||||
Tower::last_voted_slot_in_bank(&bank2, &my_vote_pubkey).unwrap(),
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut last_vote_refresh_time,
|
||||
&voting_sender,
|
||||
);
|
||||
|
||||
// No new votes have been submitted to gossip
|
||||
let (_, votes) = cluster_info.get_votes(&mut cursor);
|
||||
assert!(votes.is_empty());
|
||||
@@ -4963,14 +4976,19 @@ pub(crate) mod tests {
|
||||
&mut tower,
|
||||
&cluster_info,
|
||||
&expired_bank,
|
||||
&poh_recorder,
|
||||
Tower::last_voted_slot_in_bank(&expired_bank, &my_vote_pubkey).unwrap(),
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut last_vote_refresh_time,
|
||||
&voting_sender,
|
||||
);
|
||||
let vote_info = voting_receiver
|
||||
.recv_timeout(Duration::from_secs(1))
|
||||
.unwrap();
|
||||
crate::voting_service::VotingService::handle_vote(&cluster_info, &poh_recorder, vote_info);
|
||||
|
||||
assert!(last_vote_refresh_time.last_refresh_time > clone_refresh_time);
|
||||
let (_, votes) = cluster_info.get_votes(&mut cursor);
|
||||
assert_eq!(votes.len(), 1);
|
||||
@@ -5019,14 +5037,15 @@ pub(crate) mod tests {
|
||||
&mut tower,
|
||||
&cluster_info,
|
||||
&expired_bank_sibling,
|
||||
&poh_recorder,
|
||||
Tower::last_voted_slot_in_bank(&expired_bank_sibling, &my_vote_pubkey).unwrap(),
|
||||
&my_vote_pubkey,
|
||||
&my_vote_keypair,
|
||||
&mut voted_signatures,
|
||||
has_new_vote_been_rooted,
|
||||
&mut last_vote_refresh_time,
|
||||
&voting_sender,
|
||||
);
|
||||
|
||||
let (_, votes) = cluster_info.get_votes(&mut cursor);
|
||||
assert!(votes.is_empty());
|
||||
assert_eq!(
|
||||
|
286
core/src/rpc.rs
286
core/src/rpc.rs
@@ -11,7 +11,7 @@ use crate::{
|
||||
validator::ValidatorExit,
|
||||
};
|
||||
use bincode::{config::Options, serialize};
|
||||
use jsonrpc_core::{types::error, Error, Metadata, Result};
|
||||
use jsonrpc_core::{futures::future, types::error, BoxFuture, Error, Metadata, Result};
|
||||
use jsonrpc_derive::rpc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_account_decoder::{
|
||||
@@ -91,7 +91,6 @@ use std::{
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
pub const MAX_REQUEST_PAYLOAD_SIZE: usize = 50 * (1 << 10); // 50kB
|
||||
pub const PERFORMANCE_SAMPLES_LIMIT: usize = 720;
|
||||
@@ -154,7 +153,6 @@ pub struct JsonRpcRequestProcessor {
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
genesis_hash: Hash,
|
||||
transaction_sender: Arc<Mutex<Sender<TransactionInfo>>>,
|
||||
runtime: Arc<Runtime>,
|
||||
bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
|
||||
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
||||
largest_accounts_cache: Arc<RwLock<LargestAccountsCache>>,
|
||||
@@ -240,7 +238,6 @@ impl JsonRpcRequestProcessor {
|
||||
health: Arc<RpcHealth>,
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
genesis_hash: Hash,
|
||||
runtime: Arc<Runtime>,
|
||||
bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
|
||||
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
||||
largest_accounts_cache: Arc<RwLock<LargestAccountsCache>>,
|
||||
@@ -261,7 +258,6 @@ impl JsonRpcRequestProcessor {
|
||||
cluster_info,
|
||||
genesis_hash,
|
||||
transaction_sender: Arc::new(Mutex::new(sender)),
|
||||
runtime,
|
||||
bigtable_ledger_storage,
|
||||
optimistically_confirmed_bank,
|
||||
largest_accounts_cache,
|
||||
@@ -302,7 +298,6 @@ impl JsonRpcRequestProcessor {
|
||||
cluster_info,
|
||||
genesis_hash,
|
||||
transaction_sender: Arc::new(Mutex::new(sender)),
|
||||
runtime: Arc::new(Runtime::new().expect("Runtime")),
|
||||
bigtable_ledger_storage: None,
|
||||
optimistically_confirmed_bank: Arc::new(RwLock::new(OptimisticallyConfirmedBank {
|
||||
bank: bank.clone(),
|
||||
@@ -402,14 +397,14 @@ impl JsonRpcRequestProcessor {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_inflation_reward(
|
||||
pub async fn get_inflation_reward(
|
||||
&self,
|
||||
addresses: Vec<Pubkey>,
|
||||
config: Option<RpcEpochConfig>,
|
||||
) -> Result<Vec<Option<RpcInflationReward>>> {
|
||||
let config = config.unwrap_or_default();
|
||||
let epoch_schedule = self.get_epoch_schedule();
|
||||
let first_available_block = self.get_first_available_block();
|
||||
let first_available_block = self.get_first_available_block().await;
|
||||
let epoch = config.epoch.unwrap_or_else(|| {
|
||||
epoch_schedule
|
||||
.get_epoch(self.get_slot(config.commitment))
|
||||
@@ -434,7 +429,8 @@ impl JsonRpcRequestProcessor {
|
||||
}
|
||||
|
||||
let first_confirmed_block_in_epoch = *self
|
||||
.get_confirmed_blocks_with_limit(first_slot_in_epoch, 1, config.commitment)?
|
||||
.get_confirmed_blocks_with_limit(first_slot_in_epoch, 1, config.commitment)
|
||||
.await?
|
||||
.get(0)
|
||||
.ok_or(RpcCustomError::BlockNotAvailable {
|
||||
slot: first_slot_in_epoch,
|
||||
@@ -444,7 +440,9 @@ impl JsonRpcRequestProcessor {
|
||||
.get_confirmed_block(
|
||||
first_confirmed_block_in_epoch,
|
||||
Some(RpcConfirmedBlockConfig::rewards_with_commitment(config.commitment).into()),
|
||||
) {
|
||||
)
|
||||
.await
|
||||
{
|
||||
first_confirmed_block
|
||||
} else {
|
||||
return Err(RpcCustomError::BlockNotAvailable {
|
||||
@@ -914,7 +912,7 @@ impl JsonRpcRequestProcessor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_confirmed_block(
|
||||
pub async fn get_confirmed_block(
|
||||
&self,
|
||||
slot: Slot,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedBlockConfig>>,
|
||||
@@ -941,9 +939,8 @@ impl JsonRpcRequestProcessor {
|
||||
self.check_blockstore_root(&result, slot)?;
|
||||
if result.is_err() {
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
let bigtable_result = self
|
||||
.runtime
|
||||
.block_on(bigtable_ledger_storage.get_confirmed_block(slot));
|
||||
let bigtable_result =
|
||||
bigtable_ledger_storage.get_confirmed_block(slot).await;
|
||||
self.check_bigtable_result(&bigtable_result)?;
|
||||
return Ok(bigtable_result.ok().map(|confirmed_block| {
|
||||
confirmed_block.configure(encoding, transaction_details, show_rewards)
|
||||
@@ -989,7 +986,7 @@ impl JsonRpcRequestProcessor {
|
||||
Err(RpcCustomError::BlockNotAvailable { slot }.into())
|
||||
}
|
||||
|
||||
pub fn get_confirmed_blocks(
|
||||
pub async fn get_confirmed_blocks(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
end_slot: Option<Slot>,
|
||||
@@ -1028,12 +1025,9 @@ impl JsonRpcRequestProcessor {
|
||||
// [start_slot..end_slot] can be fetched from BigTable. This range should not ever run
|
||||
// into unfinalized confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
return self
|
||||
.runtime
|
||||
.block_on(
|
||||
bigtable_ledger_storage
|
||||
.get_confirmed_blocks(start_slot, (end_slot - start_slot) as usize + 1), // increment limit by 1 to ensure returned range is inclusive of both start_slot and end_slot
|
||||
)
|
||||
return bigtable_ledger_storage
|
||||
.get_confirmed_blocks(start_slot, (end_slot - start_slot) as usize + 1) // increment limit by 1 to ensure returned range is inclusive of both start_slot and end_slot
|
||||
.await
|
||||
.map(|mut bigtable_blocks| {
|
||||
bigtable_blocks.retain(|&slot| slot <= end_slot);
|
||||
bigtable_blocks
|
||||
@@ -1054,7 +1048,10 @@ impl JsonRpcRequestProcessor {
|
||||
.map_err(|_| Error::internal_error())?
|
||||
.filter(|&slot| slot <= end_slot && slot <= highest_confirmed_root)
|
||||
.collect();
|
||||
let last_element = blocks.last().cloned().unwrap_or_default();
|
||||
let last_element = blocks
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| start_slot.saturating_sub(1));
|
||||
|
||||
// Maybe add confirmed blocks
|
||||
if commitment.is_confirmed() && last_element < end_slot {
|
||||
@@ -1070,7 +1067,7 @@ impl JsonRpcRequestProcessor {
|
||||
Ok(blocks)
|
||||
}
|
||||
|
||||
pub fn get_confirmed_blocks_with_limit(
|
||||
pub async fn get_confirmed_blocks_with_limit(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
limit: usize,
|
||||
@@ -1093,9 +1090,9 @@ impl JsonRpcRequestProcessor {
|
||||
// range can be fetched from BigTable. This range should not ever run into unfinalized
|
||||
// confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
return Ok(self
|
||||
.runtime
|
||||
.block_on(bigtable_ledger_storage.get_confirmed_blocks(start_slot, limit))
|
||||
return Ok(bigtable_ledger_storage
|
||||
.get_confirmed_blocks(start_slot, limit)
|
||||
.await
|
||||
.unwrap_or_default());
|
||||
}
|
||||
}
|
||||
@@ -1134,7 +1131,7 @@ impl JsonRpcRequestProcessor {
|
||||
Ok(blocks)
|
||||
}
|
||||
|
||||
pub fn get_block_time(&self, slot: Slot) -> Result<Option<UnixTimestamp>> {
|
||||
pub async fn get_block_time(&self, slot: Slot) -> Result<Option<UnixTimestamp>> {
|
||||
if slot
|
||||
<= self
|
||||
.block_commitment_cache
|
||||
@@ -1146,9 +1143,7 @@ impl JsonRpcRequestProcessor {
|
||||
self.check_blockstore_root(&result, slot)?;
|
||||
if result.is_err() || matches!(result, Ok(None)) {
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
let bigtable_result = self
|
||||
.runtime
|
||||
.block_on(bigtable_ledger_storage.get_confirmed_block(slot));
|
||||
let bigtable_result = bigtable_ledger_storage.get_confirmed_block(slot).await;
|
||||
self.check_bigtable_result(&bigtable_result)?;
|
||||
return Ok(bigtable_result
|
||||
.ok()
|
||||
@@ -1193,7 +1188,7 @@ impl JsonRpcRequestProcessor {
|
||||
Some(status)
|
||||
}
|
||||
|
||||
pub fn get_signature_statuses(
|
||||
pub async fn get_signature_statuses(
|
||||
&self,
|
||||
signatures: Vec<Signature>,
|
||||
config: Option<RpcSignatureStatusConfig>,
|
||||
@@ -1213,7 +1208,8 @@ impl JsonRpcRequestProcessor {
|
||||
let status = if let Some(status) = self.get_transaction_status(signature, &bank) {
|
||||
Some(status)
|
||||
} else if self.config.enable_rpc_transaction_history && search_transaction_history {
|
||||
self.blockstore
|
||||
if let Some(status) = self
|
||||
.blockstore
|
||||
.get_rooted_transaction_status(signature)
|
||||
.map_err(|_| Error::internal_error())?
|
||||
.filter(|(slot, _status_meta)| {
|
||||
@@ -1233,16 +1229,17 @@ impl JsonRpcRequestProcessor {
|
||||
confirmation_status: Some(TransactionConfirmationStatus::Finalized),
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
self.runtime
|
||||
.block_on(bigtable_ledger_storage.get_signature_status(&signature))
|
||||
.map(Some)
|
||||
.unwrap_or(None)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
Some(status)
|
||||
} else if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
bigtable_ledger_storage
|
||||
.get_signature_status(&signature)
|
||||
.await
|
||||
.map(Some)
|
||||
.unwrap_or(None)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -1288,7 +1285,7 @@ impl JsonRpcRequestProcessor {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_confirmed_transaction(
|
||||
pub async fn get_confirmed_transaction(
|
||||
&self,
|
||||
signature: Signature,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
|
||||
@@ -1336,9 +1333,9 @@ impl JsonRpcRequestProcessor {
|
||||
}
|
||||
None => {
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
return Ok(self
|
||||
.runtime
|
||||
.block_on(bigtable_ledger_storage.get_confirmed_transaction(&signature))
|
||||
return Ok(bigtable_ledger_storage
|
||||
.get_confirmed_transaction(&signature)
|
||||
.await
|
||||
.unwrap_or(None)
|
||||
.map(|confirmed| confirmed.encode(encoding)));
|
||||
}
|
||||
@@ -1374,7 +1371,7 @@ impl JsonRpcRequestProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_confirmed_signatures_for_address2(
|
||||
pub async fn get_confirmed_signatures_for_address2(
|
||||
&self,
|
||||
address: Pubkey,
|
||||
mut before: Option<Signature>,
|
||||
@@ -1410,14 +1407,14 @@ impl JsonRpcRequestProcessor {
|
||||
before = results.last().map(|x| x.signature);
|
||||
}
|
||||
|
||||
let bigtable_results = self.runtime.block_on(
|
||||
bigtable_ledger_storage.get_confirmed_signatures_for_address(
|
||||
let bigtable_results = bigtable_ledger_storage
|
||||
.get_confirmed_signatures_for_address(
|
||||
&address,
|
||||
before.as_ref(),
|
||||
until.as_ref(),
|
||||
limit,
|
||||
),
|
||||
);
|
||||
)
|
||||
.await;
|
||||
match bigtable_results {
|
||||
Ok(bigtable_results) => {
|
||||
results.extend(bigtable_results.into_iter().map(|x| x.0));
|
||||
@@ -1452,16 +1449,16 @@ impl JsonRpcRequestProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_first_available_block(&self) -> Slot {
|
||||
pub async fn get_first_available_block(&self) -> Slot {
|
||||
let slot = self
|
||||
.blockstore
|
||||
.get_first_available_block()
|
||||
.unwrap_or_default();
|
||||
|
||||
if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
|
||||
let bigtable_slot = self
|
||||
.runtime
|
||||
.block_on(bigtable_ledger_storage.get_first_available_block())
|
||||
let bigtable_slot = bigtable_ledger_storage
|
||||
.get_first_available_block()
|
||||
.await
|
||||
.unwrap_or(None)
|
||||
.unwrap_or(slot);
|
||||
|
||||
@@ -1932,6 +1929,28 @@ fn verify_token_account_filter(
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_and_parse_signatures_for_address_params(
|
||||
address: String,
|
||||
before: Option<String>,
|
||||
until: Option<String>,
|
||||
limit: Option<usize>,
|
||||
) -> Result<(Pubkey, Option<Signature>, Option<Signature>, usize)> {
|
||||
let address = verify_pubkey(&address)?;
|
||||
let before = before
|
||||
.map(|ref before| verify_signature(before))
|
||||
.transpose()?;
|
||||
let until = until.map(|ref until| verify_signature(until)).transpose()?;
|
||||
let limit = limit.unwrap_or(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT);
|
||||
|
||||
if limit == 0 || limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
|
||||
return Err(Error::invalid_params(format!(
|
||||
"Invalid limit; max {}",
|
||||
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT
|
||||
)));
|
||||
}
|
||||
Ok((address, before, until, limit))
|
||||
}
|
||||
|
||||
fn check_is_at_least_confirmed(commitment: CommitmentConfig) -> Result<()> {
|
||||
if !commitment.is_at_least_confirmed() {
|
||||
return Err(Error::invalid_params(
|
||||
@@ -2160,6 +2179,7 @@ fn _send_transaction(
|
||||
wire_transaction: Vec<u8>,
|
||||
last_valid_slot: Slot,
|
||||
durable_nonce_info: Option<(Pubkey, Hash)>,
|
||||
max_retries: Option<usize>,
|
||||
) -> Result<String> {
|
||||
if transaction.signatures.is_empty() {
|
||||
return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
|
||||
@@ -2170,6 +2190,7 @@ fn _send_transaction(
|
||||
wire_transaction,
|
||||
last_valid_slot,
|
||||
durable_nonce_info,
|
||||
max_retries,
|
||||
);
|
||||
meta.transaction_sender
|
||||
.lock()
|
||||
@@ -2470,7 +2491,7 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
address_strs: Vec<String>,
|
||||
config: Option<RpcEpochConfig>,
|
||||
) -> Result<Vec<Option<RpcInflationReward>>>;
|
||||
) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>>;
|
||||
|
||||
#[rpc(meta, name = "getInflationGovernor")]
|
||||
fn get_inflation_governor(
|
||||
@@ -2539,7 +2560,7 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
signature_strs: Vec<String>,
|
||||
config: Option<RpcSignatureStatusConfig>,
|
||||
) -> Result<RpcResponse<Vec<Option<TransactionStatus>>>>;
|
||||
) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>>;
|
||||
|
||||
#[rpc(meta, name = "getMaxRetransmitSlot")]
|
||||
fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot>;
|
||||
@@ -2618,11 +2639,14 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
slot: Slot,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedBlockConfig>>,
|
||||
) -> Result<Option<UiConfirmedBlock>>;
|
||||
) -> BoxFuture<Result<Option<UiConfirmedBlock>>>;
|
||||
|
||||
#[rpc(meta, name = "getBlockTime")]
|
||||
fn get_block_time(&self, meta: Self::Metadata, slot: Slot)
|
||||
-> Result<Option<UnixTimestamp>>;
|
||||
fn get_block_time(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
slot: Slot,
|
||||
) -> BoxFuture<Result<Option<UnixTimestamp>>>;
|
||||
|
||||
#[rpc(meta, name = "getConfirmedBlocks")]
|
||||
fn get_confirmed_blocks(
|
||||
@@ -2631,7 +2655,7 @@ pub mod rpc_full {
|
||||
start_slot: Slot,
|
||||
config: Option<RpcConfirmedBlocksConfigWrapper>,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<Slot>>;
|
||||
) -> BoxFuture<Result<Vec<Slot>>>;
|
||||
|
||||
#[rpc(meta, name = "getConfirmedBlocksWithLimit")]
|
||||
fn get_confirmed_blocks_with_limit(
|
||||
@@ -2640,7 +2664,7 @@ pub mod rpc_full {
|
||||
start_slot: Slot,
|
||||
limit: usize,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<Slot>>;
|
||||
) -> BoxFuture<Result<Vec<Slot>>>;
|
||||
|
||||
#[rpc(meta, name = "getConfirmedTransaction")]
|
||||
fn get_confirmed_transaction(
|
||||
@@ -2648,7 +2672,7 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
signature_str: String,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
|
||||
) -> Result<Option<EncodedConfirmedTransaction>>;
|
||||
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>>;
|
||||
|
||||
// DEPRECATED
|
||||
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
||||
@@ -2666,10 +2690,10 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
address: String,
|
||||
config: Option<RpcGetConfirmedSignaturesForAddress2Config>,
|
||||
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>>;
|
||||
) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>>;
|
||||
|
||||
#[rpc(meta, name = "getFirstAvailableBlock")]
|
||||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot>;
|
||||
fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>>;
|
||||
|
||||
#[rpc(meta, name = "getStakeActivation")]
|
||||
fn get_stake_activation(
|
||||
@@ -3013,22 +3037,27 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
signature_strs: Vec<String>,
|
||||
config: Option<RpcSignatureStatusConfig>,
|
||||
) -> Result<RpcResponse<Vec<Option<TransactionStatus>>>> {
|
||||
) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>> {
|
||||
debug!(
|
||||
"get_signature_statuses rpc request received: {:?}",
|
||||
signature_strs.len()
|
||||
);
|
||||
if signature_strs.len() > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS {
|
||||
return Err(Error::invalid_params(format!(
|
||||
return Box::pin(future::err(Error::invalid_params(format!(
|
||||
"Too many inputs provided; max {}",
|
||||
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS
|
||||
)));
|
||||
))));
|
||||
}
|
||||
let mut signatures: Vec<Signature> = vec![];
|
||||
for signature_str in signature_strs {
|
||||
signatures.push(verify_signature(&signature_str)?);
|
||||
match verify_signature(&signature_str) {
|
||||
Ok(signature) => {
|
||||
signatures.push(signature);
|
||||
}
|
||||
Err(err) => return Box::pin(future::err(err)),
|
||||
}
|
||||
}
|
||||
meta.get_signature_statuses(signatures, config)
|
||||
Box::pin(async move { meta.get_signature_statuses(signatures, config).await })
|
||||
}
|
||||
|
||||
fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot> {
|
||||
@@ -3109,7 +3138,14 @@ pub mod rpc_full {
|
||||
Error::internal_error()
|
||||
})?;
|
||||
|
||||
_send_transaction(meta, transaction, wire_transaction, last_valid_slot, None)
|
||||
_send_transaction(
|
||||
meta,
|
||||
transaction,
|
||||
wire_transaction,
|
||||
last_valid_slot,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn send_transaction(
|
||||
@@ -3201,6 +3237,7 @@ pub mod rpc_full {
|
||||
wire_transaction,
|
||||
last_valid_slot,
|
||||
durable_nonce_info,
|
||||
config.max_retries,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3330,9 +3367,9 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
slot: Slot,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedBlockConfig>>,
|
||||
) -> Result<Option<UiConfirmedBlock>> {
|
||||
) -> BoxFuture<Result<Option<UiConfirmedBlock>>> {
|
||||
debug!("get_confirmed_block rpc request received: {:?}", slot);
|
||||
meta.get_confirmed_block(slot, config)
|
||||
Box::pin(async move { meta.get_confirmed_block(slot, config).await })
|
||||
}
|
||||
|
||||
fn get_confirmed_blocks(
|
||||
@@ -3341,14 +3378,17 @@ pub mod rpc_full {
|
||||
start_slot: Slot,
|
||||
config: Option<RpcConfirmedBlocksConfigWrapper>,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<Slot>> {
|
||||
) -> BoxFuture<Result<Vec<Slot>>> {
|
||||
let (end_slot, maybe_commitment) =
|
||||
config.map(|config| config.unzip()).unwrap_or_default();
|
||||
debug!(
|
||||
"get_confirmed_blocks rpc request received: {}-{:?}",
|
||||
start_slot, end_slot
|
||||
);
|
||||
meta.get_confirmed_blocks(start_slot, end_slot, commitment.or(maybe_commitment))
|
||||
Box::pin(async move {
|
||||
meta.get_confirmed_blocks(start_slot, end_slot, commitment.or(maybe_commitment))
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
fn get_confirmed_blocks_with_limit(
|
||||
@@ -3357,20 +3397,23 @@ pub mod rpc_full {
|
||||
start_slot: Slot,
|
||||
limit: usize,
|
||||
commitment: Option<CommitmentConfig>,
|
||||
) -> Result<Vec<Slot>> {
|
||||
) -> BoxFuture<Result<Vec<Slot>>> {
|
||||
debug!(
|
||||
"get_confirmed_blocks_with_limit rpc request received: {}-{}",
|
||||
start_slot, limit,
|
||||
);
|
||||
meta.get_confirmed_blocks_with_limit(start_slot, limit, commitment)
|
||||
Box::pin(async move {
|
||||
meta.get_confirmed_blocks_with_limit(start_slot, limit, commitment)
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
fn get_block_time(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
slot: Slot,
|
||||
) -> Result<Option<UnixTimestamp>> {
|
||||
meta.get_block_time(slot)
|
||||
) -> BoxFuture<Result<Option<UnixTimestamp>>> {
|
||||
Box::pin(async move { meta.get_block_time(slot).await })
|
||||
}
|
||||
|
||||
fn get_confirmed_transaction(
|
||||
@@ -3378,13 +3421,19 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
signature_str: String,
|
||||
config: Option<RpcEncodingConfigWrapper<RpcConfirmedTransactionConfig>>,
|
||||
) -> Result<Option<EncodedConfirmedTransaction>> {
|
||||
) -> BoxFuture<Result<Option<EncodedConfirmedTransaction>>> {
|
||||
debug!(
|
||||
"get_confirmed_transaction rpc request received: {:?}",
|
||||
signature_str
|
||||
);
|
||||
let signature = verify_signature(&signature_str)?;
|
||||
meta.get_confirmed_transaction(signature, config)
|
||||
let signature = verify_signature(&signature_str);
|
||||
if let Err(err) = signature {
|
||||
return Box::pin(future::err(err));
|
||||
}
|
||||
Box::pin(async move {
|
||||
meta.get_confirmed_transaction(signature.unwrap(), config)
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
fn get_confirmed_signatures_for_address(
|
||||
@@ -3423,41 +3472,29 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
address: String,
|
||||
config: Option<RpcGetConfirmedSignaturesForAddress2Config>,
|
||||
) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
|
||||
let address = verify_pubkey(&address)?;
|
||||
|
||||
) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>> {
|
||||
let config = config.unwrap_or_default();
|
||||
let before = config
|
||||
.before
|
||||
.map(|ref before| verify_signature(before))
|
||||
.transpose()?;
|
||||
let until = config
|
||||
.until
|
||||
.map(|ref until| verify_signature(until))
|
||||
.transpose()?;
|
||||
let limit = config
|
||||
.limit
|
||||
.unwrap_or(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT);
|
||||
|
||||
if limit == 0 || limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
|
||||
return Err(Error::invalid_params(format!(
|
||||
"Invalid limit; max {}",
|
||||
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT
|
||||
)));
|
||||
}
|
||||
|
||||
meta.get_confirmed_signatures_for_address2(
|
||||
let commitment = config.commitment;
|
||||
let verification = verify_and_parse_signatures_for_address_params(
|
||||
address,
|
||||
before,
|
||||
until,
|
||||
limit,
|
||||
config.commitment,
|
||||
)
|
||||
config.before,
|
||||
config.until,
|
||||
config.limit,
|
||||
);
|
||||
match verification {
|
||||
Err(err) => Box::pin(future::err(err)),
|
||||
Ok((address, before, until, limit)) => Box::pin(async move {
|
||||
meta.get_confirmed_signatures_for_address2(
|
||||
address, before, until, limit, commitment,
|
||||
)
|
||||
.await
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {
|
||||
fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>> {
|
||||
debug!("get_first_available_block rpc request received");
|
||||
Ok(meta.get_first_available_block())
|
||||
Box::pin(async move { Ok(meta.get_first_available_block().await) })
|
||||
}
|
||||
|
||||
fn get_block_production(
|
||||
@@ -3568,7 +3605,7 @@ pub mod rpc_full {
|
||||
meta: Self::Metadata,
|
||||
address_strs: Vec<String>,
|
||||
config: Option<RpcEpochConfig>,
|
||||
) -> Result<Vec<Option<RpcInflationReward>>> {
|
||||
) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>> {
|
||||
debug!(
|
||||
"get_inflation_reward rpc request received: {:?}",
|
||||
address_strs.len()
|
||||
@@ -3576,10 +3613,15 @@ pub mod rpc_full {
|
||||
|
||||
let mut addresses: Vec<Pubkey> = vec![];
|
||||
for address_str in address_strs {
|
||||
addresses.push(verify_pubkey(&address_str)?);
|
||||
match verify_pubkey(&address_str) {
|
||||
Ok(pubkey) => {
|
||||
addresses.push(pubkey);
|
||||
}
|
||||
Err(err) => return Box::pin(future::err(err)),
|
||||
}
|
||||
}
|
||||
|
||||
meta.get_inflation_reward(addresses, config)
|
||||
Box::pin(async move { meta.get_inflation_reward(addresses, config).await })
|
||||
}
|
||||
|
||||
fn get_token_account_balance(
|
||||
@@ -3946,7 +3988,6 @@ pub mod tests {
|
||||
RpcHealth::stub(),
|
||||
cluster_info.clone(),
|
||||
Hash::default(),
|
||||
Arc::new(tokio::runtime::Runtime::new().unwrap()),
|
||||
None,
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
||||
Arc::new(RwLock::new(LargestAccountsCache::new(30))),
|
||||
@@ -5614,7 +5655,6 @@ pub mod tests {
|
||||
health.clone(),
|
||||
cluster_info,
|
||||
Hash::default(),
|
||||
Arc::new(tokio::runtime::Runtime::new().unwrap()),
|
||||
None,
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
||||
Arc::new(RwLock::new(LargestAccountsCache::new(30))),
|
||||
@@ -5891,7 +5931,6 @@ pub mod tests {
|
||||
RpcHealth::stub(),
|
||||
cluster_info,
|
||||
Hash::default(),
|
||||
Arc::new(tokio::runtime::Runtime::new().unwrap()),
|
||||
None,
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
||||
Arc::new(RwLock::new(LargestAccountsCache::new(30))),
|
||||
@@ -7317,7 +7356,6 @@ pub mod tests {
|
||||
RpcHealth::stub(),
|
||||
cluster_info,
|
||||
Hash::default(),
|
||||
Arc::new(tokio::runtime::Runtime::new().unwrap()),
|
||||
None,
|
||||
optimistically_confirmed_bank.clone(),
|
||||
Arc::new(RwLock::new(LargestAccountsCache::new(30))),
|
||||
@@ -7336,6 +7374,8 @@ pub mod tests {
|
||||
let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
|
||||
let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
|
||||
assert_eq!(slot, 0);
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(2),
|
||||
@@ -7343,6 +7383,8 @@ pub mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
let req =
|
||||
r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
|
||||
@@ -7358,6 +7400,8 @@ pub mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
let req =
|
||||
r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
|
||||
@@ -7373,6 +7417,8 @@ pub mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
let req =
|
||||
r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
|
||||
@@ -7389,6 +7435,8 @@ pub mod tests {
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
let req =
|
||||
r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
|
||||
|
@@ -34,7 +34,6 @@ use std::{
|
||||
sync::{mpsc::channel, Arc, Mutex, RwLock},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
};
|
||||
use tokio::runtime;
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
|
||||
const LARGEST_ACCOUNTS_CACHE_DURATION: u64 = 60 * 60 * 2;
|
||||
@@ -112,10 +111,8 @@ impl RpcRequestMiddleware {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn open_no_follow(path: impl AsRef<Path>) -> std::io::Result<tokio_02::fs::File> {
|
||||
// Stuck on tokio 0.2 until the jsonrpc crates upgrade
|
||||
use tokio_02::fs::os::unix::OpenOptionsExt;
|
||||
tokio_02::fs::OpenOptions::new()
|
||||
async fn open_no_follow(path: impl AsRef<Path>) -> std::io::Result<tokio::fs::File> {
|
||||
tokio::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(false)
|
||||
.create(false)
|
||||
@@ -125,10 +122,9 @@ impl RpcRequestMiddleware {
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
async fn open_no_follow(path: impl AsRef<Path>) -> std::io::Result<tokio_02::fs::File> {
|
||||
async fn open_no_follow(path: impl AsRef<Path>) -> std::io::Result<tokio::fs::File> {
|
||||
// TODO: Is there any way to achieve the same on Windows?
|
||||
// Stuck on tokio 0.2 until the jsonrpc crates upgrade
|
||||
tokio_02::fs::File::open(path).await
|
||||
tokio::fs::File::open(path).await
|
||||
}
|
||||
|
||||
fn process_file_get(&self, path: &str) -> RequestMiddlewareAction {
|
||||
@@ -294,9 +290,17 @@ impl JsonRpcService {
|
||||
)));
|
||||
|
||||
let tpu_address = cluster_info.my_contact_info().tpu;
|
||||
|
||||
// sadly, some parts of our current rpc implemention block the jsonrpc's
|
||||
// _socket-listening_ event loop for too long, due to (blocking) long IO or intesive CPU,
|
||||
// causing no further processing of incoming requests and ultimatily innocent clients timing-out.
|
||||
// So create a (shared) multi-threaded event_loop for jsonrpc and set its .threads() to 1,
|
||||
// so that we avoid the single-threaded event loops from being created automatically by
|
||||
// jsonrpc for threads when .threads(N > 1) is given.
|
||||
let runtime = Arc::new(
|
||||
runtime::Builder::new_multi_thread()
|
||||
.thread_name("rpc-runtime")
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(rpc_threads)
|
||||
.thread_name("sol-rpc-el")
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("Runtime"),
|
||||
@@ -351,7 +355,6 @@ impl JsonRpcService {
|
||||
health.clone(),
|
||||
cluster_info.clone(),
|
||||
genesis_hash,
|
||||
runtime,
|
||||
bigtable_ledger_storage,
|
||||
optimistically_confirmed_bank,
|
||||
largest_accounts_cache,
|
||||
@@ -376,23 +379,6 @@ impl JsonRpcService {
|
||||
|
||||
let ledger_path = ledger_path.to_path_buf();
|
||||
|
||||
// sadly, some parts of our current rpc implemention block the jsonrpc's
|
||||
// _socket-listening_ event loop for too long, due to (blocking) long IO or intesive CPU,
|
||||
// causing no further processing of incoming requests and ultimatily innocent clients timing-out.
|
||||
// So create a (shared) multi-threaded event_loop for jsonrpc and set its .threads() to 1,
|
||||
// so that we avoid the single-threaded event loops from being created automatically by
|
||||
// jsonrpc for threads when .threads(N > 1) is given.
|
||||
let event_loop = {
|
||||
// Stuck on tokio 0.2 until the jsonrpc crates upgrade
|
||||
tokio_02::runtime::Builder::new()
|
||||
.core_threads(rpc_threads)
|
||||
.threaded_scheduler()
|
||||
.enable_all()
|
||||
.thread_name("sol-rpc-el")
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let (close_handle_sender, close_handle_receiver) = channel();
|
||||
let thread_hdl = Builder::new()
|
||||
.name("solana-jsonrpc".to_string())
|
||||
@@ -414,7 +400,7 @@ impl JsonRpcService {
|
||||
io,
|
||||
move |_req: &hyper::Request<hyper::Body>| request_processor.clone(),
|
||||
)
|
||||
.event_loop_executor(event_loop.handle().clone())
|
||||
.event_loop_executor(runtime.handle().clone())
|
||||
.threads(1)
|
||||
.cors(DomainsValidation::AllowOnly(vec![
|
||||
AccessControlAllowOrigin::Any,
|
||||
@@ -481,6 +467,7 @@ mod tests {
|
||||
use solana_sdk::{genesis_config::ClusterType, signature::Signer};
|
||||
use std::io::Write;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
#[test]
|
||||
fn test_rpc_new() {
|
||||
@@ -613,7 +600,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_process_file_get() {
|
||||
let mut runtime = tokio_02::runtime::Runtime::new().unwrap();
|
||||
let runtime = Runtime::new().unwrap();
|
||||
|
||||
let ledger_path = get_tmp_ledger_path!();
|
||||
std::fs::create_dir(&ledger_path).unwrap();
|
||||
|
@@ -1343,7 +1343,10 @@ pub(crate) mod tests {
|
||||
system_instruction, system_program, system_transaction,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use std::{fmt::Debug, sync::mpsc::channel};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{atomic::Ordering::Relaxed, mpsc::channel},
|
||||
};
|
||||
use tokio::{
|
||||
runtime::Runtime,
|
||||
time::{sleep, timeout},
|
||||
@@ -1615,6 +1618,454 @@ pub(crate) mod tests {
|
||||
.contains_key(&solana_stake_program::id()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot() {
|
||||
// Testing if we can get the pubsub notification if a slot does not
|
||||
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
||||
// notification.
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(100);
|
||||
let bank = Bank::new(&genesis_config);
|
||||
bank.lazy_rent_collection.store(true, Relaxed);
|
||||
|
||||
let blockhash = bank.last_blockhash();
|
||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||
|
||||
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
||||
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||
bank_forks.write().unwrap().insert(bank1);
|
||||
let bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
|
||||
|
||||
// add account for alice and process the transaction at bank1
|
||||
let alice = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&alice,
|
||||
blockhash,
|
||||
1,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
|
||||
bank1.process_transaction(&tx).unwrap();
|
||||
|
||||
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
||||
bank_forks.write().unwrap().insert(bank2);
|
||||
|
||||
// add account for bob and process the transaction at bank2
|
||||
let bob = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&bob,
|
||||
blockhash,
|
||||
2,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
let bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
||||
|
||||
bank2.process_transaction(&tx).unwrap();
|
||||
|
||||
let bank3 = Bank::new_from_parent(&bank2, &Pubkey::default(), 3);
|
||||
bank_forks.write().unwrap().insert(bank3);
|
||||
|
||||
// add account for joe and process the transaction at bank3
|
||||
let joe = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&joe,
|
||||
blockhash,
|
||||
3,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
let bank3 = bank_forks.read().unwrap().get(3).unwrap().clone();
|
||||
|
||||
bank3.process_transaction(&tx).unwrap();
|
||||
|
||||
// now add programSubscribe at the "confirmed" commitment level
|
||||
let (subscriber, _id_receiver, transport_receiver) =
|
||||
Subscriber::new_test("programNotification");
|
||||
let sub_id = SubscriptionId::Number(0);
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let optimistically_confirmed_bank =
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
||||
|
||||
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||
&exit,
|
||||
bank_forks.clone(),
|
||||
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
||||
1, 1,
|
||||
))),
|
||||
optimistically_confirmed_bank.clone(),
|
||||
));
|
||||
subscriptions.add_program_subscription(
|
||||
solana_stake_program::id(),
|
||||
Some(RpcProgramAccountsConfig {
|
||||
account_config: RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
}),
|
||||
sub_id.clone(),
|
||||
subscriber,
|
||||
);
|
||||
|
||||
assert!(subscriptions
|
||||
.subscriptions
|
||||
.gossip_program_subscriptions
|
||||
.read()
|
||||
.unwrap()
|
||||
.contains_key(&solana_stake_program::id()));
|
||||
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is unfrozen, we expect
|
||||
// to see transaction for alice and bob to be notified in order.
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
// a closure to reduce code duplications in building expected responses:
|
||||
let build_expected_resp = |slot: Slot, lamports: u64, pubkey: &str, subscription: i32| {
|
||||
json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "programNotification",
|
||||
"params": {
|
||||
"result": {
|
||||
"context": { "slot": slot },
|
||||
"value": {
|
||||
"account": {
|
||||
"data": "1111111111111111",
|
||||
"executable": false,
|
||||
"lamports": lamports,
|
||||
"owner": "Stake11111111111111111111111111111111111111",
|
||||
"rentEpoch": 0,
|
||||
},
|
||||
"pubkey": pubkey,
|
||||
},
|
||||
},
|
||||
"subscription": subscription,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let (response, transport_receiver) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(1, 1, &alice.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
|
||||
let (response, transport_receiver) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(2, 2, &bob.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
|
||||
bank3.freeze();
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::Frozen(bank3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
let (response, _) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(3, 3, &joe.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
subscriptions.remove_program_subscription(&sub_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[should_panic]
|
||||
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot_with_no_banks_no_notifications(
|
||||
) {
|
||||
// Testing if we can get the pubsub notification if a slot does not
|
||||
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
||||
// notification with a bank in the BankForks. We are not expecting to receive any notifications -- should panic.
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(100);
|
||||
let bank = Bank::new(&genesis_config);
|
||||
bank.lazy_rent_collection.store(true, Relaxed);
|
||||
|
||||
let blockhash = bank.last_blockhash();
|
||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||
|
||||
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
||||
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||
bank_forks.write().unwrap().insert(bank1);
|
||||
let bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
|
||||
|
||||
// add account for alice and process the transaction at bank1
|
||||
let alice = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&alice,
|
||||
blockhash,
|
||||
1,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
|
||||
bank1.process_transaction(&tx).unwrap();
|
||||
|
||||
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
||||
bank_forks.write().unwrap().insert(bank2);
|
||||
|
||||
// add account for bob and process the transaction at bank2
|
||||
let bob = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&bob,
|
||||
blockhash,
|
||||
2,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
let bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
||||
|
||||
bank2.process_transaction(&tx).unwrap();
|
||||
|
||||
// now add programSubscribe at the "confirmed" commitment level
|
||||
let (subscriber, _id_receiver, transport_receiver) =
|
||||
Subscriber::new_test("programNotification");
|
||||
let sub_id = SubscriptionId::Number(0);
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let optimistically_confirmed_bank =
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
||||
|
||||
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||
&exit,
|
||||
bank_forks.clone(),
|
||||
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
||||
1, 1,
|
||||
))),
|
||||
optimistically_confirmed_bank.clone(),
|
||||
));
|
||||
subscriptions.add_program_subscription(
|
||||
solana_stake_program::id(),
|
||||
Some(RpcProgramAccountsConfig {
|
||||
account_config: RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
}),
|
||||
sub_id,
|
||||
subscriber,
|
||||
);
|
||||
|
||||
assert!(subscriptions
|
||||
.subscriptions
|
||||
.gossip_program_subscriptions
|
||||
.read()
|
||||
.unwrap()
|
||||
.contains_key(&solana_stake_program::id()));
|
||||
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is not in the bankforks, we do not
|
||||
// expect to see any RPC notifications.
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
// The following should panic
|
||||
let (_response, _transport_receiver) = robust_poll_or_panic(transport_receiver);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot_with_no_banks() {
|
||||
// Testing if we can get the pubsub notification if a slot does not
|
||||
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
||||
// notification. It differs from the test_check_program_subscribe_for_missing_optimistically_confirmed_slot
|
||||
// test in that when the descendant get confirmed, the descendant does not have a bank yet.
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(100);
|
||||
let bank = Bank::new(&genesis_config);
|
||||
bank.lazy_rent_collection.store(true, Relaxed);
|
||||
|
||||
let blockhash = bank.last_blockhash();
|
||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
||||
|
||||
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
||||
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||
bank_forks.write().unwrap().insert(bank1);
|
||||
let bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
|
||||
|
||||
// add account for alice and process the transaction at bank1
|
||||
let alice = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&alice,
|
||||
blockhash,
|
||||
1,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
|
||||
bank1.process_transaction(&tx).unwrap();
|
||||
|
||||
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
||||
bank_forks.write().unwrap().insert(bank2);
|
||||
|
||||
// add account for bob and process the transaction at bank2
|
||||
let bob = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&bob,
|
||||
blockhash,
|
||||
2,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
let bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
||||
|
||||
bank2.process_transaction(&tx).unwrap();
|
||||
|
||||
// now add programSubscribe at the "confirmed" commitment level
|
||||
let (subscriber, _id_receiver, transport_receiver) =
|
||||
Subscriber::new_test("programNotification");
|
||||
let sub_id = SubscriptionId::Number(0);
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let optimistically_confirmed_bank =
|
||||
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
||||
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
||||
|
||||
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||
&exit,
|
||||
bank_forks.clone(),
|
||||
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
||||
1, 1,
|
||||
))),
|
||||
optimistically_confirmed_bank.clone(),
|
||||
));
|
||||
subscriptions.add_program_subscription(
|
||||
solana_stake_program::id(),
|
||||
Some(RpcProgramAccountsConfig {
|
||||
account_config: RpcAccountInfoConfig {
|
||||
commitment: Some(CommitmentConfig::confirmed()),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
..RpcProgramAccountsConfig::default()
|
||||
}),
|
||||
sub_id.clone(),
|
||||
subscriber,
|
||||
);
|
||||
|
||||
assert!(subscriptions
|
||||
.subscriptions
|
||||
.gossip_program_subscriptions
|
||||
.read()
|
||||
.unwrap()
|
||||
.contains_key(&solana_stake_program::id()));
|
||||
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is not in the bankforks, we expect
|
||||
// to see transaction for alice and bob to be notified only when bank3 is added to the fork and
|
||||
// frozen. The notifications should be in the increasing order of the slot.
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
// a closure to reduce code duplications in building expected responses:
|
||||
let build_expected_resp = |slot: Slot, lamports: u64, pubkey: &str, subscription: i32| {
|
||||
json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "programNotification",
|
||||
"params": {
|
||||
"result": {
|
||||
"context": { "slot": slot },
|
||||
"value": {
|
||||
"account": {
|
||||
"data": "1111111111111111",
|
||||
"executable": false,
|
||||
"lamports": lamports,
|
||||
"owner": "Stake11111111111111111111111111111111111111",
|
||||
"rentEpoch": 0,
|
||||
},
|
||||
"pubkey": pubkey,
|
||||
},
|
||||
},
|
||||
"subscription": subscription,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let bank3 = Bank::new_from_parent(&bank2, &Pubkey::default(), 3);
|
||||
bank_forks.write().unwrap().insert(bank3);
|
||||
|
||||
// add account for joe and process the transaction at bank3
|
||||
let joe = Keypair::new();
|
||||
let tx = system_transaction::create_account(
|
||||
&mint_keypair,
|
||||
&joe,
|
||||
blockhash,
|
||||
3,
|
||||
16,
|
||||
&solana_stake_program::id(),
|
||||
);
|
||||
let bank3 = bank_forks.read().unwrap().get(3).unwrap().clone();
|
||||
|
||||
bank3.process_transaction(&tx).unwrap();
|
||||
bank3.freeze();
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::Frozen(bank3),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
let (response, transport_receiver) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(1, 1, &alice.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
|
||||
let (response, transport_receiver) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(2, 2, &bob.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
|
||||
let (response, _) = robust_poll_or_panic(transport_receiver);
|
||||
let expected = build_expected_resp(3, 3, &joe.pubkey().to_string(), 0);
|
||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
||||
subscriptions.remove_program_subscription(&sub_id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_check_signature_subscribe() {
|
||||
@@ -2058,21 +2509,28 @@ pub(crate) mod tests {
|
||||
.unwrap();
|
||||
|
||||
// First, notify the unfrozen bank first to queue pending notification
|
||||
let mut highest_confirmed_slot: Slot = 0;
|
||||
let mut last_notified_confirmed_slot: Slot = 0;
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(2),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
// Now, notify the frozen bank and ensure its notifications are processed
|
||||
highest_confirmed_slot = 0;
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::OptimisticallyConfirmed(1),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
|
||||
let (response, _) = robust_poll_or_panic(transport_receiver0);
|
||||
@@ -2109,12 +2567,16 @@ pub(crate) mod tests {
|
||||
);
|
||||
|
||||
let bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
||||
bank2.freeze();
|
||||
highest_confirmed_slot = 0;
|
||||
OptimisticallyConfirmedBankTracker::process_notification(
|
||||
BankNotification::Frozen(bank2),
|
||||
&bank_forks,
|
||||
&optimistically_confirmed_bank,
|
||||
&subscriptions,
|
||||
&mut pending_optimistically_confirmed_banks,
|
||||
&mut last_notified_confirmed_slot,
|
||||
&mut highest_confirmed_slot,
|
||||
);
|
||||
let (response, _) = robust_poll_or_panic(transport_receiver1);
|
||||
let expected = json!({
|
||||
|
@@ -35,6 +35,8 @@ pub struct TransactionInfo {
|
||||
pub wire_transaction: Vec<u8>,
|
||||
pub last_valid_slot: Slot,
|
||||
pub durable_nonce_info: Option<(Pubkey, Hash)>,
|
||||
pub max_retries: Option<usize>,
|
||||
retries: usize,
|
||||
}
|
||||
|
||||
impl TransactionInfo {
|
||||
@@ -43,12 +45,15 @@ impl TransactionInfo {
|
||||
wire_transaction: Vec<u8>,
|
||||
last_valid_slot: Slot,
|
||||
durable_nonce_info: Option<(Pubkey, Hash)>,
|
||||
max_retries: Option<usize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
signature,
|
||||
wire_transaction,
|
||||
last_valid_slot,
|
||||
durable_nonce_info,
|
||||
max_retries,
|
||||
retries: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,6 +105,7 @@ struct ProcessTransactionsResult {
|
||||
rooted: u64,
|
||||
expired: u64,
|
||||
retried: u64,
|
||||
max_retries_elapsed: u64,
|
||||
failed: u64,
|
||||
retained: u64,
|
||||
}
|
||||
@@ -222,7 +228,7 @@ impl SendTransactionService {
|
||||
) -> ProcessTransactionsResult {
|
||||
let mut result = ProcessTransactionsResult::default();
|
||||
|
||||
transactions.retain(|signature, transaction_info| {
|
||||
transactions.retain(|signature, mut transaction_info| {
|
||||
if transaction_info.durable_nonce_info.is_some() {
|
||||
inc_new_counter_info!("send_transaction_service-nonced", 1);
|
||||
}
|
||||
@@ -249,6 +255,14 @@ impl SendTransactionService {
|
||||
inc_new_counter_info!("send_transaction_service-expired", 1);
|
||||
return false;
|
||||
}
|
||||
if let Some(max_retries) = transaction_info.max_retries {
|
||||
if transaction_info.retries >= max_retries {
|
||||
info!("Dropping transaction due to max retries: {}", signature);
|
||||
result.max_retries_elapsed += 1;
|
||||
inc_new_counter_info!("send_transaction_service-max_retries", 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
match working_bank.get_signature_status_slot(signature) {
|
||||
None => {
|
||||
@@ -256,6 +270,7 @@ impl SendTransactionService {
|
||||
// dropped or landed in another fork. Re-send it
|
||||
info!("Retrying transaction: {}", signature);
|
||||
result.retried += 1;
|
||||
transaction_info.retries += 1;
|
||||
inc_new_counter_info!("send_transaction_service-retry", 1);
|
||||
let addresses = leader_info
|
||||
.as_ref()
|
||||
@@ -387,7 +402,13 @@ mod test {
|
||||
info!("Expired transactions are dropped...");
|
||||
transactions.insert(
|
||||
Signature::default(),
|
||||
TransactionInfo::new(Signature::default(), vec![], root_bank.slot() - 1, None),
|
||||
TransactionInfo::new(
|
||||
Signature::default(),
|
||||
vec![],
|
||||
root_bank.slot() - 1,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
@@ -410,7 +431,7 @@ mod test {
|
||||
info!("Rooted transactions are dropped...");
|
||||
transactions.insert(
|
||||
rooted_signature,
|
||||
TransactionInfo::new(rooted_signature, vec![], working_bank.slot(), None),
|
||||
TransactionInfo::new(rooted_signature, vec![], working_bank.slot(), None, None),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
@@ -433,7 +454,7 @@ mod test {
|
||||
info!("Failed transactions are dropped...");
|
||||
transactions.insert(
|
||||
failed_signature,
|
||||
TransactionInfo::new(failed_signature, vec![], working_bank.slot(), None),
|
||||
TransactionInfo::new(failed_signature, vec![], working_bank.slot(), None, None),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
@@ -456,7 +477,13 @@ mod test {
|
||||
info!("Non-rooted transactions are kept...");
|
||||
transactions.insert(
|
||||
non_rooted_signature,
|
||||
TransactionInfo::new(non_rooted_signature, vec![], working_bank.slot(), None),
|
||||
TransactionInfo::new(
|
||||
non_rooted_signature,
|
||||
vec![],
|
||||
working_bank.slot(),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
@@ -480,7 +507,13 @@ mod test {
|
||||
info!("Unknown transactions are retried...");
|
||||
transactions.insert(
|
||||
Signature::default(),
|
||||
TransactionInfo::new(Signature::default(), vec![], working_bank.slot(), None),
|
||||
TransactionInfo::new(
|
||||
Signature::default(),
|
||||
vec![],
|
||||
working_bank.slot(),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
@@ -499,6 +532,64 @@ mod test {
|
||||
..ProcessTransactionsResult::default()
|
||||
}
|
||||
);
|
||||
transactions.clear();
|
||||
|
||||
info!("Transactions are only retried until max_retries");
|
||||
transactions.insert(
|
||||
Signature::new(&[1; 64]),
|
||||
TransactionInfo::new(
|
||||
Signature::default(),
|
||||
vec![],
|
||||
working_bank.slot(),
|
||||
None,
|
||||
Some(0),
|
||||
),
|
||||
);
|
||||
transactions.insert(
|
||||
Signature::new(&[2; 64]),
|
||||
TransactionInfo::new(
|
||||
Signature::default(),
|
||||
vec![],
|
||||
working_bank.slot(),
|
||||
None,
|
||||
Some(1),
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
&root_bank,
|
||||
&send_socket,
|
||||
&tpu_address,
|
||||
&mut transactions,
|
||||
&None,
|
||||
leader_forward_count,
|
||||
);
|
||||
assert_eq!(transactions.len(), 1);
|
||||
assert_eq!(
|
||||
result,
|
||||
ProcessTransactionsResult {
|
||||
retried: 1,
|
||||
max_retries_elapsed: 1,
|
||||
..ProcessTransactionsResult::default()
|
||||
}
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
&working_bank,
|
||||
&root_bank,
|
||||
&send_socket,
|
||||
&tpu_address,
|
||||
&mut transactions,
|
||||
&None,
|
||||
leader_forward_count,
|
||||
);
|
||||
assert!(transactions.is_empty());
|
||||
assert_eq!(
|
||||
result,
|
||||
ProcessTransactionsResult {
|
||||
max_retries_elapsed: 1,
|
||||
..ProcessTransactionsResult::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -559,6 +650,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -586,6 +678,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, Hash::new_unique())),
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -615,6 +708,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, Hash::new_unique())),
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -642,6 +736,7 @@ mod test {
|
||||
vec![],
|
||||
root_bank.slot() - 1,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -670,6 +765,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, Hash::new_unique())), // runtime should advance nonce on failed transactions
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -698,6 +794,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, Hash::new_unique())), // runtime advances nonce when transaction lands
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
@@ -727,6 +824,7 @@ mod test {
|
||||
vec![],
|
||||
last_valid_slot,
|
||||
Some((nonce_address, durable_nonce)),
|
||||
None,
|
||||
),
|
||||
);
|
||||
let result = SendTransactionService::process_transactions(
|
||||
|
@@ -8,7 +8,11 @@ use crate::{
|
||||
weighted_shuffle::weighted_best,
|
||||
};
|
||||
use bincode::serialize;
|
||||
use rand::distributions::{Distribution, WeightedIndex};
|
||||
use lru::LruCache;
|
||||
use rand::{
|
||||
distributions::{Distribution, WeightedError, WeightedIndex},
|
||||
Rng,
|
||||
};
|
||||
use solana_ledger::{blockstore::Blockstore, shred::Nonce};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_measure::thread_mem_usage;
|
||||
@@ -22,7 +26,7 @@ use solana_sdk::{
|
||||
};
|
||||
use solana_streamer::streamer::{PacketReceiver, PacketSender};
|
||||
use std::{
|
||||
collections::{hash_map::Entry, HashMap, HashSet},
|
||||
collections::HashSet,
|
||||
net::SocketAddr,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::{Arc, RwLock},
|
||||
@@ -34,6 +38,11 @@ use std::{
|
||||
pub const MAX_ORPHAN_REPAIR_RESPONSES: usize = 10;
|
||||
pub const DEFAULT_NONCE: u32 = 42;
|
||||
|
||||
// Number of slots to cache their respective repair peers and sampling weights.
|
||||
pub(crate) const REPAIR_PEERS_CACHE_CAPACITY: usize = 128;
|
||||
// Limit cache entries ttl in order to avoid re-using outdated data.
|
||||
const REPAIR_PEERS_CACHE_TTL: Duration = Duration::from_secs(10);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum RepairType {
|
||||
Orphan(Slot),
|
||||
@@ -81,7 +90,38 @@ pub struct ServeRepair {
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
}
|
||||
|
||||
type RepairCache = HashMap<Slot, (Vec<ContactInfo>, WeightedIndex<u64>)>;
|
||||
// Cache entry for repair peers for a slot.
|
||||
pub(crate) struct RepairPeers {
|
||||
asof: Instant,
|
||||
peers: Vec<(Pubkey, /*ContactInfo.serve_repair:*/ SocketAddr)>,
|
||||
weighted_index: WeightedIndex<u64>,
|
||||
}
|
||||
|
||||
impl RepairPeers {
|
||||
fn new(asof: Instant, peers: &[ContactInfo], weights: &[u64]) -> Result<Self> {
|
||||
if peers.is_empty() {
|
||||
return Err(Error::from(ClusterInfoError::NoPeers));
|
||||
}
|
||||
if peers.len() != weights.len() {
|
||||
return Err(Error::from(WeightedError::InvalidWeight));
|
||||
}
|
||||
let weighted_index = WeightedIndex::new(weights)?;
|
||||
let peers = peers
|
||||
.iter()
|
||||
.map(|peer| (peer.id, peer.serve_repair))
|
||||
.collect();
|
||||
Ok(Self {
|
||||
asof,
|
||||
peers,
|
||||
weighted_index,
|
||||
})
|
||||
}
|
||||
|
||||
fn sample<R: Rng>(&self, rng: &mut R) -> (Pubkey, SocketAddr) {
|
||||
let index = self.weighted_index.sample(rng);
|
||||
self.peers[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl ServeRepair {
|
||||
/// Without a valid keypair gossip will not function. Only useful for tests.
|
||||
@@ -377,39 +417,30 @@ impl ServeRepair {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn repair_request(
|
||||
pub(crate) fn repair_request(
|
||||
&self,
|
||||
cluster_slots: &ClusterSlots,
|
||||
repair_request: RepairType,
|
||||
cache: &mut RepairCache,
|
||||
peers_cache: &mut LruCache<Slot, RepairPeers>,
|
||||
repair_stats: &mut RepairStats,
|
||||
repair_validators: &Option<HashSet<Pubkey>>,
|
||||
) -> Result<(SocketAddr, Vec<u8>)> {
|
||||
// find a peer that appears to be accepting replication and has the desired slot, as indicated
|
||||
// by a valid tvu port location
|
||||
let slot = repair_request.slot();
|
||||
let (repair_peers, weighted_index) = match cache.entry(slot) {
|
||||
Entry::Occupied(entry) => entry.into_mut(),
|
||||
Entry::Vacant(entry) => {
|
||||
let repair_peers = self.repair_peers(&repair_validators, slot);
|
||||
if repair_peers.is_empty() {
|
||||
return Err(Error::from(ClusterInfoError::NoPeers));
|
||||
}
|
||||
let repair_peers = match peers_cache.get(&slot) {
|
||||
Some(entry) if entry.asof.elapsed() < REPAIR_PEERS_CACHE_TTL => entry,
|
||||
_ => {
|
||||
peers_cache.pop(&slot);
|
||||
let repair_peers = self.repair_peers(repair_validators, slot);
|
||||
let weights = cluster_slots.compute_weights(slot, &repair_peers);
|
||||
debug_assert_eq!(weights.len(), repair_peers.len());
|
||||
let weighted_index = WeightedIndex::new(weights)?;
|
||||
entry.insert((repair_peers, weighted_index))
|
||||
let repair_peers = RepairPeers::new(Instant::now(), &repair_peers, &weights)?;
|
||||
peers_cache.put(slot, repair_peers);
|
||||
peers_cache.get(&slot).unwrap()
|
||||
}
|
||||
};
|
||||
let n = weighted_index.sample(&mut rand::thread_rng());
|
||||
let addr = repair_peers[n].serve_repair; // send the request to the peer's serve_repair port
|
||||
let repair_peer_id = repair_peers[n].id;
|
||||
let out = self.map_repair_request(
|
||||
&repair_request,
|
||||
&repair_peer_id,
|
||||
repair_stats,
|
||||
DEFAULT_NONCE,
|
||||
)?;
|
||||
let (peer, addr) = repair_peers.sample(&mut rand::thread_rng());
|
||||
let out = self.map_repair_request(&repair_request, &peer, repair_stats, DEFAULT_NONCE)?;
|
||||
Ok((addr, out))
|
||||
}
|
||||
|
||||
@@ -755,7 +786,7 @@ mod tests {
|
||||
let rv = serve_repair.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&None,
|
||||
);
|
||||
@@ -782,7 +813,7 @@ mod tests {
|
||||
.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&None,
|
||||
)
|
||||
@@ -815,7 +846,7 @@ mod tests {
|
||||
.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&None,
|
||||
)
|
||||
@@ -991,7 +1022,7 @@ mod tests {
|
||||
.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&trusted_validators,
|
||||
)
|
||||
@@ -1007,7 +1038,7 @@ mod tests {
|
||||
.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&trusted_validators,
|
||||
)
|
||||
@@ -1027,7 +1058,7 @@ mod tests {
|
||||
.repair_request(
|
||||
&cluster_slots,
|
||||
RepairType::Shred(0, 0),
|
||||
&mut HashMap::new(),
|
||||
&mut LruCache::new(100),
|
||||
&mut RepairStats::default(),
|
||||
&None,
|
||||
)
|
||||
|
@@ -7,7 +7,9 @@ use solana_ledger::{
|
||||
use solana_runtime::bank::{
|
||||
Bank, InnerInstructionsList, NonceRollbackInfo, TransactionLogMessages,
|
||||
};
|
||||
use solana_transaction_status::{InnerInstructions, Reward, TransactionStatusMeta};
|
||||
use solana_transaction_status::{
|
||||
extract_and_fmt_memos, InnerInstructions, Reward, TransactionStatusMeta,
|
||||
};
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
@@ -107,9 +109,8 @@ impl TransactionStatusService {
|
||||
})
|
||||
.expect("FeeCalculator must exist");
|
||||
let fee = fee_calculator.calculate_fee(transaction.message());
|
||||
let (writable_keys, readonly_keys) = transaction
|
||||
.message
|
||||
.get_account_keys_by_lock_type(bank.demote_sysvar_write_locks());
|
||||
let (writable_keys, readonly_keys) =
|
||||
transaction.message.get_account_keys_by_lock_type();
|
||||
|
||||
let inner_instructions = inner_instructions.map(|inner_instructions| {
|
||||
inner_instructions
|
||||
@@ -140,6 +141,12 @@ impl TransactionStatusService {
|
||||
.collect(),
|
||||
);
|
||||
|
||||
if let Some(memos) = extract_and_fmt_memos(transaction.message()) {
|
||||
blockstore
|
||||
.write_transaction_memos(&transaction.signatures[0], memos)
|
||||
.expect("Expect database write to succeed: TransactionMemos");
|
||||
}
|
||||
|
||||
blockstore
|
||||
.write_transaction_status(
|
||||
slot,
|
||||
@@ -158,7 +165,7 @@ impl TransactionStatusService {
|
||||
rewards,
|
||||
},
|
||||
)
|
||||
.expect("Expect database write to succeed");
|
||||
.expect("Expect database write to succeed: TransactionStatus");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ use crate::{
|
||||
sigverify_shreds::ShredSigVerifier,
|
||||
sigverify_stage::SigVerifyStage,
|
||||
snapshot_packager_service::PendingSnapshotPackage,
|
||||
voting_service::VotingService,
|
||||
};
|
||||
use crossbeam_channel::unbounded;
|
||||
use solana_ledger::{
|
||||
@@ -65,6 +66,7 @@ pub struct Tvu {
|
||||
ledger_cleanup_service: Option<LedgerCleanupService>,
|
||||
accounts_background_service: AccountsBackgroundService,
|
||||
accounts_hash_verifier: AccountsHashVerifier,
|
||||
voting_service: VotingService,
|
||||
}
|
||||
|
||||
pub struct Sockets {
|
||||
@@ -265,6 +267,10 @@ impl Tvu {
|
||||
wait_for_vote_to_start_leader: tvu_config.wait_for_vote_to_start_leader,
|
||||
};
|
||||
|
||||
let (voting_sender, voting_receiver) = channel();
|
||||
let voting_service =
|
||||
VotingService::new(voting_receiver, cluster_info.clone(), poh_recorder.clone());
|
||||
|
||||
let replay_stage = ReplayStage::new(
|
||||
replay_stage_config,
|
||||
blockstore.clone(),
|
||||
@@ -281,6 +287,7 @@ impl Tvu {
|
||||
replay_vote_sender,
|
||||
gossip_confirmed_slots_receiver,
|
||||
gossip_verified_vote_hash_receiver,
|
||||
voting_sender,
|
||||
);
|
||||
|
||||
let ledger_cleanup_service = tvu_config.max_ledger_shreds.map(|max_ledger_shreds| {
|
||||
@@ -311,6 +318,7 @@ impl Tvu {
|
||||
ledger_cleanup_service,
|
||||
accounts_background_service,
|
||||
accounts_hash_verifier,
|
||||
voting_service,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +332,7 @@ impl Tvu {
|
||||
self.accounts_background_service.join()?;
|
||||
self.replay_stage.join()?;
|
||||
self.accounts_hash_verifier.join()?;
|
||||
self.voting_service.join()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@@ -1,84 +1,89 @@
|
||||
//! The `validator` module hosts all the validator microservices.
|
||||
|
||||
use crate::{
|
||||
broadcast_stage::BroadcastStageType,
|
||||
cache_block_meta_service::{CacheBlockMetaSender, CacheBlockMetaService},
|
||||
cluster_info::{
|
||||
ClusterInfo, Node, DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS,
|
||||
DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS,
|
||||
use {
|
||||
crate::{
|
||||
broadcast_stage::BroadcastStageType,
|
||||
cache_block_meta_service::{CacheBlockMetaSender, CacheBlockMetaService},
|
||||
cluster_info::{
|
||||
ClusterInfo, Node, DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS,
|
||||
DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS,
|
||||
},
|
||||
cluster_info_vote_listener::VoteTracker,
|
||||
completed_data_sets_service::CompletedDataSetsService,
|
||||
consensus::{reconcile_blockstore_roots_with_tower, Tower},
|
||||
contact_info::ContactInfo,
|
||||
crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS,
|
||||
gossip_service::GossipService,
|
||||
max_slots::MaxSlots,
|
||||
optimistically_confirmed_bank_tracker::{
|
||||
OptimisticallyConfirmedBank, OptimisticallyConfirmedBankTracker,
|
||||
},
|
||||
poh_recorder::{PohRecorder, GRACE_TICKS_FACTOR, MAX_GRACE_SLOTS},
|
||||
poh_service::{self, PohService},
|
||||
rewards_recorder_service::{RewardsRecorderSender, RewardsRecorderService},
|
||||
rpc::JsonRpcConfig,
|
||||
rpc_pubsub_service::{PubSubConfig, PubSubService},
|
||||
rpc_service::JsonRpcService,
|
||||
rpc_subscriptions::RpcSubscriptions,
|
||||
sample_performance_service::SamplePerformanceService,
|
||||
serve_repair::ServeRepair,
|
||||
serve_repair_service::ServeRepairService,
|
||||
sigverify,
|
||||
snapshot_packager_service::{PendingSnapshotPackage, SnapshotPackagerService},
|
||||
tpu::{Tpu, DEFAULT_TPU_COALESCE_MS},
|
||||
transaction_status_service::TransactionStatusService,
|
||||
tvu::{Sockets, Tvu, TvuConfig},
|
||||
},
|
||||
cluster_info_vote_listener::VoteTracker,
|
||||
completed_data_sets_service::CompletedDataSetsService,
|
||||
consensus::{reconcile_blockstore_roots_with_tower, Tower},
|
||||
contact_info::ContactInfo,
|
||||
gossip_service::GossipService,
|
||||
max_slots::MaxSlots,
|
||||
optimistically_confirmed_bank_tracker::{
|
||||
OptimisticallyConfirmedBank, OptimisticallyConfirmedBankTracker,
|
||||
crossbeam_channel::{bounded, unbounded},
|
||||
rand::{thread_rng, Rng},
|
||||
solana_ledger::{
|
||||
bank_forks_utils,
|
||||
blockstore::{Blockstore, BlockstoreSignals, CompletedSlotsReceiver, PurgeType},
|
||||
blockstore_db::BlockstoreRecoveryMode,
|
||||
blockstore_processor::{self, TransactionStatusSender},
|
||||
leader_schedule::FixedSchedule,
|
||||
leader_schedule_cache::LeaderScheduleCache,
|
||||
poh::compute_hash_time_ns,
|
||||
},
|
||||
solana_measure::measure::Measure,
|
||||
solana_metrics::datapoint_info,
|
||||
solana_runtime::{
|
||||
accounts_index::AccountSecondaryIndexes,
|
||||
bank::Bank,
|
||||
bank_forks::{BankForks, SnapshotConfig},
|
||||
commitment::BlockCommitmentCache,
|
||||
hardened_unpack::{open_genesis_config, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE},
|
||||
},
|
||||
solana_sdk::{
|
||||
clock::Slot,
|
||||
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
|
||||
genesis_config::GenesisConfig,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
shred_version::compute_shred_version,
|
||||
signature::{Keypair, Signer},
|
||||
timing::timestamp,
|
||||
},
|
||||
solana_vote_program::vote_state::VoteState,
|
||||
std::time::Instant,
|
||||
std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt,
|
||||
net::SocketAddr,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
mpsc::Receiver,
|
||||
Arc, Mutex, RwLock,
|
||||
},
|
||||
thread::{sleep, Builder},
|
||||
time::Duration,
|
||||
},
|
||||
poh_recorder::{PohRecorder, GRACE_TICKS_FACTOR, MAX_GRACE_SLOTS},
|
||||
poh_service::{self, PohService},
|
||||
rewards_recorder_service::{RewardsRecorderSender, RewardsRecorderService},
|
||||
rpc::JsonRpcConfig,
|
||||
rpc_pubsub_service::{PubSubConfig, PubSubService},
|
||||
rpc_service::JsonRpcService,
|
||||
rpc_subscriptions::RpcSubscriptions,
|
||||
sample_performance_service::SamplePerformanceService,
|
||||
serve_repair::ServeRepair,
|
||||
serve_repair_service::ServeRepairService,
|
||||
sigverify,
|
||||
snapshot_packager_service::{PendingSnapshotPackage, SnapshotPackagerService},
|
||||
tpu::{Tpu, DEFAULT_TPU_COALESCE_MS},
|
||||
transaction_status_service::TransactionStatusService,
|
||||
tvu::{Sockets, Tvu, TvuConfig},
|
||||
};
|
||||
use crossbeam_channel::{bounded, unbounded};
|
||||
use rand::{thread_rng, Rng};
|
||||
use solana_ledger::{
|
||||
bank_forks_utils,
|
||||
blockstore::{Blockstore, BlockstoreSignals, CompletedSlotsReceiver, PurgeType},
|
||||
blockstore_db::BlockstoreRecoveryMode,
|
||||
blockstore_processor::{self, TransactionStatusSender},
|
||||
leader_schedule::FixedSchedule,
|
||||
leader_schedule_cache::LeaderScheduleCache,
|
||||
poh::compute_hash_time_ns,
|
||||
};
|
||||
use solana_measure::measure::Measure;
|
||||
use solana_metrics::datapoint_info;
|
||||
use solana_runtime::{
|
||||
accounts_index::AccountSecondaryIndexes,
|
||||
bank::Bank,
|
||||
bank_forks::{BankForks, SnapshotConfig},
|
||||
commitment::BlockCommitmentCache,
|
||||
hardened_unpack::{open_genesis_config, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE},
|
||||
};
|
||||
use solana_sdk::{
|
||||
clock::Slot,
|
||||
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
|
||||
genesis_config::GenesisConfig,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
shred_version::compute_shred_version,
|
||||
signature::{Keypair, Signer},
|
||||
timing::timestamp,
|
||||
};
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::time::Instant;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
fmt,
|
||||
net::SocketAddr,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
sync::mpsc::Receiver,
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
thread::{sleep, Builder},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
const MAX_COMPLETED_DATA_SETS_IN_CHANNEL: usize = 100_000;
|
||||
const WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT: u64 = 90;
|
||||
const WAIT_FOR_SUPERMAJORITY_THRESHOLD_PERCENT: u64 = 80;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ValidatorConfig {
|
||||
@@ -1458,7 +1463,20 @@ fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: boo
|
||||
let mut offline_nodes = vec![];
|
||||
|
||||
let mut total_activated_stake = 0;
|
||||
let all_tvu_peers = cluster_info.all_tvu_peers();
|
||||
let now = timestamp();
|
||||
// Nodes contact infos are saved to disk and restored on validator startup.
|
||||
// Staked nodes entries will not expire until an epoch after. So it
|
||||
// is necessary here to filter for recent entries to establish liveness.
|
||||
let peers: HashMap<_, _> = cluster_info
|
||||
.all_tvu_peers()
|
||||
.into_iter()
|
||||
.filter(|node| {
|
||||
let age = now.saturating_sub(node.wallclock);
|
||||
// Contact infos are refreshed twice during this period.
|
||||
age < CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS
|
||||
})
|
||||
.map(|node| (node.id, node))
|
||||
.collect();
|
||||
let my_shred_version = cluster_info.my_shred_version();
|
||||
let my_id = cluster_info.id();
|
||||
|
||||
@@ -1474,10 +1492,7 @@ fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: boo
|
||||
.map(|vote_state| vote_state.node_pubkey)
|
||||
.unwrap_or_default();
|
||||
|
||||
if let Some(peer) = all_tvu_peers
|
||||
.iter()
|
||||
.find(|peer| peer.id == vote_state_node_pubkey)
|
||||
{
|
||||
if let Some(peer) = peers.get(&vote_state_node_pubkey) {
|
||||
if peer.shred_version == my_shred_version {
|
||||
trace!(
|
||||
"observed {} in gossip, (activated_stake={})",
|
||||
|
79
core/src/voting_service.rs
Normal file
79
core/src/voting_service.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use crate::cluster_info::ClusterInfo;
|
||||
use crate::poh_recorder::PohRecorder;
|
||||
use solana_sdk::{clock::Slot, transaction::Transaction};
|
||||
use std::{
|
||||
sync::{mpsc::Receiver, Arc, Mutex},
|
||||
thread::{self, Builder, JoinHandle},
|
||||
};
|
||||
|
||||
pub enum VoteOp {
|
||||
PushVote {
|
||||
tx: Transaction,
|
||||
tower_slots: Vec<Slot>,
|
||||
},
|
||||
RefreshVote {
|
||||
tx: Transaction,
|
||||
last_voted_slot: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
impl VoteOp {
|
||||
fn tx(&self) -> &Transaction {
|
||||
match self {
|
||||
VoteOp::PushVote { tx, tower_slots: _ } => tx,
|
||||
VoteOp::RefreshVote {
|
||||
tx,
|
||||
last_voted_slot: _,
|
||||
} => tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VotingService {
|
||||
thread_hdl: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl VotingService {
|
||||
pub fn new(
|
||||
vote_receiver: Receiver<VoteOp>,
|
||||
cluster_info: Arc<ClusterInfo>,
|
||||
poh_recorder: Arc<Mutex<PohRecorder>>,
|
||||
) -> Self {
|
||||
let thread_hdl = Builder::new()
|
||||
.name("sol-vote-service".to_string())
|
||||
.spawn(move || {
|
||||
for vote_op in vote_receiver.iter() {
|
||||
Self::handle_vote(&cluster_info, &poh_recorder, vote_op);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
Self { thread_hdl }
|
||||
}
|
||||
|
||||
pub fn handle_vote(
|
||||
cluster_info: &ClusterInfo,
|
||||
poh_recorder: &Mutex<PohRecorder>,
|
||||
vote_op: VoteOp,
|
||||
) {
|
||||
let _ = cluster_info.send_vote(
|
||||
vote_op.tx(),
|
||||
crate::banking_stage::next_leader_tpu(cluster_info, poh_recorder),
|
||||
);
|
||||
|
||||
match vote_op {
|
||||
VoteOp::PushVote { tx, tower_slots } => {
|
||||
cluster_info.push_vote(&tower_slots, tx);
|
||||
}
|
||||
VoteOp::RefreshVote {
|
||||
tx,
|
||||
last_voted_slot,
|
||||
} => {
|
||||
cluster_info.refresh_vote(tx, last_voted_slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) -> thread::Result<()> {
|
||||
self.thread_hdl.join()
|
||||
}
|
||||
}
|
@@ -483,7 +483,7 @@ fn network_run_pull(
|
||||
.collect()
|
||||
};
|
||||
let transfered: Vec<_> = requests
|
||||
.into_par_iter()
|
||||
.into_iter()
|
||||
.map(|(to, filters, caller_info)| {
|
||||
let mut bytes: usize = 0;
|
||||
let mut msgs: usize = 0;
|
||||
@@ -506,8 +506,9 @@ fn network_run_pull(
|
||||
.lock()
|
||||
.unwrap()
|
||||
.generate_pull_responses(
|
||||
thread_pool,
|
||||
&filters,
|
||||
/*output_size_limit=*/ usize::MAX,
|
||||
usize::MAX, // output_size_limit
|
||||
now,
|
||||
)
|
||||
.into_iter()
|
||||
|
@@ -27,7 +27,7 @@ use std::{
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio_02::runtime::Runtime;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
macro_rules! json_req {
|
||||
($method: expr, $params: expr) => {{
|
||||
@@ -159,7 +159,7 @@ fn test_rpc_slot_updates() {
|
||||
let connect = ws::try_connect::<PubsubClient>(&rpc_pubsub_url).unwrap();
|
||||
let client = connect.await.unwrap();
|
||||
|
||||
tokio_02::spawn(async move {
|
||||
tokio::spawn(async move {
|
||||
let mut update_sub = client.slots_updates_subscribe().unwrap();
|
||||
loop {
|
||||
let response = update_sub.next().await.unwrap();
|
||||
@@ -268,7 +268,7 @@ fn test_rpc_subscriptions() {
|
||||
)
|
||||
.unwrap_or_else(|err| panic!("sig sub err: {:#?}", err));
|
||||
|
||||
tokio_02::spawn(async move {
|
||||
tokio::spawn(async move {
|
||||
let response = sig_sub.next().await.unwrap();
|
||||
status_sender
|
||||
.send((sig.clone(), response.unwrap()))
|
||||
@@ -288,7 +288,7 @@ fn test_rpc_subscriptions() {
|
||||
}),
|
||||
)
|
||||
.unwrap_or_else(|err| panic!("acct sub err: {:#?}", err));
|
||||
tokio_02::spawn(async move {
|
||||
tokio::spawn(async move {
|
||||
let response = client_sub.next().await.unwrap();
|
||||
account_sender.send(response.unwrap()).unwrap();
|
||||
});
|
||||
@@ -298,7 +298,7 @@ fn test_rpc_subscriptions() {
|
||||
let mut slot_sub = client
|
||||
.slot_subscribe()
|
||||
.unwrap_or_else(|err| panic!("sig sub err: {:#?}", err));
|
||||
tokio_02::spawn(async move {
|
||||
tokio::spawn(async move {
|
||||
let _response = slot_sub.next().await.unwrap();
|
||||
ready_sender.send(()).unwrap();
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-crate-features"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Crate Features"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -24,7 +24,6 @@ serde = { version = "1.0.100", features = ["rc"] }
|
||||
ed25519-dalek = { version = "=1.0.1", features = ["serde"] }
|
||||
syn_0_15 = { package = "syn", version = "0.15.42", features = ["extra-traits", "fold", "full"] }
|
||||
syn_1_0 = { package = "syn", version = "1.0.3", features = ["extra-traits", "fold", "full"] }
|
||||
tokio = { version = "0.1.22",features=["bytes", "codec", "default", "fs", "io", "mio", "num_cpus", "reactor", "rt-full", "sync", "tcp", "timer", "tokio-codec", "tokio-current-thread", "tokio-executor", "tokio-io", "tokio-io", "tokio-reactor", "tokio-tcp", "tokio-tcp", "tokio-threadpool", "tokio-timer", "tokio-udp", "tokio-uds", "udp", "uds"] }
|
||||
winapi = { version = "0.3.8", features=["basetsd", "consoleapi", "errhandlingapi", "fileapi", "handleapi", "impl-debug", "impl-default", "knownfolders", "libloaderapi", "memoryapi", "minwinbase", "minwindef", "ntdef", "ntsecapi", "ntstatus", "objbase", "processenv", "processthreadsapi", "profileapi", "shlobj", "std", "synchapi", "sysinfoapi", "timezoneapi", "utilapiset", "winbase", "wincon", "windef", "winerror", "winnls", "winnt", "winreg", "winsock2", "winuser", "ws2def", "ws2ipdef", "ws2tcpip", "wtypesbase"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -3034,7 +3034,7 @@ curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
|
||||
|
||||
Result:
|
||||
```json
|
||||
{"jsonrpc":"2.0","result":{"solana-core": "1.6.19"},"id":1}
|
||||
{"jsonrpc":"2.0","result":{"solana-core": "1.6.24"},"id":1}
|
||||
```
|
||||
|
||||
### getVoteAccounts
|
||||
@@ -3241,6 +3241,8 @@ submission.
|
||||
- `skipPreflight: <bool>` - if true, skip the preflight transaction checks (default: false)
|
||||
- `preflightCommitment: <string>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to use for preflight (default: `"finalized"`).
|
||||
- `encoding: <string>` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`).
|
||||
- `maxRetries: <usize>` - (optional) Maximum number of times for the RPC node to retry sending the transaction to the leader.
|
||||
If this parameter not provided, the RPC node will retry the transaction until it is finalized or until the blockhash expires.
|
||||
|
||||
#### Results:
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-dos"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,15 +14,15 @@ clap = "2.33.1"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-download-utils"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Download Utils"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,8 +15,8 @@ console = "0.11.3"
|
||||
indicatif = "0.15.0"
|
||||
log = "0.4.11"
|
||||
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
tar = "0.4.28"
|
||||
|
||||
[lib]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-faucet"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Faucet"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -16,12 +16,12 @@ clap = "2.33"
|
||||
log = "0.4.11"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-frozen-abi"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Frozen ABI"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -16,11 +16,11 @@ log = "0.4.11"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
sha2 = "0.9.2"
|
||||
solana-frozen-abi-macro = { path = "macro", version = "=1.6.19" }
|
||||
solana-frozen-abi-macro = { path = "macro", version = "=1.6.24" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[target.'cfg(not(target_arch = "bpf"))'.dependencies]
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
generic-array = { version = "0.14.3", default-features = false, features = ["serde", "more_lengths"]}
|
||||
memmap2 = "0.1.0"
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-frozen-abi-macro"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Frozen ABI Macro"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-genesis"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -16,18 +16,18 @@ chrono = "0.4"
|
||||
serde = "1.0.122"
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.19" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.24" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-gossip"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -11,12 +11,12 @@ documentation = "https://docs.rs/solana-gossip"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33.1"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-net-utils = { path = "../net-utils", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-install"
|
||||
description = "The solana cluster software installer"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -25,12 +25,12 @@ reqwest = { version = "0.11.2", default-features = false, features = ["blocking"
|
||||
serde = { version = "1.0.122", features = ["derive"] }
|
||||
serde_json = "1.0.62"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
semver = "0.9.0"
|
||||
tar = "0.4.28"
|
||||
tempfile = "3.1.0"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-keygen"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana key generation utility"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -14,11 +14,11 @@ bs58 = "0.3.1"
|
||||
clap = "2.33"
|
||||
dirs-next = "2.0.0"
|
||||
num_cpus = "1.13.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.19" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-cli-config = { path = "../cli-config", version = "=1.6.24" }
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
tiny-bip39 = "0.7.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-ledger-tool"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -23,23 +23,23 @@ regex = "1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
serde_yaml = "0.8.13"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-cli-output = { path = "../cli-output", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
tempfile = "3.1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "1.0"
|
||||
assert_cmd = "2.0"
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
signal-hook = "0.1.15"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-ledger"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana ledger"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -34,22 +34,22 @@ reed-solomon-erasure = { version = "4.0.2", features = ["simd-accel"] }
|
||||
serde = "1.0.122"
|
||||
serde_bytes = "0.11.4"
|
||||
sha2 = "0.9.2"
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.19" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.19" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.19" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.19" }
|
||||
solana-storage-proto = { path = "../storage-proto", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.24" }
|
||||
solana-frozen-abi = { path = "../frozen-abi", version = "=1.6.24" }
|
||||
solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-merkle-tree = { path = "../merkle-tree", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.24" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-storage-bigtable = { path = "../storage-bigtable", version = "=1.6.24" }
|
||||
solana-storage-proto = { path = "../storage-proto", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
tempfile = "3.1.0"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
@@ -66,8 +66,8 @@ features = ["lz4"]
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
matches = "0.1.6"
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.19" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../account-decoder", version = "=1.6.24" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.24" }
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
|
@@ -139,6 +139,7 @@ pub struct Blockstore {
|
||||
code_shred_cf: LedgerColumn<cf::ShredCode>,
|
||||
transaction_status_cf: LedgerColumn<cf::TransactionStatus>,
|
||||
address_signatures_cf: LedgerColumn<cf::AddressSignatures>,
|
||||
transaction_memos_cf: LedgerColumn<cf::TransactionMemos>,
|
||||
transaction_status_index_cf: LedgerColumn<cf::TransactionStatusIndex>,
|
||||
active_transaction_status_index: RwLock<u64>,
|
||||
rewards_cf: LedgerColumn<cf::Rewards>,
|
||||
@@ -313,6 +314,7 @@ impl Blockstore {
|
||||
let code_shred_cf = db.column();
|
||||
let transaction_status_cf = db.column();
|
||||
let address_signatures_cf = db.column();
|
||||
let transaction_memos_cf = db.column();
|
||||
let transaction_status_index_cf = db.column();
|
||||
let rewards_cf = db.column();
|
||||
let blocktime_cf = db.column();
|
||||
@@ -362,6 +364,7 @@ impl Blockstore {
|
||||
code_shred_cf,
|
||||
transaction_status_cf,
|
||||
address_signatures_cf,
|
||||
transaction_memos_cf,
|
||||
transaction_status_index_cf,
|
||||
active_transaction_status_index: RwLock::new(active_transaction_status_index),
|
||||
rewards_cf,
|
||||
@@ -2016,6 +2019,14 @@ impl Blockstore {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_transaction_memos(&self, signature: Signature) -> Result<Option<String>> {
|
||||
self.transaction_memos_cf.get(signature)
|
||||
}
|
||||
|
||||
pub fn write_transaction_memos(&self, signature: &Signature, memos: String) -> Result<()> {
|
||||
self.transaction_memos_cf.put(*signature, &memos)
|
||||
}
|
||||
|
||||
fn ensure_lowest_cleanup_slot(&self) -> (std::sync::RwLockReadGuard<Slot>, Slot) {
|
||||
// Ensures consistent result by using lowest_cleanup_slot as the lower bound
|
||||
// for reading columns that do not employ strong read consistency with slot-based
|
||||
@@ -2499,12 +2510,13 @@ impl Blockstore {
|
||||
let transaction_status =
|
||||
self.get_transaction_status(signature, &confirmed_unrooted_slots)?;
|
||||
let err = transaction_status.and_then(|(_slot, status)| status.status.err());
|
||||
let memo = self.read_transaction_memos(signature)?;
|
||||
let block_time = self.get_block_time(slot)?;
|
||||
infos.push(ConfirmedTransactionStatusWithSignature {
|
||||
signature,
|
||||
slot,
|
||||
err,
|
||||
memo: None,
|
||||
memo,
|
||||
block_time,
|
||||
});
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ use solana_sdk::{
|
||||
};
|
||||
use solana_storage_proto::convert::generated;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
ffi::{CStr, CString},
|
||||
fs,
|
||||
marker::PhantomData,
|
||||
@@ -61,6 +61,8 @@ const CODE_SHRED_CF: &str = "code_shred";
|
||||
const TRANSACTION_STATUS_CF: &str = "transaction_status";
|
||||
/// Column family for Address Signatures
|
||||
const ADDRESS_SIGNATURES_CF: &str = "address_signatures";
|
||||
/// Column family for TransactionMemos
|
||||
const TRANSACTION_MEMOS_CF: &str = "transaction_memos";
|
||||
/// Column family for the Transaction Status Index.
|
||||
/// This column family is used for tracking the active primary index for columns that for
|
||||
/// query performance reasons should not be indexed by Slot.
|
||||
@@ -163,6 +165,10 @@ pub mod columns {
|
||||
/// The address signatures column
|
||||
pub struct AddressSignatures;
|
||||
|
||||
#[derive(Debug)]
|
||||
// The transaction memos column
|
||||
pub struct TransactionMemos;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// The transaction status index column
|
||||
pub struct TransactionStatusIndex;
|
||||
@@ -332,6 +338,10 @@ impl Rocks {
|
||||
AddressSignatures::NAME,
|
||||
get_cf_options::<AddressSignatures>(&access_type, &oldest_slot),
|
||||
);
|
||||
let transaction_memos_cf_descriptor = ColumnFamilyDescriptor::new(
|
||||
TransactionMemos::NAME,
|
||||
get_cf_options::<TransactionMemos>(&access_type, &oldest_slot),
|
||||
);
|
||||
let transaction_status_index_cf_descriptor = ColumnFamilyDescriptor::new(
|
||||
TransactionStatusIndex::NAME,
|
||||
get_cf_options::<TransactionStatusIndex>(&access_type, &oldest_slot),
|
||||
@@ -372,6 +382,7 @@ impl Rocks {
|
||||
(ShredCode::NAME, shred_code_cf_descriptor),
|
||||
(TransactionStatus::NAME, transaction_status_cf_descriptor),
|
||||
(AddressSignatures::NAME, address_signatures_cf_descriptor),
|
||||
(TransactionMemos::NAME, transaction_memos_cf_descriptor),
|
||||
(
|
||||
TransactionStatusIndex::NAME,
|
||||
transaction_status_index_cf_descriptor,
|
||||
@@ -421,9 +432,9 @@ impl Rocks {
|
||||
// this is only needed for LedgerCleanupService. so guard with PrimaryOnly (i.e. running solana-validator)
|
||||
if matches!(access_type, AccessType::PrimaryOnly) {
|
||||
for cf_name in cf_names {
|
||||
// this special column family must be excluded from LedgerCleanupService's rocksdb
|
||||
// these special column families must be excluded from LedgerCleanupService's rocksdb
|
||||
// compactions
|
||||
if cf_name == TransactionStatusIndex::NAME {
|
||||
if excludes_from_compaction(cf_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -494,6 +505,7 @@ impl Rocks {
|
||||
ShredCode::NAME,
|
||||
TransactionStatus::NAME,
|
||||
AddressSignatures::NAME,
|
||||
TransactionMemos::NAME,
|
||||
TransactionStatusIndex::NAME,
|
||||
Rewards::NAME,
|
||||
Blocktime::NAME,
|
||||
@@ -589,6 +601,10 @@ impl TypedColumn for columns::AddressSignatures {
|
||||
type Type = blockstore_meta::AddressSignatureMeta;
|
||||
}
|
||||
|
||||
impl TypedColumn for columns::TransactionMemos {
|
||||
type Type = String;
|
||||
}
|
||||
|
||||
impl TypedColumn for columns::TransactionStatusIndex {
|
||||
type Type = blockstore_meta::TransactionStatusIndexMeta;
|
||||
}
|
||||
@@ -703,6 +719,37 @@ impl ColumnName for columns::AddressSignatures {
|
||||
const NAME: &'static str = ADDRESS_SIGNATURES_CF;
|
||||
}
|
||||
|
||||
impl Column for columns::TransactionMemos {
|
||||
type Index = Signature;
|
||||
|
||||
fn key(signature: Signature) -> Vec<u8> {
|
||||
let mut key = vec![0; 64]; // size_of Signature
|
||||
key[0..64].clone_from_slice(&signature.as_ref()[0..64]);
|
||||
key
|
||||
}
|
||||
|
||||
fn index(key: &[u8]) -> Signature {
|
||||
Signature::new(&key[0..64])
|
||||
}
|
||||
|
||||
fn primary_index(_index: Self::Index) -> u64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn slot(_index: Self::Index) -> Slot {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn as_index(_index: u64) -> Self::Index {
|
||||
Signature::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl ColumnName for columns::TransactionMemos {
|
||||
const NAME: &'static str = TRANSACTION_MEMOS_CF;
|
||||
}
|
||||
|
||||
impl Column for columns::TransactionStatusIndex {
|
||||
type Index = u64;
|
||||
|
||||
@@ -1319,9 +1366,7 @@ fn get_cf_options<C: 'static + Column + ColumnName>(
|
||||
|
||||
// TransactionStatusIndex must be excluded from LedgerCleanupService's rocksdb
|
||||
// compactions....
|
||||
if matches!(access_type, AccessType::PrimaryOnly)
|
||||
&& C::NAME != columns::TransactionStatusIndex::NAME
|
||||
{
|
||||
if matches!(access_type, AccessType::PrimaryOnly) && !excludes_from_compaction(C::NAME) {
|
||||
options.set_compaction_filter_factory(PurgedSlotFilterFactory::<C> {
|
||||
oldest_slot: oldest_slot.clone(),
|
||||
name: CString::new(format!("purged_slot_filter_factory({})", C::NAME)).unwrap(),
|
||||
@@ -1361,6 +1406,19 @@ fn get_db_options(access_type: &AccessType) -> Options {
|
||||
options
|
||||
}
|
||||
|
||||
fn excludes_from_compaction(cf_name: &str) -> bool {
|
||||
// list of Column Families must be excluded from compaction:
|
||||
let no_compaction_cfs: HashSet<&'static str> = vec![
|
||||
columns::TransactionStatusIndex::NAME,
|
||||
columns::ProgramCosts::NAME,
|
||||
columns::TransactionMemos::NAME,
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
no_compaction_cfs.get(cf_name).is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
@@ -1413,4 +1471,15 @@ pub mod tests {
|
||||
CompactionDecision::Keep
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_excludes_from_compaction() {
|
||||
// currently there are two CFs are excluded from compaction:
|
||||
assert!(excludes_from_compaction(
|
||||
columns::TransactionStatusIndex::NAME
|
||||
));
|
||||
assert!(excludes_from_compaction(columns::ProgramCosts::NAME));
|
||||
assert!(excludes_from_compaction(columns::TransactionMemos::NAME));
|
||||
assert!(!excludes_from_compaction("something else"));
|
||||
}
|
||||
}
|
||||
|
@@ -244,13 +244,11 @@ pub fn verify_shreds_gpu(
|
||||
shred_gpu_offsets(pubkeys_len, batches, recycler_cache);
|
||||
let mut out = recycler_cache.buffer().allocate().unwrap();
|
||||
out.set_pinnable();
|
||||
elems.push(
|
||||
perf_libs::Elems {
|
||||
#![allow(clippy::cast_ptr_alignment)]
|
||||
elems: pubkeys.as_ptr() as *const solana_sdk::packet::Packet,
|
||||
num: num_packets as u32,
|
||||
},
|
||||
);
|
||||
elems.push(perf_libs::Elems {
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
elems: pubkeys.as_ptr() as *const solana_sdk::packet::Packet,
|
||||
num: num_packets as u32,
|
||||
});
|
||||
|
||||
for p in batches {
|
||||
elems.push(perf_libs::Elems {
|
||||
@@ -383,13 +381,11 @@ pub fn sign_shreds_gpu(
|
||||
let mut signatures_out = recycler_cache.buffer().allocate().unwrap();
|
||||
signatures_out.set_pinnable();
|
||||
signatures_out.resize(total_sigs * sig_size, 0);
|
||||
elems.push(
|
||||
perf_libs::Elems {
|
||||
#![allow(clippy::cast_ptr_alignment)]
|
||||
elems: pinned_keypair.as_ptr() as *const solana_sdk::packet::Packet,
|
||||
num: num_keypair_packets as u32,
|
||||
},
|
||||
);
|
||||
elems.push(perf_libs::Elems {
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
elems: pinned_keypair.as_ptr() as *const solana_sdk::packet::Packet,
|
||||
num: num_keypair_packets as u32,
|
||||
});
|
||||
|
||||
for p in batches.iter() {
|
||||
elems.push(perf_libs::Elems {
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-local-cluster"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -17,21 +17,21 @@ fs_extra = "1.2.0"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.19" }
|
||||
solana-core = { path = "../core", version = "=1.6.19" }
|
||||
solana-client = { path = "../client", version = "=1.6.19" }
|
||||
solana-download-utils = { path = "../download-utils", version = "=1.6.19" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.19" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-config-program = { path = "../programs/config", version = "=1.6.24" }
|
||||
solana-core = { path = "../core", version = "=1.6.24" }
|
||||
solana-client = { path = "../client", version = "=1.6.24" }
|
||||
solana-download-utils = { path = "../download-utils", version = "=1.6.24" }
|
||||
solana-faucet = { path = "../faucet", version = "=1.6.24" }
|
||||
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
solana-vest-program = { path = "../programs/vest", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
tempfile = "3.1.0"
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.19" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
edition = "2018"
|
||||
name = "solana-log-analyzer"
|
||||
description = "The solana cluster network analysis tool"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -14,9 +14,9 @@ byte-unit = "4.0.9"
|
||||
clap = "2.33.1"
|
||||
serde = "1.0.122"
|
||||
serde_json = "1.0.56"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
|
||||
[[bin]]
|
||||
name = "solana-log-analyzer"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-logger"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Logger"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-measure"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-measure"
|
||||
readme = "../README.md"
|
||||
@@ -12,8 +12,8 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
jemallocator = "0.3.2"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-merkle-root-bench"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -10,11 +10,11 @@ publish = false
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
clap = "2.33.1"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-merkle-tree"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Merkle Tree"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-merkle-tree"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../sdk/program", version = "=1.6.24" }
|
||||
fast-math = "0.1"
|
||||
|
||||
# This can go once the BPF toolchain target Rust 1.42.0+
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-metrics"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Metrics"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -15,7 +15,7 @@ gethostname = "0.2.1"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.11"
|
||||
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7.0"
|
||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-net-shaper"
|
||||
description = "The solana cluster network shaping tool"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,8 +13,8 @@ publish = false
|
||||
clap = "2.33.1"
|
||||
serde = "1.0.122"
|
||||
serde_json = "1.0.56"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
rand = "0.7.0"
|
||||
|
||||
[[bin]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-net-utils"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Network Utilities"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -18,9 +18,9 @@ rand = "0.7.0"
|
||||
serde = "1.0.122"
|
||||
serde_derive = "1.0.103"
|
||||
socket2 = "0.3.17"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
url = "2.1.1"
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-notifier"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Notifier"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-perf"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana Performance APIs"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -18,12 +18,12 @@ serde = "1.0.122"
|
||||
dlopen_derive = "0.1.4"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.11"
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.19" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "=1.6.24" }
|
||||
solana-budget-program = { path = "../programs/budget", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-metrics = { path = "../metrics", version = "=1.6.24" }
|
||||
curve25519-dalek = { version = "2" }
|
||||
|
||||
[lib]
|
||||
|
@@ -118,10 +118,8 @@ fn verify_packet(packet: &mut Packet) {
|
||||
let pubkey_end = pubkey_start.saturating_add(size_of::<Pubkey>());
|
||||
let sig_end = sig_start.saturating_add(size_of::<Signature>());
|
||||
|
||||
if pubkey_end >= packet.meta.size || sig_end >= packet.meta.size {
|
||||
packet.meta.discard = true;
|
||||
return;
|
||||
}
|
||||
// get_packet_offsets should ensure pubkey_end and sig_end do
|
||||
// not overflow packet.meta.size
|
||||
|
||||
let signature = Signature::new(&packet.data[sig_start..sig_end]);
|
||||
|
||||
@@ -217,6 +215,10 @@ fn do_get_packet_offsets(
|
||||
.filter(|v| *v <= packet.meta.size)
|
||||
.ok_or(PacketError::InvalidPubkeyLen)?;
|
||||
|
||||
if pubkey_len < sig_len_untrusted {
|
||||
return Err(PacketError::InvalidPubkeyLen);
|
||||
}
|
||||
|
||||
let sig_start = current_offset
|
||||
.checked_add(sig_size)
|
||||
.ok_or(PacketError::InvalidLen)?;
|
||||
@@ -597,6 +599,65 @@ mod tests {
|
||||
assert_eq!(res, Err(PacketError::InvalidLen));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_too_small() {
|
||||
solana_logger::setup();
|
||||
let mut tx = test_tx();
|
||||
let sig = tx.signatures[0];
|
||||
const NUM_SIG: usize = 18;
|
||||
tx.signatures = vec![sig; NUM_SIG];
|
||||
tx.message.account_keys = vec![];
|
||||
tx.message.header.num_required_signatures = NUM_SIG as u8;
|
||||
let mut packet = sigverify::make_packet_from_transaction(tx);
|
||||
|
||||
let res = sigverify::do_get_packet_offsets(&packet, 0);
|
||||
assert_eq!(res, Err(PacketError::InvalidPubkeyLen));
|
||||
|
||||
verify_packet(&mut packet);
|
||||
assert!(packet.meta.discard);
|
||||
|
||||
packet.meta.discard = false;
|
||||
let mut batches = generate_packet_vec(&packet, 1, 1);
|
||||
ed25519_verify(&mut batches);
|
||||
assert!(batches[0].packets[0].meta.discard);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_len() {
|
||||
// See that the verify cannot walk off the end of the packet
|
||||
// trying to index into the account_keys to access pubkey.
|
||||
use solana_sdk::signer::{keypair::Keypair, Signer};
|
||||
solana_logger::setup();
|
||||
|
||||
const NUM_SIG: usize = 17;
|
||||
let keypair1 = Keypair::new();
|
||||
let pubkey1 = keypair1.pubkey();
|
||||
let mut message = Message::new(&[], Some(&pubkey1));
|
||||
message.account_keys.push(pubkey1);
|
||||
message.account_keys.push(pubkey1);
|
||||
message.header.num_required_signatures = NUM_SIG as u8;
|
||||
message.recent_blockhash = Hash(pubkey1.to_bytes());
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
|
||||
info!("message: {:?}", tx.message_data());
|
||||
info!("tx: {:?}", tx);
|
||||
let sig = keypair1.try_sign_message(&tx.message_data()).unwrap();
|
||||
tx.signatures = vec![sig; NUM_SIG];
|
||||
|
||||
let mut packet = sigverify::make_packet_from_transaction(tx);
|
||||
|
||||
let res = sigverify::do_get_packet_offsets(&packet, 0);
|
||||
assert_eq!(res, Err(PacketError::InvalidPubkeyLen));
|
||||
|
||||
verify_packet(&mut packet);
|
||||
assert!(packet.meta.discard);
|
||||
|
||||
packet.meta.discard = false;
|
||||
let mut batches = generate_packet_vec(&packet, 1, 1);
|
||||
ed25519_verify(&mut batches);
|
||||
assert!(batches[0].packets[0].meta.discard);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_large_sig_len() {
|
||||
let tx = test_tx();
|
||||
@@ -748,10 +809,8 @@ mod tests {
|
||||
|
||||
let mut batches = generate_packet_vec(&packet, n, 2);
|
||||
|
||||
let recycler = Recycler::new_without_limit("");
|
||||
let recycler_out = Recycler::new_without_limit("");
|
||||
// verify packets
|
||||
sigverify::ed25519_verify(&mut batches, &recycler, &recycler_out);
|
||||
ed25519_verify(&mut batches);
|
||||
|
||||
// check result
|
||||
let should_discard = modify_data;
|
||||
@@ -761,6 +820,12 @@ mod tests {
|
||||
.all(|p| p.meta.discard == should_discard));
|
||||
}
|
||||
|
||||
fn ed25519_verify(batches: &mut [Packets]) {
|
||||
let recycler = Recycler::new_without_limit("");
|
||||
let recycler_out = Recycler::new_without_limit("");
|
||||
sigverify::ed25519_verify(batches, &recycler, &recycler_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_verify_tampered_sig_len() {
|
||||
let mut tx = test_tx();
|
||||
@@ -770,10 +835,8 @@ mod tests {
|
||||
|
||||
let mut batches = generate_packet_vec(&packet, 1, 1);
|
||||
|
||||
let recycler = Recycler::new_without_limit("");
|
||||
let recycler_out = Recycler::new_without_limit("");
|
||||
// verify packets
|
||||
sigverify::ed25519_verify(&mut batches, &recycler, &recycler_out);
|
||||
ed25519_verify(&mut batches);
|
||||
assert!(batches
|
||||
.iter()
|
||||
.flat_map(|p| &p.packets)
|
||||
@@ -810,10 +873,8 @@ mod tests {
|
||||
|
||||
batches[0].packets.push(packet);
|
||||
|
||||
let recycler = Recycler::new_without_limit("");
|
||||
let recycler_out = Recycler::new_without_limit("");
|
||||
// verify packets
|
||||
sigverify::ed25519_verify(&mut batches, &recycler, &recycler_out);
|
||||
ed25519_verify(&mut batches);
|
||||
|
||||
// check result
|
||||
let ref_ans = 1u8;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
edition = "2018"
|
||||
name = "solana-poh-bench"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
@@ -13,13 +13,13 @@ clap = "2.33.1"
|
||||
log = "0.4.11"
|
||||
rand = "0.7.0"
|
||||
rayon = "1.5.0"
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.19" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.19" }
|
||||
solana-version = { path = "../version", version = "=1.6.19" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-ledger = { path = "../ledger", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "=1.6.24" }
|
||||
solana-measure = { path = "../measure", version = "=1.6.24" }
|
||||
solana-version = { path = "../version", version = "=1.6.24" }
|
||||
solana-perf = { path = "../perf", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -5,7 +5,7 @@ edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
name = "solana-program-test"
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.42"
|
||||
@@ -17,16 +17,16 @@ log = "0.4.11"
|
||||
mio = "0.7.6"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
solana-banks-client = { path = "../banks-client", version = "=1.6.19" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.19" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.19" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.19" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.19" }
|
||||
solana-banks-client = { path = "../banks-client", version = "=1.6.24" }
|
||||
solana-banks-server = { path = "../banks-server", version = "=1.6.24" }
|
||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.24" }
|
||||
solana-logger = { path = "../logger", version = "=1.6.24" }
|
||||
solana-runtime = { path = "../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.6.24" }
|
||||
solana-vote-program = { path = "../programs/vote", version = "=1.6.24" }
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches = "1.3.0"
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.19" }
|
||||
solana-stake-program = { path = "../programs/stake", version = "=1.6.24" }
|
||||
|
@@ -19,7 +19,6 @@ use {
|
||||
clock::{Clock, Slot},
|
||||
entrypoint::{ProgramResult, SUCCESS},
|
||||
epoch_schedule::EpochSchedule,
|
||||
feature_set::demote_sysvar_write_locks,
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
genesis_config::{ClusterType, GenesisConfig},
|
||||
hash::Hash,
|
||||
@@ -256,14 +255,12 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||
}
|
||||
panic!("Program id {} wasn't found in account_infos", program_id);
|
||||
};
|
||||
let demote_sysvar_write_locks =
|
||||
invoke_context.is_feature_active(&demote_sysvar_write_locks::id());
|
||||
// TODO don't have the caller's keyed_accounts so can't validate writer or signer escalation or deescalation yet
|
||||
let caller_privileges = message
|
||||
.account_keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| message.is_writable(i, demote_sysvar_write_locks))
|
||||
.map(|(i, _)| message.is_writable(i))
|
||||
.collect::<Vec<bool>>();
|
||||
|
||||
stable_log::program_invoke(&logger, &program_id, invoke_context.invoke_depth());
|
||||
@@ -334,7 +331,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||
|
||||
// Copy writeable account modifications back into the caller's AccountInfos
|
||||
for (i, account_pubkey) in message.account_keys.iter().enumerate() {
|
||||
if !message.is_writable(i, true) {
|
||||
if !message.is_writable(i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
780
programs/bpf/Cargo.lock
generated
780
programs/bpf/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "solana-bpf-programs"
|
||||
description = "Blockchain, Rebuilt for Scale"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
documentation = "https://docs.rs/solana"
|
||||
homepage = "https://solana.com/"
|
||||
readme = "README.md"
|
||||
@@ -25,15 +25,15 @@ elf = "0.0.10"
|
||||
itertools = "0.10.0"
|
||||
miow = "0.2.2"
|
||||
net2 = "0.2.37"
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.6.19" }
|
||||
solana-cli-output = { path = "../../cli-output", version = "=1.6.19" }
|
||||
solana-logger = { path = "../../logger", version = "=1.6.19" }
|
||||
solana-measure = { path = "../../measure", version = "=1.6.19" }
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.6.24" }
|
||||
solana-cli-output = { path = "../../cli-output", version = "=1.6.24" }
|
||||
solana-logger = { path = "../../logger", version = "=1.6.24" }
|
||||
solana-measure = { path = "../../measure", version = "=1.6.24" }
|
||||
solana_rbpf = "=0.2.9"
|
||||
solana-runtime = { path = "../../runtime", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../../sdk", version = "=1.6.19" }
|
||||
solana-transaction-status = { path = "../../transaction-status", version = "=1.6.19" }
|
||||
solana-account-decoder = { path = "../../account-decoder", version = "=1.6.19" }
|
||||
solana-runtime = { path = "../../runtime", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../../sdk", version = "=1.6.24" }
|
||||
solana-transaction-status = { path = "../../transaction-status", version = "=1.6.24" }
|
||||
solana-account-decoder = { path = "../../account-decoder", version = "=1.6.24" }
|
||||
|
||||
|
||||
[[bench]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,8 +10,8 @@ documentation = "https://docs.rs/solana-bpf-rust-128bit"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-128bit-dep"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-128bit-dep"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-alloc"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-alloc"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-call-depth"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-call-depth"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-caller-access"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-caller-access"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-custom-heap"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-custom-heap"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[features]
|
||||
default = ["custom-heap"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-dep-crate"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,7 +11,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { version = "1", default-features = false }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-deprecated-loader"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-deprecated-loader"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-dup-accounts"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-dup-accounts"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-error-handling"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -12,7 +12,7 @@ edition = "2018"
|
||||
[dependencies]
|
||||
num-derive = "0.2"
|
||||
num-traits = "0.2"
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[lib]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-external-spend"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-external-spend"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-finalize"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-finalize"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-instruction-introspection"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-instruction-introspection"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-invoke"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -11,7 +11,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-bpf-rust-invoked = { path = "../invoked", default-features = false }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-invoke-and-error"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-invoke-and-error"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-invoke-and-ok"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-invoke-and-ok"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-invoke-and-return"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-invoke-and-return"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-invoked"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-invoked"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[features]
|
||||
default = ["program"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-iter"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-iter"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,8 +10,8 @@ documentation = "https://docs.rs/solana-bpf-rust-many-args"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-many-args-dep"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/solana-bpf-rust-many-args-dep"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-mem"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -13,11 +13,11 @@ edition = "2018"
|
||||
no-entrypoint = []
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-program-test = { path = "../../../../program-test", version = "=1.6.19" }
|
||||
solana-sdk = { path = "../../../../sdk", version = "=1.6.19" }
|
||||
solana-program-test = { path = "../../../../program-test", version = "=1.6.24" }
|
||||
solana-sdk = { path = "../../../../sdk", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-membuiltins"
|
||||
version = "1.6.19"
|
||||
version = "1.6.24"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
@@ -10,8 +10,8 @@ documentation = "https://docs.rs/solana-bpf-rust-mem"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-bpf-rust-mem = { path = "../mem", version = "=1.6.19", features = [ "no-entrypoint" ] }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.19" }
|
||||
solana-bpf-rust-mem = { path = "../mem", version = "=1.6.24", features = [ "no-entrypoint" ] }
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.6.24" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user