Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
cfc7b22c4c | ||
|
5f1c637508 | ||
|
d888e0a6d7 | ||
|
10e808e1bd | ||
|
d9b03ca38b | ||
|
608d75b348 | ||
|
cee3cee4ef | ||
|
09e51323f0 | ||
|
da6f702129 | ||
|
02a83e7c6e | ||
|
83263e1737 | ||
|
1f7ac22b60 | ||
|
747debae56 | ||
|
00b4186469 | ||
|
b087dabf4f | ||
|
e00eb0a069 | ||
|
d4e49ffd06 | ||
|
0f34a190ea | ||
|
df2fb8f5b3 | ||
|
80d2a6046b | ||
|
24273b826f | ||
|
68d2616e35 | ||
|
f506d39339 | ||
|
bc58c9ec7e | ||
|
b57a52cd85 | ||
|
8631be42ac | ||
|
09367369ef | ||
|
23b8c95cc4 | ||
|
e61392b057 | ||
|
7deba20395 | ||
|
274c097f84 | ||
|
1c7cea1af4 | ||
|
4406496d2f | ||
|
a15fa4840c | ||
|
c9030660d6 | ||
|
fdeda769d0 | ||
|
53edd26578 | ||
|
2433cdd6d6 | ||
|
77b34c278e | ||
|
90e993fd9a | ||
|
251054d8c9 | ||
|
d4bb7cec69 | ||
|
a3f6b04345 | ||
|
ba4a5053dd | ||
|
6b47a259c3 | ||
|
c9ec13cf1f | ||
|
906a6ab837 | ||
|
d0e478a9f8 | ||
|
b560b64d33 | ||
|
057af41716 | ||
|
a44b8abd48 |
733
Cargo.lock
generated
733
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,7 @@ members = [
|
|||||||
"sdk",
|
"sdk",
|
||||||
"sdk-c",
|
"sdk-c",
|
||||||
"scripts",
|
"scripts",
|
||||||
|
"stake-monitor",
|
||||||
"sys-tuner",
|
"sys-tuner",
|
||||||
"transaction-status",
|
"transaction-status",
|
||||||
"upload-perf",
|
"upload-perf",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-archiver-lib"
|
name = "solana-archiver-lib"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Archiver Library"
|
description = "Solana Archiver Library"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -15,22 +15,22 @@ ed25519-dalek = "=1.0.0-pre.1"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
rand_chacha = "0.1.1"
|
rand_chacha = "0.1.1"
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-chacha = { path = "../chacha", version = "1.0.12" }
|
solana-chacha = { path = "../chacha", version = "1.0.17" }
|
||||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.12" }
|
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.12" }
|
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-archiver-utils"
|
name = "solana-archiver-utils"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Archiver Utils"
|
description = "Solana Archiver Utils"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -11,12 +11,12 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
solana-chacha = { path = "../chacha", version = "1.0.12" }
|
solana-chacha = { path = "../chacha", version = "1.0.17" }
|
||||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.12" }
|
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-archiver"
|
name = "solana-archiver"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -10,11 +10,11 @@ homepage = "https://solana.com/"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
console = "0.9.2"
|
console = "0.9.2"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.0.12" }
|
solana-archiver-lib = { path = "../archiver-lib", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-banking-bench"
|
name = "solana-banking-bench"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -10,11 +10,11 @@ homepage = "https://solana.com/"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.6"
|
log = "0.4.6"
|
||||||
rayon = "1.2.0"
|
rayon = "1.2.0"
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-measure = { path = "../measure", version = "1.0.12" }
|
solana-measure = { path = "../measure", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
crossbeam-channel = "0.3"
|
crossbeam-channel = "0.3"
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-exchange"
|
name = "solana-bench-exchange"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -18,17 +18,17 @@ rand = "0.6.5"
|
|||||||
rayon = "1.2.0"
|
rayon = "1.2.0"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-genesis = { path = "../genesis", version = "1.0.12" }
|
solana-genesis = { path = "../genesis", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.0.12" }
|
solana-faucet = { path = "../faucet", version = "1.0.17" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.0.12" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
solana-local-cluster = { path = "../local-cluster", version = "1.0.12" }
|
solana-local-cluster = { path = "../local-cluster", version = "1.0.17" }
|
||||||
|
@@ -2,14 +2,14 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-streamer"
|
name = "solana-bench-streamer"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-bench-tps"
|
name = "solana-bench-tps"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -14,24 +14,24 @@ log = "0.4.8"
|
|||||||
rayon = "1.2.0"
|
rayon = "1.2.0"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-genesis = { path = "../genesis", version = "1.0.12" }
|
solana-genesis = { path = "../genesis", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.0.12" }
|
solana-faucet = { path = "../faucet", version = "1.0.17" }
|
||||||
solana-librapay = { path = "../programs/librapay", version = "1.0.12", optional = true }
|
solana-librapay = { path = "../programs/librapay", version = "1.0.17", optional = true }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-measure = { path = "../measure", version = "1.0.12" }
|
solana-measure = { path = "../measure", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-move-loader-program = { path = "../programs/move_loader", version = "1.0.12", optional = true }
|
solana-move-loader-program = { path = "../programs/move_loader", version = "1.0.17", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "0.3.2"
|
serial_test = "0.3.2"
|
||||||
serial_test_derive = "0.4.0"
|
serial_test_derive = "0.4.0"
|
||||||
solana-local-cluster = { path = "../local-cluster", version = "1.0.12" }
|
solana-local-cluster = { path = "../local-cluster", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
move = ["solana-librapay", "solana-move-loader-program"]
|
move = ["solana-librapay", "solana-move-loader-program"]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-chacha-cuda"
|
name = "solana-chacha-cuda"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Chacha Cuda APIs"
|
description = "Solana Chacha Cuda APIs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -10,12 +10,12 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.12" }
|
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.17" }
|
||||||
solana-chacha = { path = "../chacha", version = "1.0.12" }
|
solana-chacha = { path = "../chacha", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.2.1"
|
hex-literal = "0.2.1"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-chacha-sys"
|
name = "solana-chacha-sys"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana chacha-sys"
|
description = "Solana chacha-sys"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-chacha"
|
name = "solana-chacha"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Chacha APIs"
|
description = "Solana Chacha APIs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,11 +12,11 @@ edition = "2018"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
rand_chacha = "0.1.1"
|
rand_chacha = "0.1.1"
|
||||||
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.12" }
|
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.2.1"
|
hex-literal = "0.2.1"
|
||||||
|
@@ -18,3 +18,6 @@ steps:
|
|||||||
- command: "ci/publish-docs.sh"
|
- command: "ci/publish-docs.sh"
|
||||||
timeout_in_minutes: 15
|
timeout_in_minutes: 15
|
||||||
name: "publish docs"
|
name: "publish docs"
|
||||||
|
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-move.sh"
|
||||||
|
name: "move"
|
||||||
|
timeout_in_minutes: 20
|
||||||
|
30
ci/buildkite-tests.yml
Normal file
30
ci/buildkite-tests.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# These steps are conditionally triggered by ci/buildkite.yml when files
|
||||||
|
# other than those in docs/ are modified
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- command: "ci/shellcheck.sh"
|
||||||
|
name: "shellcheck"
|
||||||
|
timeout_in_minutes: 5
|
||||||
|
- wait
|
||||||
|
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-coverage.sh"
|
||||||
|
name: "coverage"
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
- wait
|
||||||
|
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
|
||||||
|
name: "stable"
|
||||||
|
timeout_in_minutes: 60
|
||||||
|
artifact_paths: "log-*.txt"
|
||||||
|
- wait
|
||||||
|
- command: "ci/test-stable-perf.sh"
|
||||||
|
name: "stable-perf"
|
||||||
|
timeout_in_minutes: 40
|
||||||
|
artifact_paths: "log-*.txt"
|
||||||
|
agents:
|
||||||
|
- "queue=cuda"
|
||||||
|
- command: "ci/test-bench.sh"
|
||||||
|
name: "bench"
|
||||||
|
timeout_in_minutes: 30
|
||||||
|
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-local-cluster.sh"
|
||||||
|
name: "local-cluster"
|
||||||
|
timeout_in_minutes: 45
|
||||||
|
artifact_paths: "log-*.txt"
|
@@ -1,42 +1,22 @@
|
|||||||
# Build steps that run on pushes and pull requests.
|
# Build steps that run on pushes and pull requests.
|
||||||
|
# If files other than those in docs/ were modified, this will be followed up by
|
||||||
|
# ci/buildkite-tests.yml
|
||||||
#
|
#
|
||||||
# Release tags use buildkite-release.yml instead
|
# Release tags use buildkite-release.yml instead
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- command: "ci/shellcheck.sh"
|
|
||||||
name: "shellcheck"
|
|
||||||
timeout_in_minutes: 5
|
|
||||||
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-checks.sh"
|
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-checks.sh"
|
||||||
name: "checks"
|
name: "checks"
|
||||||
timeout_in_minutes: 20
|
timeout_in_minutes: 20
|
||||||
|
|
||||||
- wait
|
- wait
|
||||||
- command: "ci/test-stable-perf.sh"
|
|
||||||
name: "stable-perf"
|
- command: "ci/maybe-trigger-tests.sh"
|
||||||
timeout_in_minutes: 40
|
name: "maybe-trigger-tests"
|
||||||
artifact_paths: "log-*.txt"
|
timeout_in_minutes: 2
|
||||||
agents:
|
|
||||||
- "queue=cuda"
|
|
||||||
- command: "ci/test-bench.sh"
|
|
||||||
name: "bench"
|
|
||||||
timeout_in_minutes: 30
|
|
||||||
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
|
|
||||||
name: "stable"
|
|
||||||
timeout_in_minutes: 60
|
|
||||||
artifact_paths: "log-*.txt"
|
|
||||||
agents:
|
|
||||||
- "queue=rpc-test-capable"
|
|
||||||
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-move.sh"
|
|
||||||
name: "move"
|
|
||||||
timeout_in_minutes: 20
|
|
||||||
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-local-cluster.sh"
|
|
||||||
name: "local-cluster"
|
|
||||||
timeout_in_minutes: 45
|
|
||||||
artifact_paths: "log-*.txt"
|
|
||||||
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-coverage.sh"
|
|
||||||
name: "coverage"
|
|
||||||
timeout_in_minutes: 30
|
|
||||||
agents:
|
|
||||||
- "queue=rpc-test-capable"
|
|
||||||
- wait
|
- wait
|
||||||
|
|
||||||
- trigger: "solana-secondary"
|
- trigger: "solana-secondary"
|
||||||
branches: "!pull/*"
|
branches: "!pull/*"
|
||||||
async: true
|
async: true
|
||||||
|
21
ci/maybe-trigger-tests.sh
Executable file
21
ci/maybe-trigger-tests.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
annotate() {
|
||||||
|
${BUILDKITE:-false} && {
|
||||||
|
buildkite-agent annotate "$@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Skip if only the docs have been modified
|
||||||
|
ci/affects-files.sh \
|
||||||
|
\!^docs/ \
|
||||||
|
|| {
|
||||||
|
annotate --style info \
|
||||||
|
"Skipping all further tests as only docs/ files were modified"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
annotate --style info "Triggering tests"
|
||||||
|
buildkite-agent pipeline upload ci/buildkite-tests.yml
|
@@ -22,7 +22,7 @@ _ cargo +"$rust_stable" clippy --all --exclude solana-sdk-c -- --deny=warnings
|
|||||||
_ cargo +"$rust_stable" clippy --manifest-path sdk-c/Cargo.toml -- --deny=warnings
|
_ cargo +"$rust_stable" clippy --manifest-path sdk-c/Cargo.toml -- --deny=warnings
|
||||||
|
|
||||||
_ cargo +"$rust_stable" audit --version
|
_ cargo +"$rust_stable" audit --version
|
||||||
_ cargo +"$rust_stable" audit --ignore RUSTSEC-2020-0002
|
_ cargo +"$rust_stable" audit --ignore RUSTSEC-2020-0002 --ignore RUSTSEC-2020-0008
|
||||||
_ ci/nits.sh
|
_ ci/nits.sh
|
||||||
_ ci/order-crates-for-publishing.py
|
_ ci/order-crates-for-publishing.py
|
||||||
_ docs/build.sh
|
_ docs/build.sh
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-clap-utils"
|
name = "solana-clap-utils"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana utilities for the clap"
|
description = "Solana utilities for the clap"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -11,8 +11,8 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
rpassword = "4.0"
|
rpassword = "4.0"
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.12" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
thiserror = "1.0.11"
|
thiserror = "1.0.11"
|
||||||
tiny-bip39 = "0.7.0"
|
tiny-bip39 = "0.7.0"
|
||||||
url = "2.1.0"
|
url = "2.1.0"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-cli-config"
|
name = "solana-cli-config"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
@@ -1,10 +1,6 @@
|
|||||||
// Wallet settings that can be configured for long-term use
|
// Wallet settings that can be configured for long-term use
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::io;
|
||||||
fs::{create_dir_all, File},
|
|
||||||
io::{self, Write},
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@@ -46,23 +42,11 @@ impl Default for Config {
|
|||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load(config_file: &str) -> Result<Self, io::Error> {
|
pub fn load(config_file: &str) -> Result<Self, io::Error> {
|
||||||
let file = File::open(config_file.to_string())?;
|
crate::load_config_file(config_file)
|
||||||
let config = serde_yaml::from_reader(file)
|
|
||||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
|
|
||||||
Ok(config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self, config_file: &str) -> Result<(), io::Error> {
|
pub fn save(&self, config_file: &str) -> Result<(), io::Error> {
|
||||||
let serialized = serde_yaml::to_string(self)
|
crate::save_config_file(self, config_file)
|
||||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
|
|
||||||
|
|
||||||
if let Some(outdir) = Path::new(&config_file).parent() {
|
|
||||||
create_dir_all(outdir)?;
|
|
||||||
}
|
|
||||||
let mut file = File::create(config_file)?;
|
|
||||||
file.write_all(&serialized.into_bytes())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_websocket_url(json_rpc_url: &str) -> String {
|
pub fn compute_websocket_url(json_rpc_url: &str) -> String {
|
||||||
@@ -76,17 +60,38 @@ impl Config {
|
|||||||
ws_url
|
ws_url
|
||||||
.set_scheme(if is_secure { "wss" } else { "ws" })
|
.set_scheme(if is_secure { "wss" } else { "ws" })
|
||||||
.expect("unable to set scheme");
|
.expect("unable to set scheme");
|
||||||
let ws_port = match json_rpc_url.port() {
|
if let Some(port) = json_rpc_url.port() {
|
||||||
Some(port) => port + 1,
|
ws_url.set_port(Some(port + 1)).expect("unable to set port");
|
||||||
None => {
|
}
|
||||||
if is_secure {
|
|
||||||
8901
|
|
||||||
} else {
|
|
||||||
8900
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ws_url.set_port(Some(ws_port)).expect("unable to set port");
|
|
||||||
ws_url.to_string()
|
ws_url.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compute_websocket_url() {
|
||||||
|
assert_eq!(
|
||||||
|
Config::compute_websocket_url(&"http://devnet.solana.com"),
|
||||||
|
"ws://devnet.solana.com/".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Config::compute_websocket_url(&"https://devnet.solana.com"),
|
||||||
|
"wss://devnet.solana.com/".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Config::compute_websocket_url(&"http://example.com:8899"),
|
||||||
|
"ws://example.com:8900/".to_string()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Config::compute_websocket_url(&"https://example.com:1234"),
|
||||||
|
"wss://example.com:1235/".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -3,3 +3,37 @@ extern crate lazy_static;
|
|||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
pub use config::{Config, CONFIG_FILE};
|
pub use config::{Config, CONFIG_FILE};
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fs::{create_dir_all, File},
|
||||||
|
io::{self, Write},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn load_config_file<T, P>(config_file: P) -> Result<T, io::Error>
|
||||||
|
where
|
||||||
|
T: serde::de::DeserializeOwned,
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let file = File::open(config_file)?;
|
||||||
|
let config = serde_yaml::from_reader(file)
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save_config_file<T, P>(config: &T, config_file: P) -> Result<(), io::Error>
|
||||||
|
where
|
||||||
|
T: serde::ser::Serialize,
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let serialized = serde_yaml::to_string(config)
|
||||||
|
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
|
||||||
|
|
||||||
|
if let Some(outdir) = config_file.as_ref().parent() {
|
||||||
|
create_dir_all(outdir)?;
|
||||||
|
}
|
||||||
|
let mut file = File::create(config_file)?;
|
||||||
|
file.write_all(&serialized.into_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-cli"
|
name = "solana-cli"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -26,28 +26,28 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.0.12" }
|
solana-cli-config = { path = "../cli-config", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.0.12" }
|
solana-config-program = { path = "../programs/config", version = "1.0.17" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.0.12" }
|
solana-faucet = { path = "../faucet", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.12" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "1.0.12" }
|
solana-vote-signer = { path = "../vote-signer", version = "1.0.17" }
|
||||||
titlecase = "1.1.0"
|
titlecase = "1.1.0"
|
||||||
thiserror = "1.0.11"
|
thiserror = "1.0.11"
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -188,6 +188,9 @@ pub enum CliCommand {
|
|||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
},
|
},
|
||||||
GetGenesisHash,
|
GetGenesisHash,
|
||||||
|
GetEpoch {
|
||||||
|
commitment_config: CommitmentConfig,
|
||||||
|
},
|
||||||
GetSlot {
|
GetSlot {
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
},
|
},
|
||||||
@@ -402,6 +405,7 @@ pub enum CliCommand {
|
|||||||
to: Pubkey,
|
to: Pubkey,
|
||||||
from: SignerIndex,
|
from: SignerIndex,
|
||||||
sign_only: bool,
|
sign_only: bool,
|
||||||
|
no_wait: bool,
|
||||||
blockhash_query: BlockhashQuery,
|
blockhash_query: BlockhashQuery,
|
||||||
nonce_account: Option<Pubkey>,
|
nonce_account: Option<Pubkey>,
|
||||||
nonce_authority: SignerIndex,
|
nonce_authority: SignerIndex,
|
||||||
@@ -583,6 +587,7 @@ pub fn parse_command(
|
|||||||
command: CliCommand::GetGenesisHash,
|
command: CliCommand::GetGenesisHash,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
}),
|
}),
|
||||||
|
("epoch", Some(matches)) => parse_get_epoch(matches),
|
||||||
("slot", Some(matches)) => parse_get_slot(matches),
|
("slot", Some(matches)) => parse_get_slot(matches),
|
||||||
("transaction-count", Some(matches)) => parse_get_transaction_count(matches),
|
("transaction-count", Some(matches)) => parse_get_transaction_count(matches),
|
||||||
("leader-schedule", Some(_matches)) => Ok(CliCommandInfo {
|
("leader-schedule", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
@@ -898,6 +903,7 @@ pub fn parse_command(
|
|||||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
||||||
let to = pubkey_of_signer(matches, "to", wallet_manager)?.unwrap();
|
let to = pubkey_of_signer(matches, "to", wallet_manager)?.unwrap();
|
||||||
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
|
||||||
|
let no_wait = matches.is_present("no_wait");
|
||||||
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
let blockhash_query = BlockhashQuery::new_from_matches(matches);
|
||||||
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
|
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
|
||||||
let (nonce_authority, nonce_authority_pubkey) =
|
let (nonce_authority, nonce_authority_pubkey) =
|
||||||
@@ -923,6 +929,7 @@ pub fn parse_command(
|
|||||||
lamports,
|
lamports,
|
||||||
to,
|
to,
|
||||||
sign_only,
|
sign_only,
|
||||||
|
no_wait,
|
||||||
blockhash_query,
|
blockhash_query,
|
||||||
nonce_account,
|
nonce_account,
|
||||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||||
@@ -1149,7 +1156,7 @@ fn process_balance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_confirm(rpc_client: &RpcClient, signature: &Signature) -> ProcessResult {
|
fn process_confirm(rpc_client: &RpcClient, signature: &Signature) -> ProcessResult {
|
||||||
match rpc_client.get_signature_status(&signature.to_string()) {
|
match rpc_client.get_signature_status(&signature) {
|
||||||
Ok(status) => {
|
Ok(status) => {
|
||||||
if let Some(result) = status {
|
if let Some(result) = status {
|
||||||
match result {
|
match result {
|
||||||
@@ -1484,6 +1491,7 @@ fn process_transfer(
|
|||||||
to: &Pubkey,
|
to: &Pubkey,
|
||||||
from: SignerIndex,
|
from: SignerIndex,
|
||||||
sign_only: bool,
|
sign_only: bool,
|
||||||
|
no_wait: bool,
|
||||||
blockhash_query: &BlockhashQuery,
|
blockhash_query: &BlockhashQuery,
|
||||||
nonce_account: Option<&Pubkey>,
|
nonce_account: Option<&Pubkey>,
|
||||||
nonce_authority: SignerIndex,
|
nonce_authority: SignerIndex,
|
||||||
@@ -1530,7 +1538,11 @@ fn process_transfer(
|
|||||||
&fee_calculator,
|
&fee_calculator,
|
||||||
&tx.message,
|
&tx.message,
|
||||||
)?;
|
)?;
|
||||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers);
|
let result = if no_wait {
|
||||||
|
rpc_client.send_transaction(&tx)
|
||||||
|
} else {
|
||||||
|
rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &config.signers)
|
||||||
|
};
|
||||||
log_instruction_custom_error::<SystemError>(result)
|
log_instruction_custom_error::<SystemError>(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1598,6 +1610,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
CliCommand::GetEpochInfo { commitment_config } => {
|
CliCommand::GetEpochInfo { commitment_config } => {
|
||||||
process_get_epoch_info(&rpc_client, *commitment_config)
|
process_get_epoch_info(&rpc_client, *commitment_config)
|
||||||
}
|
}
|
||||||
|
CliCommand::GetEpoch { commitment_config } => {
|
||||||
|
process_get_epoch(&rpc_client, *commitment_config)
|
||||||
|
}
|
||||||
CliCommand::GetSlot { commitment_config } => {
|
CliCommand::GetSlot { commitment_config } => {
|
||||||
process_get_slot(&rpc_client, *commitment_config)
|
process_get_slot(&rpc_client, *commitment_config)
|
||||||
}
|
}
|
||||||
@@ -2073,6 +2088,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
to,
|
to,
|
||||||
from,
|
from,
|
||||||
sign_only,
|
sign_only,
|
||||||
|
no_wait,
|
||||||
ref blockhash_query,
|
ref blockhash_query,
|
||||||
ref nonce_account,
|
ref nonce_account,
|
||||||
nonce_authority,
|
nonce_authority,
|
||||||
@@ -2084,6 +2100,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
to,
|
to,
|
||||||
*from,
|
*from,
|
||||||
*sign_only,
|
*sign_only,
|
||||||
|
*no_wait,
|
||||||
blockhash_query,
|
blockhash_query,
|
||||||
nonce_account.as_ref(),
|
nonce_account.as_ref(),
|
||||||
*nonce_authority,
|
*nonce_authority,
|
||||||
@@ -2158,7 +2175,7 @@ pub fn request_and_confirm_airdrop(
|
|||||||
log_instruction_custom_error::<SystemError>(result)
|
log_instruction_custom_error::<SystemError>(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_instruction_custom_error<E>(result: ClientResult<String>) -> ProcessResult
|
pub fn log_instruction_custom_error<E>(result: ClientResult<Signature>) -> ProcessResult
|
||||||
where
|
where
|
||||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||||
{
|
{
|
||||||
@@ -2175,7 +2192,7 @@ where
|
|||||||
}
|
}
|
||||||
Err(err.into())
|
Err(err.into())
|
||||||
}
|
}
|
||||||
Ok(sig) => Ok(sig),
|
Ok(sig) => Ok(sig.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2490,6 +2507,12 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.validator(is_valid_signer)
|
.validator(is_valid_signer)
|
||||||
.help("Source account of funds (if different from client local account)"),
|
.help("Source account of funds (if different from client local account)"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("no_wait")
|
||||||
|
.long("no-wait")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
|
||||||
|
)
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.arg(nonce_arg())
|
||||||
.arg(nonce_authority_arg())
|
.arg(nonce_authority_arg())
|
||||||
@@ -3550,6 +3573,33 @@ mod tests {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
fee_payer: 0,
|
||||||
|
},
|
||||||
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test Transfer no-wait
|
||||||
|
let test_transfer = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"transfer",
|
||||||
|
"--no-wait",
|
||||||
|
&to_string,
|
||||||
|
"42",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&test_transfer, &default_keypair_file, None).unwrap(),
|
||||||
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Transfer {
|
||||||
|
lamports: 42_000_000_000,
|
||||||
|
to: to_pubkey,
|
||||||
|
from: 0,
|
||||||
|
sign_only: false,
|
||||||
|
no_wait: true,
|
||||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -3579,6 +3629,7 @@ mod tests {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -3613,6 +3664,7 @@ mod tests {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
blockhash_query::Source::Cluster,
|
blockhash_query::Source::Cluster,
|
||||||
blockhash
|
blockhash
|
||||||
@@ -3651,6 +3703,7 @@ mod tests {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
blockhash_query::Source::NonceAccount(nonce_address),
|
blockhash_query::Source::NonceAccount(nonce_address),
|
||||||
blockhash
|
blockhash
|
||||||
|
@@ -117,6 +117,17 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("epoch").about("Get current epoch")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("confirmed")
|
||||||
|
.long("confirmed")
|
||||||
|
.takes_value(false)
|
||||||
|
.help(
|
||||||
|
"Return epoch at maximum-lockout commitment level",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("transaction-count").about("Get current transaction count")
|
SubCommand::with_name("transaction-count").about("Get current transaction count")
|
||||||
.alias("get-transaction-count")
|
.alias("get-transaction-count")
|
||||||
@@ -325,6 +336,18 @@ pub fn parse_get_slot(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliErr
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_get_epoch(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
|
let commitment_config = if matches.is_present("confirmed") {
|
||||||
|
CommitmentConfig::default()
|
||||||
|
} else {
|
||||||
|
CommitmentConfig::recent()
|
||||||
|
};
|
||||||
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetEpoch { commitment_config },
|
||||||
|
signers: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_get_transaction_count(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
pub fn parse_get_transaction_count(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let commitment_config = if matches.is_present("confirmed") {
|
let commitment_config = if matches.is_present("confirmed") {
|
||||||
CommitmentConfig::default()
|
CommitmentConfig::default()
|
||||||
@@ -575,6 +598,14 @@ pub fn process_get_slot(
|
|||||||
Ok(slot.to_string())
|
Ok(slot.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_get_epoch(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
commitment_config: CommitmentConfig,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let epoch_info = rpc_client.get_epoch_info_with_commitment(commitment_config.clone())?;
|
||||||
|
Ok(epoch_info.epoch.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let epoch = value_t!(matches, "epoch", Epoch).ok();
|
let epoch = value_t!(matches, "epoch", Epoch).ok();
|
||||||
let slot_limit = value_t!(matches, "slot_limit", u64).ok();
|
let slot_limit = value_t!(matches, "slot_limit", u64).ok();
|
||||||
@@ -1280,6 +1311,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let test_get_epoch = test_commands
|
||||||
|
.clone()
|
||||||
|
.get_matches_from(vec!["test", "epoch"]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&test_get_epoch, &default_keypair_file, None).unwrap(),
|
||||||
|
CliCommandInfo {
|
||||||
|
command: CliCommand::GetEpoch {
|
||||||
|
commitment_config: CommitmentConfig::recent(),
|
||||||
|
},
|
||||||
|
signers: vec![],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
let test_transaction_count = test_commands
|
let test_transaction_count = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "transaction-count"]);
|
.get_matches_from(vec!["test", "transaction-count"]);
|
||||||
|
@@ -266,8 +266,8 @@ pub fn process_claim_storage_reward(
|
|||||||
&fee_calculator,
|
&fee_calculator,
|
||||||
&tx.message,
|
&tx.message,
|
||||||
)?;
|
)?;
|
||||||
let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?;
|
let signature = rpc_client.send_and_confirm_transaction_with_spinner(&mut tx, &signers)?;
|
||||||
Ok(signature_str)
|
Ok(signature.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_show_storage_account(
|
pub fn process_show_storage_account(
|
||||||
|
@@ -338,6 +338,7 @@ fn test_create_account_with_seed() {
|
|||||||
to: to_address,
|
to: to_address,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(nonce_hash),
|
blockhash_query: BlockhashQuery::None(nonce_hash),
|
||||||
nonce_account: Some(nonce_address),
|
nonce_account: Some(nonce_address),
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -358,6 +359,7 @@ fn test_create_account_with_seed() {
|
|||||||
to: to_address,
|
to: to_address,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
blockhash_query::Source::NonceAccount(nonce_address),
|
blockhash_query::Source::NonceAccount(nonce_address),
|
||||||
sign_only.blockhash,
|
sign_only.blockhash,
|
||||||
|
@@ -68,6 +68,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -95,6 +96,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -110,6 +112,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -147,6 +150,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
|
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
|
||||||
nonce_hash,
|
nonce_hash,
|
||||||
@@ -187,6 +191,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(nonce_hash),
|
blockhash_query: BlockhashQuery::None(nonce_hash),
|
||||||
nonce_account: Some(nonce_account.pubkey()),
|
nonce_account: Some(nonce_account.pubkey()),
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -202,6 +207,7 @@ fn test_transfer() {
|
|||||||
to: recipient_pubkey,
|
to: recipient_pubkey,
|
||||||
from: 0,
|
from: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
|
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
|
||||||
sign_only.blockhash,
|
sign_only.blockhash,
|
||||||
@@ -269,6 +275,7 @@ fn test_transfer_multisession_signing() {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 1,
|
from: 1,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -293,6 +300,7 @@ fn test_transfer_multisession_signing() {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 1,
|
from: 1,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
@@ -314,6 +322,7 @@ fn test_transfer_multisession_signing() {
|
|||||||
to: to_pubkey,
|
to: to_pubkey,
|
||||||
from: 1,
|
from: 1,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||||
nonce_account: None,
|
nonce_account: None,
|
||||||
nonce_authority: 0,
|
nonce_authority: 0,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-client"
|
name = "solana-client"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Client"
|
description = "Solana Client"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -19,10 +19,10 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.0.12" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tungstenite = "0.10.1"
|
tungstenite = "0.10.1"
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
@@ -31,4 +31,4 @@ url = "2.1.1"
|
|||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
jsonrpc-core = "14.0.5"
|
jsonrpc-core = "14.0.5"
|
||||||
jsonrpc-http-server = "14.0.6"
|
jsonrpc-http-server = "14.0.6"
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
|
@@ -40,7 +40,7 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
fn send(
|
fn send(
|
||||||
&self,
|
&self,
|
||||||
request: &RpcRequest,
|
request: &RpcRequest,
|
||||||
params: serde_json::Value,
|
_params: serde_json::Value,
|
||||||
_retries: usize,
|
_retries: usize,
|
||||||
) -> Result<serde_json::Value> {
|
) -> Result<serde_json::Value> {
|
||||||
if let Some(value) = self.mocks.write().unwrap().remove(request) {
|
if let Some(value) = self.mocks.write().unwrap().remove(request) {
|
||||||
@@ -50,17 +50,6 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
return Ok(Value::Null);
|
return Ok(Value::Null);
|
||||||
}
|
}
|
||||||
let val = match request {
|
let val = match request {
|
||||||
RpcRequest::ConfirmTransaction => {
|
|
||||||
if let Some(params_array) = params.as_array() {
|
|
||||||
if let Value::String(param_string) = ¶ms_array[0] {
|
|
||||||
Value::Bool(param_string == SIGNATURE)
|
|
||||||
} else {
|
|
||||||
Value::Null
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Value::Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RpcRequest::GetBalance => serde_json::to_value(Response {
|
RpcRequest::GetBalance => serde_json::to_value(Response {
|
||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: Value::Number(Number::from(50)),
|
value: Value::Number(Number::from(50)),
|
||||||
@@ -87,7 +76,7 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
context: RpcResponseContext { slot: 1 },
|
context: RpcResponseContext { slot: 1 },
|
||||||
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
|
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
|
||||||
})?,
|
})?,
|
||||||
RpcRequest::GetSignatureStatus => {
|
RpcRequest::GetSignatureStatuses => {
|
||||||
let status: transaction::Result<()> = if self.url == "account_in_use" {
|
let status: transaction::Result<()> = if self.url == "account_in_use" {
|
||||||
Err(TransactionError::AccountInUse)
|
Err(TransactionError::AccountInUse)
|
||||||
} else if self.url == "instruction_error" {
|
} else if self.url == "instruction_error" {
|
||||||
@@ -101,10 +90,12 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
|||||||
let status = if self.url == "sig_not_found" {
|
let status = if self.url == "sig_not_found" {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
let err = status.clone().err();
|
||||||
Some(TransactionStatus {
|
Some(TransactionStatus {
|
||||||
status,
|
status,
|
||||||
slot: 1,
|
slot: 1,
|
||||||
confirmations: Some(0),
|
confirmations: None,
|
||||||
|
err,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
serde_json::to_value(Response {
|
serde_json::to_value(Response {
|
||||||
|
@@ -27,12 +27,11 @@ use solana_sdk::{
|
|||||||
signers::Signers,
|
signers::Signers,
|
||||||
transaction::{self, Transaction, TransactionError},
|
transaction::{self, Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{ConfirmedBlock, TransactionStatus};
|
use solana_transaction_status::{ConfirmedBlock, TransactionEncoding, TransactionStatus};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
error,
|
error,
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
str::FromStr,
|
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
@@ -71,7 +70,7 @@ impl RpcClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn confirm_transaction(&self, signature: &str) -> ClientResult<bool> {
|
pub fn confirm_transaction(&self, signature: &Signature) -> ClientResult<bool> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.confirm_transaction_with_commitment(signature, CommitmentConfig::default())?
|
.confirm_transaction_with_commitment(signature, CommitmentConfig::default())?
|
||||||
.value)
|
.value)
|
||||||
@@ -79,55 +78,72 @@ impl RpcClient {
|
|||||||
|
|
||||||
pub fn confirm_transaction_with_commitment(
|
pub fn confirm_transaction_with_commitment(
|
||||||
&self,
|
&self,
|
||||||
signature: &str,
|
signature: &Signature,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<bool> {
|
) -> RpcResult<bool> {
|
||||||
let response = self
|
let Response { context, value } = self.get_signature_statuses(&[*signature])?;
|
||||||
.client
|
|
||||||
.send(
|
|
||||||
&RpcRequest::ConfirmTransaction,
|
|
||||||
json!([signature, commitment_config]),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.map_err(|err| err.into_with_command("ConfirmTransaction"))?;
|
|
||||||
|
|
||||||
serde_json::from_value::<Response<bool>>(response)
|
Ok(Response {
|
||||||
.map_err(|err| ClientError::new_with_command(err.into(), "ConfirmTransaction"))
|
context,
|
||||||
|
value: value[0]
|
||||||
|
.as_ref()
|
||||||
|
.filter(|result| result.satisfies_commitment(commitment_config))
|
||||||
|
.map(|result| result.status.is_ok())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<String> {
|
pub fn send_transaction(&self, transaction: &Transaction) -> ClientResult<Signature> {
|
||||||
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
||||||
let signature =
|
let response =
|
||||||
self.client
|
self.client
|
||||||
.send(&RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
|
.send(&RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
|
||||||
if signature.as_str().is_none() {
|
|
||||||
Err(RpcError::ForUser("Received result of an unexpected type".to_string()).into())
|
match response.as_str() {
|
||||||
} else {
|
None => {
|
||||||
Ok(signature.as_str().unwrap().to_string())
|
Err(RpcError::ForUser("Received result of an unexpected type".to_string()).into())
|
||||||
|
}
|
||||||
|
Some(signature_base58_str) => signature_base58_str
|
||||||
|
.parse::<Signature>()
|
||||||
|
.map_err(|err| RpcError::ParseError(err.to_string()).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_signature_status(
|
pub fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
signature: &str,
|
signature: &Signature,
|
||||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||||
self.get_signature_status_with_commitment(signature, CommitmentConfig::default())
|
self.get_signature_status_with_commitment(signature, CommitmentConfig::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_signature_statuses(
|
||||||
|
&self,
|
||||||
|
signatures: &[Signature],
|
||||||
|
) -> RpcResult<Vec<Option<TransactionStatus>>> {
|
||||||
|
let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
|
||||||
|
let signature_status =
|
||||||
|
self.client
|
||||||
|
.send(&RpcRequest::GetSignatureStatuses, json!([signatures]), 5)?;
|
||||||
|
Ok(serde_json::from_value(signature_status)
|
||||||
|
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_signature_status_with_commitment(
|
pub fn get_signature_status_with_commitment(
|
||||||
&self,
|
&self,
|
||||||
signature: &str,
|
signature: &Signature,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<Option<transaction::Result<()>>> {
|
) -> ClientResult<Option<transaction::Result<()>>> {
|
||||||
let signature_status = self.client.send(
|
let signature_status = self.client.send(
|
||||||
&RpcRequest::GetSignatureStatus,
|
&RpcRequest::GetSignatureStatuses,
|
||||||
json!([[signature.to_string()], commitment_config]),
|
json!([[signature.to_string()]]),
|
||||||
5,
|
5,
|
||||||
)?;
|
)?;
|
||||||
let result: Response<Vec<Option<TransactionStatus>>> =
|
let result: Response<Vec<Option<TransactionStatus>>> =
|
||||||
serde_json::from_value(signature_status).unwrap();
|
serde_json::from_value(signature_status)
|
||||||
|
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
|
||||||
Ok(result.value[0]
|
Ok(result.value[0]
|
||||||
.clone()
|
.clone()
|
||||||
|
.filter(|result| result.satisfies_commitment(commitment_config))
|
||||||
.map(|status_meta| status_meta.status))
|
.map(|status_meta| status_meta.status))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +192,17 @@ impl RpcClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
||||||
|
self.get_confirmed_block_with_encoding(slot, TransactionEncoding::Json)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_block_with_encoding(
|
||||||
|
&self,
|
||||||
|
slot: Slot,
|
||||||
|
encoding: TransactionEncoding,
|
||||||
|
) -> ClientResult<ConfirmedBlock> {
|
||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.send(&RpcRequest::GetConfirmedBlock, json!([slot]), 0)
|
.send(&RpcRequest::GetConfirmedBlock, json!([slot, encoding]), 0)
|
||||||
.map_err(|err| err.into_with_command("GetConfirmedBlock"))?;
|
.map_err(|err| err.into_with_command("GetConfirmedBlock"))?;
|
||||||
|
|
||||||
serde_json::from_value(response)
|
serde_json::from_value(response)
|
||||||
@@ -325,13 +349,13 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
transaction: &mut Transaction,
|
transaction: &mut Transaction,
|
||||||
signer_keys: &T,
|
signer_keys: &T,
|
||||||
) -> ClientResult<String> {
|
) -> ClientResult<Signature> {
|
||||||
let mut send_retries = 20;
|
let mut send_retries = 20;
|
||||||
loop {
|
loop {
|
||||||
let mut status_retries = 15;
|
let mut status_retries = 15;
|
||||||
let signature_str = self.send_transaction(transaction)?;
|
let signature = self.send_transaction(transaction)?;
|
||||||
let status = loop {
|
let status = loop {
|
||||||
let status = self.get_signature_status(&signature_str)?;
|
let status = self.get_signature_status(&signature)?;
|
||||||
if status.is_none() {
|
if status.is_none() {
|
||||||
status_retries -= 1;
|
status_retries -= 1;
|
||||||
if status_retries == 0 {
|
if status_retries == 0 {
|
||||||
@@ -347,7 +371,7 @@ impl RpcClient {
|
|||||||
};
|
};
|
||||||
send_retries = if let Some(result) = status.clone() {
|
send_retries = if let Some(result) = status.clone() {
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => return Ok(signature_str),
|
Ok(_) => return Ok(signature),
|
||||||
Err(TransactionError::AccountInUse) => {
|
Err(TransactionError::AccountInUse) => {
|
||||||
// Fetch a new blockhash and re-sign the transaction before sending it again
|
// Fetch a new blockhash and re-sign the transaction before sending it again
|
||||||
self.resign_transaction(transaction, signer_keys)?;
|
self.resign_transaction(transaction, signer_keys)?;
|
||||||
@@ -809,10 +833,9 @@ impl RpcClient {
|
|||||||
) -> ClientResult<()> {
|
) -> ClientResult<()> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
if let Ok(Some(_)) = self.get_signature_status_with_commitment(
|
if let Ok(Some(_)) =
|
||||||
&signature.to_string(),
|
self.get_signature_status_with_commitment(&signature, commitment_config.clone())
|
||||||
commitment_config.clone(),
|
{
|
||||||
) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if now.elapsed().as_secs() > 15 {
|
if now.elapsed().as_secs() > 15 {
|
||||||
@@ -832,14 +855,13 @@ impl RpcClient {
|
|||||||
trace!("check_signature: {:?}", signature);
|
trace!("check_signature: {:?}", signature);
|
||||||
|
|
||||||
for _ in 0..30 {
|
for _ in 0..30 {
|
||||||
let response = self.client.send(
|
let response =
|
||||||
&RpcRequest::ConfirmTransaction,
|
self.confirm_transaction_with_commitment(signature, CommitmentConfig::recent());
|
||||||
json!([signature.to_string(), CommitmentConfig::recent()]),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
Ok(Value::Bool(signature_status)) => {
|
Ok(Response {
|
||||||
|
value: signature_status,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
if signature_status {
|
if signature_status {
|
||||||
trace!("Response found signature");
|
trace!("Response found signature");
|
||||||
} else {
|
} else {
|
||||||
@@ -848,12 +870,6 @@ impl RpcClient {
|
|||||||
|
|
||||||
return signature_status;
|
return signature_status;
|
||||||
}
|
}
|
||||||
Ok(other) => {
|
|
||||||
debug!(
|
|
||||||
"check_signature request failed, expected bool, got: {:?}",
|
|
||||||
other
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("check_signature request failed: {:?}", err);
|
debug!("check_signature request failed: {:?}", err);
|
||||||
}
|
}
|
||||||
@@ -925,20 +941,20 @@ impl RpcClient {
|
|||||||
let response = self
|
let response = self
|
||||||
.client
|
.client
|
||||||
.send(
|
.send(
|
||||||
&RpcRequest::GetSignatureStatus,
|
&RpcRequest::GetSignatureStatuses,
|
||||||
json!([[signature.to_string()], CommitmentConfig::recent().ok()]),
|
json!([[signature.to_string()]]),
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.into_with_command("GetSignatureStatus"))?;
|
.map_err(|err| err.into_with_command("GetSignatureStatuses"))?;
|
||||||
let result: Response<Vec<Option<TransactionStatus>>> =
|
let result: Response<Vec<Option<TransactionStatus>>> = serde_json::from_value(response)
|
||||||
serde_json::from_value(response).unwrap();
|
.map_err(|err| ClientError::new_with_command(err.into(), "GetSignatureStatuses"))?;
|
||||||
|
|
||||||
let confirmations = result.value[0]
|
let confirmations = result.value[0]
|
||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
ClientError::new_with_command(
|
ClientError::new_with_command(
|
||||||
ClientErrorKind::Custom("signature not found".to_string()),
|
ClientErrorKind::Custom("signature not found".to_string()),
|
||||||
"GetSignatureStatus",
|
"GetSignatureStatuses",
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
.confirmations
|
.confirmations
|
||||||
@@ -950,7 +966,7 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
transaction: &mut Transaction,
|
transaction: &mut Transaction,
|
||||||
signer_keys: &T,
|
signer_keys: &T,
|
||||||
) -> ClientResult<String> {
|
) -> ClientResult<Signature> {
|
||||||
let mut confirmations = 0;
|
let mut confirmations = 0;
|
||||||
|
|
||||||
let progress_bar = new_spinner_progress_bar();
|
let progress_bar = new_spinner_progress_bar();
|
||||||
@@ -961,23 +977,21 @@ impl RpcClient {
|
|||||||
));
|
));
|
||||||
|
|
||||||
let mut send_retries = 20;
|
let mut send_retries = 20;
|
||||||
let signature_str = loop {
|
let signature = loop {
|
||||||
let mut status_retries = 15;
|
let mut status_retries = 15;
|
||||||
let (signature_str, status) = loop {
|
let (signature, status) = loop {
|
||||||
let signature_str = self.send_transaction(transaction)?;
|
let signature = self.send_transaction(transaction)?;
|
||||||
|
|
||||||
// Get recent commitment in order to count confirmations for successful transactions
|
// Get recent commitment in order to count confirmations for successful transactions
|
||||||
let status = self.get_signature_status_with_commitment(
|
let status = self
|
||||||
&signature_str,
|
.get_signature_status_with_commitment(&signature, CommitmentConfig::recent())?;
|
||||||
CommitmentConfig::recent(),
|
|
||||||
)?;
|
|
||||||
if status.is_none() {
|
if status.is_none() {
|
||||||
status_retries -= 1;
|
status_retries -= 1;
|
||||||
if status_retries == 0 {
|
if status_retries == 0 {
|
||||||
break (signature_str, status);
|
break (signature, status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break (signature_str, status);
|
break (signature, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg!(not(test)) {
|
if cfg!(not(test)) {
|
||||||
@@ -1002,7 +1016,7 @@ impl RpcClient {
|
|||||||
if let Some(result) = status {
|
if let Some(result) = status {
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
break signature_str;
|
break signature;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
@@ -1015,19 +1029,13 @@ impl RpcClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let signature = Signature::from_str(&signature_str).map_err(|_| {
|
|
||||||
ClientError::from(ClientErrorKind::Custom(format!(
|
|
||||||
"Returned string {} cannot be parsed as a signature",
|
|
||||||
signature_str
|
|
||||||
)))
|
|
||||||
})?;
|
|
||||||
loop {
|
loop {
|
||||||
// Return when default (max) commitment is reached
|
// Return when default (max) commitment is reached
|
||||||
// Failed transactions have already been eliminated, `is_some` check is sufficient
|
// Failed transactions have already been eliminated, `is_some` check is sufficient
|
||||||
if self.get_signature_status(&signature_str)?.is_some() {
|
if self.get_signature_status(&signature)?.is_some() {
|
||||||
progress_bar.set_message("Transaction confirmed");
|
progress_bar.set_message("Transaction confirmed");
|
||||||
progress_bar.finish_and_clear();
|
progress_bar.finish_and_clear();
|
||||||
return Ok(signature_str);
|
return Ok(signature);
|
||||||
}
|
}
|
||||||
progress_bar.set_message(&format!(
|
progress_bar.set_message(&format!(
|
||||||
"[{}/{}] Waiting for confirmations",
|
"[{}/{}] Waiting for confirmations",
|
||||||
@@ -1189,7 +1197,7 @@ mod tests {
|
|||||||
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
let tx = system_transaction::transfer(&key, &to, 50, blockhash);
|
||||||
|
|
||||||
let signature = rpc_client.send_transaction(&tx);
|
let signature = rpc_client.send_transaction(&tx);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.parse().unwrap());
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("fails".to_string());
|
let rpc_client = RpcClient::new_mock("fails".to_string());
|
||||||
|
|
||||||
@@ -1212,18 +1220,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_signature_status() {
|
fn test_get_signature_status() {
|
||||||
|
let signature = Signature::default();
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("succeeds".to_string());
|
let rpc_client = RpcClient::new_mock("succeeds".to_string());
|
||||||
let signature = "good_signature";
|
|
||||||
let status = rpc_client.get_signature_status(&signature).unwrap();
|
let status = rpc_client.get_signature_status(&signature).unwrap();
|
||||||
assert_eq!(status, Some(Ok(())));
|
assert_eq!(status, Some(Ok(())));
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("sig_not_found".to_string());
|
let rpc_client = RpcClient::new_mock("sig_not_found".to_string());
|
||||||
let signature = "sig_not_found";
|
|
||||||
let status = rpc_client.get_signature_status(&signature).unwrap();
|
let status = rpc_client.get_signature_status(&signature).unwrap();
|
||||||
assert_eq!(status, None);
|
assert_eq!(status, None);
|
||||||
|
|
||||||
let rpc_client = RpcClient::new_mock("account_in_use".to_string());
|
let rpc_client = RpcClient::new_mock("account_in_use".to_string());
|
||||||
let signature = "account_in_use";
|
|
||||||
let status = rpc_client.get_signature_status(&signature).unwrap();
|
let status = rpc_client.get_signature_status(&signature).unwrap();
|
||||||
assert_eq!(status, Some(Err(TransactionError::AccountInUse)));
|
assert_eq!(status, Some(Err(TransactionError::AccountInUse)));
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,6 @@ use thiserror::Error;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum RpcRequest {
|
pub enum RpcRequest {
|
||||||
ConfirmTransaction,
|
|
||||||
DeregisterNode,
|
DeregisterNode,
|
||||||
ValidatorExit,
|
ValidatorExit,
|
||||||
GetAccountInfo,
|
GetAccountInfo,
|
||||||
@@ -22,7 +21,7 @@ pub enum RpcRequest {
|
|||||||
GetRecentBlockhash,
|
GetRecentBlockhash,
|
||||||
GetFeeCalculatorForBlockhash,
|
GetFeeCalculatorForBlockhash,
|
||||||
GetFeeRateGovernor,
|
GetFeeRateGovernor,
|
||||||
GetSignatureStatus,
|
GetSignatureStatuses,
|
||||||
GetSlot,
|
GetSlot,
|
||||||
GetSlotLeader,
|
GetSlotLeader,
|
||||||
GetStorageTurn,
|
GetStorageTurn,
|
||||||
@@ -44,7 +43,6 @@ impl RpcRequest {
|
|||||||
pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value {
|
pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value {
|
||||||
let jsonrpc = "2.0";
|
let jsonrpc = "2.0";
|
||||||
let method = match self {
|
let method = match self {
|
||||||
RpcRequest::ConfirmTransaction => "confirmTransaction",
|
|
||||||
RpcRequest::DeregisterNode => "deregisterNode",
|
RpcRequest::DeregisterNode => "deregisterNode",
|
||||||
RpcRequest::ValidatorExit => "validatorExit",
|
RpcRequest::ValidatorExit => "validatorExit",
|
||||||
RpcRequest::GetAccountInfo => "getAccountInfo",
|
RpcRequest::GetAccountInfo => "getAccountInfo",
|
||||||
@@ -63,7 +61,7 @@ impl RpcRequest {
|
|||||||
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
RpcRequest::GetRecentBlockhash => "getRecentBlockhash",
|
||||||
RpcRequest::GetFeeCalculatorForBlockhash => "getFeeCalculatorForBlockhash",
|
RpcRequest::GetFeeCalculatorForBlockhash => "getFeeCalculatorForBlockhash",
|
||||||
RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
|
RpcRequest::GetFeeRateGovernor => "getFeeRateGovernor",
|
||||||
RpcRequest::GetSignatureStatus => "getSignatureStatus",
|
RpcRequest::GetSignatureStatuses => "getSignatureStatuses",
|
||||||
RpcRequest::GetSlot => "getSlot",
|
RpcRequest::GetSlot => "getSlot",
|
||||||
RpcRequest::GetSlotLeader => "getSlotLeader",
|
RpcRequest::GetSlotLeader => "getSlotLeader",
|
||||||
RpcRequest::GetStorageTurn => "getStorageTurn",
|
RpcRequest::GetStorageTurn => "getStorageTurn",
|
||||||
|
@@ -4,7 +4,7 @@ use solana_sdk::{
|
|||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
transaction::Result,
|
transaction::{Result, TransactionError},
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
||||||
|
|
||||||
@@ -54,6 +54,12 @@ pub struct RpcKeyedAccount {
|
|||||||
pub account: RpcAccount,
|
pub account: RpcAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcSignatureResult {
|
||||||
|
pub err: Option<TransactionError>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A duplicate representation of a Message for pretty JSON serialization
|
/// A duplicate representation of a Message for pretty JSON serialization
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@@ -471,7 +471,7 @@ impl SyncClient for ThinClient {
|
|||||||
) -> TransportResult<Option<transaction::Result<()>>> {
|
) -> TransportResult<Option<transaction::Result<()>>> {
|
||||||
let status = self
|
let status = self
|
||||||
.rpc_client()
|
.rpc_client()
|
||||||
.get_signature_status(&signature.to_string())
|
.get_signature_status(&signature)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
@@ -488,7 +488,7 @@ impl SyncClient for ThinClient {
|
|||||||
) -> TransportResult<Option<transaction::Result<()>>> {
|
) -> TransportResult<Option<transaction::Result<()>>> {
|
||||||
let status = self
|
let status = self
|
||||||
.rpc_client()
|
.rpc_client()
|
||||||
.get_signature_status_with_commitment(&signature.to_string(), commitment_config)
|
.get_signature_status_with_commitment(&signature, commitment_config)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-core"
|
name = "solana-core"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
@@ -43,34 +43,34 @@ regex = "1.3.4"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.0.12" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.0.17" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.0.12" }
|
solana-faucet = { path = "../faucet", version = "1.0.17" }
|
||||||
ed25519-dalek = "=1.0.0-pre.1"
|
ed25519-dalek = "=1.0.0-pre.1"
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.0.12" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-measure = { path = "../measure", version = "1.0.12" }
|
solana-measure = { path = "../measure", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-chacha-cuda = { path = "../chacha-cuda", version = "1.0.12" }
|
solana-chacha-cuda = { path = "../chacha-cuda", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
solana-vote-signer = { path = "../vote-signer", version = "1.0.12" }
|
solana-vote-signer = { path = "../vote-signer", version = "1.0.17" }
|
||||||
solana-sys-tuner = { path = "../sys-tuner", version = "1.0.12" }
|
solana-sys-tuner = { path = "../sys-tuner", version = "1.0.17" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
tokio-fs = "0.1"
|
tokio-fs = "0.1"
|
||||||
tokio-io = "0.1"
|
tokio-io = "0.1"
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.12" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.17" }
|
||||||
trees = "0.2.1"
|
trees = "0.2.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
// hash on gossip. Monitor gossip for messages from validators in the --trusted-validators
|
// hash on gossip. Monitor gossip for messages from validators in the --trusted-validators
|
||||||
// set and halt the node if a mismatch is detected.
|
// set and halt the node if a mismatch is detected.
|
||||||
|
|
||||||
use crate::cluster_info::ClusterInfo;
|
use crate::cluster_info::{ClusterInfo, MAX_SNAPSHOT_HASHES};
|
||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
snapshot_package::SnapshotPackage, snapshot_package::SnapshotPackageReceiver,
|
snapshot_package::SnapshotPackage, snapshot_package::SnapshotPackageReceiver,
|
||||||
snapshot_package::SnapshotPackageSender,
|
snapshot_package::SnapshotPackageSender,
|
||||||
@@ -94,6 +94,10 @@ impl AccountsHashVerifier {
|
|||||||
hashes.push((snapshot_package.root, snapshot_package.hash));
|
hashes.push((snapshot_package.root, snapshot_package.hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while hashes.len() > MAX_SNAPSHOT_HASHES {
|
||||||
|
hashes.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
if halt_on_trusted_validator_accounts_hash_mismatch {
|
if halt_on_trusted_validator_accounts_hash_mismatch {
|
||||||
let mut slot_to_hash = HashMap::new();
|
let mut slot_to_hash = HashMap::new();
|
||||||
for (slot, hash) in hashes.iter() {
|
for (slot, hash) in hashes.iter() {
|
||||||
@@ -119,6 +123,7 @@ impl AccountsHashVerifier {
|
|||||||
slot_to_hash: &mut HashMap<Slot, Hash>,
|
slot_to_hash: &mut HashMap<Slot, Hash>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut verified_count = 0;
|
let mut verified_count = 0;
|
||||||
|
let mut highest_slot = 0;
|
||||||
if let Some(trusted_validators) = trusted_validators.as_ref() {
|
if let Some(trusted_validators) = trusted_validators.as_ref() {
|
||||||
for trusted_validator in trusted_validators {
|
for trusted_validator in trusted_validators {
|
||||||
let cluster_info_r = cluster_info.read().unwrap();
|
let cluster_info_r = cluster_info.read().unwrap();
|
||||||
@@ -140,6 +145,7 @@ impl AccountsHashVerifier {
|
|||||||
verified_count += 1;
|
verified_count += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
highest_slot = std::cmp::max(*slot, highest_slot);
|
||||||
slot_to_hash.insert(*slot, *hash);
|
slot_to_hash.insert(*slot, *hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,10 @@ impl AccountsHashVerifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inc_new_counter_info!("accounts_hash_verifier-hashes_verified", verified_count);
|
inc_new_counter_info!("accounts_hash_verifier-hashes_verified", verified_count);
|
||||||
|
datapoint_info!(
|
||||||
|
"accounts_hash_verifier",
|
||||||
|
("highest_slot_verified", highest_slot, i64),
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,4 +207,57 @@ mod tests {
|
|||||||
&mut slot_to_hash,
|
&mut slot_to_hash,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max_hashes() {
|
||||||
|
solana_logger::setup();
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
let keypair = Keypair::new();
|
||||||
|
|
||||||
|
let contact_info = ContactInfo::new_localhost(&keypair.pubkey(), 0);
|
||||||
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(contact_info);
|
||||||
|
let cluster_info = Arc::new(RwLock::new(cluster_info));
|
||||||
|
|
||||||
|
let trusted_validators = HashSet::new();
|
||||||
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
let mut hashes = vec![];
|
||||||
|
for i in 0..MAX_SNAPSHOT_HASHES + 1 {
|
||||||
|
let snapshot_links = TempDir::new().unwrap();
|
||||||
|
let snapshot_package = SnapshotPackage {
|
||||||
|
hash: hash(&[i as u8]),
|
||||||
|
root: 100 + i as u64,
|
||||||
|
slot_deltas: vec![],
|
||||||
|
snapshot_links,
|
||||||
|
tar_output_file: PathBuf::from("."),
|
||||||
|
storages: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
AccountsHashVerifier::process_snapshot(
|
||||||
|
snapshot_package,
|
||||||
|
&cluster_info,
|
||||||
|
&Some(trusted_validators.clone()),
|
||||||
|
false,
|
||||||
|
&None,
|
||||||
|
&mut hashes,
|
||||||
|
&exit,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let cluster_info_r = cluster_info.read().unwrap();
|
||||||
|
let cluster_hashes = cluster_info_r
|
||||||
|
.get_accounts_hash_for_node(&keypair.pubkey())
|
||||||
|
.unwrap();
|
||||||
|
info!("{:?}", cluster_hashes);
|
||||||
|
assert_eq!(hashes.len(), MAX_SNAPSHOT_HASHES);
|
||||||
|
assert_eq!(cluster_hashes.len(), MAX_SNAPSHOT_HASHES);
|
||||||
|
assert_eq!(cluster_hashes[0], (101, hash(&[1])));
|
||||||
|
assert_eq!(
|
||||||
|
cluster_hashes[MAX_SNAPSHOT_HASHES - 1],
|
||||||
|
(
|
||||||
|
100 + MAX_SNAPSHOT_HASHES as u64,
|
||||||
|
hash(&[MAX_SNAPSHOT_HASHES as u8])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1980,10 +1980,20 @@ mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == success_signature.to_string() {
|
if transaction.signatures[0] == success_signature.to_string() {
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
let meta = meta.unwrap();
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
|
assert_eq!(meta.status, Ok(()));
|
||||||
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
} else if transaction.signatures[0] == ix_error_signature.to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
|
use crate::consensus::VOTE_THRESHOLD_SIZE;
|
||||||
|
use solana_measure::measure::Measure;
|
||||||
|
use solana_metrics::inc_new_counter_info;
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::clock::Slot;
|
use solana_sdk::clock::Slot;
|
||||||
use solana_vote_program::{vote_state::VoteState, vote_state::MAX_LOCKOUT_HISTORY};
|
use solana_vote_program::{vote_state::VoteState, vote_state::MAX_LOCKOUT_HISTORY};
|
||||||
@@ -31,17 +34,40 @@ impl BlockCommitment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Default)]
|
||||||
pub struct BlockCommitmentCache {
|
pub struct BlockCommitmentCache {
|
||||||
block_commitment: HashMap<Slot, BlockCommitment>,
|
block_commitment: HashMap<Slot, BlockCommitment>,
|
||||||
total_stake: u64,
|
total_stake: u64,
|
||||||
|
bank: Arc<Bank>,
|
||||||
|
root: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for BlockCommitmentCache {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("BlockCommitmentCache")
|
||||||
|
.field("block_commitment", &self.block_commitment)
|
||||||
|
.field("total_stake", &self.total_stake)
|
||||||
|
.field(
|
||||||
|
"bank",
|
||||||
|
&format_args!("Bank({{current_slot: {:?}}})", self.bank.slot()),
|
||||||
|
)
|
||||||
|
.field("root", &self.root)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockCommitmentCache {
|
impl BlockCommitmentCache {
|
||||||
pub fn new(block_commitment: HashMap<Slot, BlockCommitment>, total_stake: u64) -> Self {
|
pub fn new(
|
||||||
|
block_commitment: HashMap<Slot, BlockCommitment>,
|
||||||
|
total_stake: u64,
|
||||||
|
bank: Arc<Bank>,
|
||||||
|
root: Slot,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
block_commitment,
|
block_commitment,
|
||||||
total_stake,
|
total_stake,
|
||||||
|
bank,
|
||||||
|
root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,38 +79,62 @@ impl BlockCommitmentCache {
|
|||||||
self.total_stake
|
self.total_stake
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_with_depth_commitment(
|
pub fn bank(&self) -> Arc<Bank> {
|
||||||
&self,
|
self.bank.clone()
|
||||||
minimum_depth: usize,
|
|
||||||
minimum_stake_percentage: f64,
|
|
||||||
) -> Option<Slot> {
|
|
||||||
self.block_commitment
|
|
||||||
.iter()
|
|
||||||
.filter(|&(_, block_commitment)| {
|
|
||||||
let fork_stake_minimum_depth: u64 = block_commitment.commitment[minimum_depth..]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.sum();
|
|
||||||
fork_stake_minimum_depth as f64 / self.total_stake as f64
|
|
||||||
>= minimum_stake_percentage
|
|
||||||
})
|
|
||||||
.map(|(slot, _)| *slot)
|
|
||||||
.max()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rooted_block_with_commitment(&self, minimum_stake_percentage: f64) -> Option<u64> {
|
pub fn slot(&self) -> Slot {
|
||||||
self.get_block_with_depth_commitment(MAX_LOCKOUT_HISTORY - 1, minimum_stake_percentage)
|
self.bank.slot()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root(&self) -> Slot {
|
||||||
|
self.root
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmation_count(&self, slot: Slot) -> Option<usize> {
|
||||||
|
self.get_lockout_count(slot, VOTE_THRESHOLD_SIZE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the lowest level at which at least `minimum_stake_percentage` of the total epoch
|
||||||
|
// stake is locked out
|
||||||
|
fn get_lockout_count(&self, slot: Slot, minimum_stake_percentage: f64) -> Option<usize> {
|
||||||
|
self.get_block_commitment(slot).map(|block_commitment| {
|
||||||
|
let iterator = block_commitment.commitment.iter().enumerate().rev();
|
||||||
|
let mut sum = 0;
|
||||||
|
for (i, stake) in iterator {
|
||||||
|
sum += stake;
|
||||||
|
if (sum as f64 / self.total_stake as f64) > minimum_stake_percentage {
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn new_for_tests() -> Self {
|
||||||
|
let mut block_commitment: HashMap<Slot, BlockCommitment> = HashMap::new();
|
||||||
|
block_commitment.insert(0, BlockCommitment::default());
|
||||||
|
Self {
|
||||||
|
block_commitment,
|
||||||
|
total_stake: 42,
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommitmentAggregationData {
|
pub struct CommitmentAggregationData {
|
||||||
bank: Arc<Bank>,
|
bank: Arc<Bank>,
|
||||||
|
root: Slot,
|
||||||
total_staked: u64,
|
total_staked: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitmentAggregationData {
|
impl CommitmentAggregationData {
|
||||||
pub fn new(bank: Arc<Bank>, total_staked: u64) -> Self {
|
pub fn new(bank: Arc<Bank>, root: Slot, total_staked: u64) -> Self {
|
||||||
Self { bank, total_staked }
|
Self {
|
||||||
|
bank,
|
||||||
|
root,
|
||||||
|
total_staked,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +194,24 @@ impl AggregateCommitmentService {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut aggregate_commitment_time = Measure::start("aggregate-commitment-ms");
|
||||||
let block_commitment = Self::aggregate_commitment(&ancestors, &aggregation_data.bank);
|
let block_commitment = Self::aggregate_commitment(&ancestors, &aggregation_data.bank);
|
||||||
|
|
||||||
let mut new_block_commitment =
|
let mut new_block_commitment = BlockCommitmentCache::new(
|
||||||
BlockCommitmentCache::new(block_commitment, aggregation_data.total_staked);
|
block_commitment,
|
||||||
|
aggregation_data.total_staked,
|
||||||
|
aggregation_data.bank,
|
||||||
|
aggregation_data.root,
|
||||||
|
);
|
||||||
|
|
||||||
let mut w_block_commitment_cache = block_commitment_cache.write().unwrap();
|
let mut w_block_commitment_cache = block_commitment_cache.write().unwrap();
|
||||||
|
|
||||||
std::mem::swap(&mut *w_block_commitment_cache, &mut new_block_commitment);
|
std::mem::swap(&mut *w_block_commitment_cache, &mut new_block_commitment);
|
||||||
|
aggregate_commitment_time.stop();
|
||||||
|
inc_new_counter_info!(
|
||||||
|
"aggregate-commitment-ms",
|
||||||
|
aggregate_commitment_time.as_ms() as usize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,84 +306,31 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_block_with_depth_commitment() {
|
fn test_get_confirmations() {
|
||||||
|
let bank = Arc::new(Bank::default());
|
||||||
// Build BlockCommitmentCache with votes at depths 0 and 1 for 2 slots
|
// Build BlockCommitmentCache with votes at depths 0 and 1 for 2 slots
|
||||||
let mut cache0 = BlockCommitment::default();
|
let mut cache0 = BlockCommitment::default();
|
||||||
cache0.increase_confirmation_stake(1, 15);
|
cache0.increase_confirmation_stake(1, 5);
|
||||||
cache0.increase_confirmation_stake(2, 25);
|
cache0.increase_confirmation_stake(2, 40);
|
||||||
|
|
||||||
let mut cache1 = BlockCommitment::default();
|
let mut cache1 = BlockCommitment::default();
|
||||||
cache1.increase_confirmation_stake(1, 10);
|
cache1.increase_confirmation_stake(1, 40);
|
||||||
cache1.increase_confirmation_stake(2, 20);
|
cache1.increase_confirmation_stake(2, 5);
|
||||||
|
|
||||||
|
let mut cache2 = BlockCommitment::default();
|
||||||
|
cache2.increase_confirmation_stake(1, 20);
|
||||||
|
cache2.increase_confirmation_stake(2, 5);
|
||||||
|
|
||||||
let mut block_commitment = HashMap::new();
|
let mut block_commitment = HashMap::new();
|
||||||
block_commitment.entry(0).or_insert(cache0.clone());
|
block_commitment.entry(0).or_insert(cache0.clone());
|
||||||
block_commitment.entry(1).or_insert(cache1.clone());
|
block_commitment.entry(1).or_insert(cache1.clone());
|
||||||
let block_commitment_cache = BlockCommitmentCache::new(block_commitment, 50);
|
block_commitment.entry(2).or_insert(cache2.clone());
|
||||||
|
let block_commitment_cache = BlockCommitmentCache::new(block_commitment, 50, bank, 0);
|
||||||
|
|
||||||
// Neither slot has rooted votes
|
assert_eq!(block_commitment_cache.get_confirmation_count(0), Some(2));
|
||||||
assert_eq!(
|
assert_eq!(block_commitment_cache.get_confirmation_count(1), Some(1));
|
||||||
block_commitment_cache.get_rooted_block_with_commitment(0.1),
|
assert_eq!(block_commitment_cache.get_confirmation_count(2), Some(0),);
|
||||||
None
|
assert_eq!(block_commitment_cache.get_confirmation_count(3), None,);
|
||||||
);
|
|
||||||
// Neither slot meets the minimum level of commitment 0.6 at depth 1
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_block_with_depth_commitment(1, 0.6),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
// Only slot 0 meets the minimum level of commitment 0.5 at depth 1
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_block_with_depth_commitment(1, 0.5),
|
|
||||||
Some(0)
|
|
||||||
);
|
|
||||||
// If multiple slots meet the minimum level of commitment, method should return the most recent
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_block_with_depth_commitment(1, 0.4),
|
|
||||||
Some(1)
|
|
||||||
);
|
|
||||||
// If multiple slots meet the minimum level of commitment, method should return the most recent
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_block_with_depth_commitment(0, 0.6),
|
|
||||||
Some(1)
|
|
||||||
);
|
|
||||||
// Neither slot meets the minimum level of commitment 0.9 at depth 0
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_block_with_depth_commitment(0, 0.9),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_rooted_block_with_commitment() {
|
|
||||||
// Build BlockCommitmentCache with rooted votes
|
|
||||||
let mut cache0 = BlockCommitment::new([0; MAX_LOCKOUT_HISTORY]);
|
|
||||||
cache0.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, 40);
|
|
||||||
cache0.increase_confirmation_stake(MAX_LOCKOUT_HISTORY - 1, 10);
|
|
||||||
let mut cache1 = BlockCommitment::new([0; MAX_LOCKOUT_HISTORY]);
|
|
||||||
cache1.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, 30);
|
|
||||||
cache1.increase_confirmation_stake(MAX_LOCKOUT_HISTORY - 1, 10);
|
|
||||||
cache1.increase_confirmation_stake(MAX_LOCKOUT_HISTORY - 2, 10);
|
|
||||||
|
|
||||||
let mut block_commitment = HashMap::new();
|
|
||||||
block_commitment.entry(0).or_insert(cache0.clone());
|
|
||||||
block_commitment.entry(1).or_insert(cache1.clone());
|
|
||||||
let block_commitment_cache = BlockCommitmentCache::new(block_commitment, 50);
|
|
||||||
|
|
||||||
// Only slot 0 meets the minimum level of commitment 0.66 at root
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_rooted_block_with_commitment(0.66),
|
|
||||||
Some(0)
|
|
||||||
);
|
|
||||||
// If multiple slots meet the minimum level of commitment, method should return the most recent
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_rooted_block_with_commitment(0.6),
|
|
||||||
Some(1)
|
|
||||||
);
|
|
||||||
// Neither slot meets the minimum level of commitment 0.9 at root
|
|
||||||
assert_eq!(
|
|
||||||
block_commitment_cache.get_rooted_block_with_commitment(0.9),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@@ -13,15 +13,18 @@ use std::thread;
|
|||||||
use std::thread::{Builder, JoinHandle};
|
use std::thread::{Builder, JoinHandle};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// - To try and keep the RocksDB size under 512GB:
|
// - To try and keep the RocksDB size under 400GB:
|
||||||
// Seeing about 1600b/shred, using 2000b/shred for margin, so 250m shreds can be stored in 512gb.
|
// Seeing about 1600b/shred, using 2000b/shred for margin, so 200m shreds can be stored in 400gb.
|
||||||
// at 5k shreds/slot at 50k tps, this is 500k slots (~5.5 hours).
|
// at 5k shreds/slot at 50k tps, this is 500k slots (~5 hours).
|
||||||
// At idle, 60 shreds/slot this is about 4m slots (18 days)
|
// At idle, 60 shreds/slot this is about 4m slots (18 days)
|
||||||
// This is chosen to allow enough time for
|
// This is chosen to allow enough time for
|
||||||
// - A validator to download a snapshot from a peer and boot from it
|
// - A validator to download a snapshot from a peer and boot from it
|
||||||
// - To make sure that if a validator needs to reboot from its own snapshot, it has enough slots locally
|
// - To make sure that if a validator needs to reboot from its own snapshot, it has enough slots locally
|
||||||
// to catch back up to where it was when it stopped
|
// to catch back up to where it was when it stopped
|
||||||
pub const DEFAULT_MAX_LEDGER_SHREDS: u64 = 250_000_000;
|
pub const DEFAULT_MAX_LEDGER_SHREDS: u64 = 200_000_000;
|
||||||
|
|
||||||
|
// Allow down to 50m, or 3.5 days at idle, 1hr at 50k load, around ~100GB
|
||||||
|
pub const DEFAULT_MIN_MAX_LEDGER_SHREDS: u64 = 50_000_000;
|
||||||
|
|
||||||
// Check for removing slots at this interval so we don't purge too often
|
// Check for removing slots at this interval so we don't purge too often
|
||||||
// and starve other blockstore users.
|
// and starve other blockstore users.
|
||||||
|
@@ -26,6 +26,7 @@ use solana_metrics::inc_new_counter_info;
|
|||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::Slot,
|
clock::Slot,
|
||||||
|
genesis_config::GenesisConfig,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
@@ -80,6 +81,7 @@ pub struct ReplayStageConfig {
|
|||||||
pub block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
pub block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
pub transaction_status_sender: Option<TransactionStatusSender>,
|
pub transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
pub rewards_recorder_sender: Option<RewardsRecorderSender>,
|
pub rewards_recorder_sender: Option<RewardsRecorderSender>,
|
||||||
|
pub genesis_config: GenesisConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReplayStage {
|
pub struct ReplayStage {
|
||||||
@@ -183,6 +185,7 @@ impl ReplayStage {
|
|||||||
block_commitment_cache,
|
block_commitment_cache,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
rewards_recorder_sender,
|
rewards_recorder_sender,
|
||||||
|
genesis_config,
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
let (root_bank_sender, root_bank_receiver) = channel();
|
let (root_bank_sender, root_bank_receiver) = channel();
|
||||||
@@ -192,7 +195,7 @@ impl ReplayStage {
|
|||||||
// Start the replay stage loop
|
// Start the replay stage loop
|
||||||
|
|
||||||
let (lockouts_sender, commitment_service) =
|
let (lockouts_sender, commitment_service) =
|
||||||
AggregateCommitmentService::new(&exit, block_commitment_cache);
|
AggregateCommitmentService::new(&exit, block_commitment_cache.clone());
|
||||||
|
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
let t_replay = Builder::new()
|
let t_replay = Builder::new()
|
||||||
@@ -246,6 +249,7 @@ impl ReplayStage {
|
|||||||
&slot_full_senders,
|
&slot_full_senders,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
&verify_recyclers,
|
&verify_recyclers,
|
||||||
|
&genesis_config,
|
||||||
);
|
);
|
||||||
datapoint_debug!(
|
datapoint_debug!(
|
||||||
"replay_stage-memory",
|
"replay_stage-memory",
|
||||||
@@ -309,7 +313,10 @@ impl ReplayStage {
|
|||||||
let start = allocated.get();
|
let start = allocated.get();
|
||||||
if !is_locked_out && vote_threshold {
|
if !is_locked_out && vote_threshold {
|
||||||
info!("voting: {} {}", bank.slot(), fork_weight);
|
info!("voting: {} {}", bank.slot(), fork_weight);
|
||||||
subscriptions.notify_subscribers(bank.slot(), &bank_forks);
|
subscriptions.notify_subscribers(
|
||||||
|
block_commitment_cache.read().unwrap().slot(),
|
||||||
|
&bank_forks,
|
||||||
|
);
|
||||||
if let Some(votable_leader) =
|
if let Some(votable_leader) =
|
||||||
leader_schedule_cache.slot_leader_at(bank.slot(), Some(&bank))
|
leader_schedule_cache.slot_leader_at(bank.slot(), Some(&bank))
|
||||||
{
|
{
|
||||||
@@ -548,6 +555,7 @@ impl ReplayStage {
|
|||||||
bank_progress: &mut ForkProgress,
|
bank_progress: &mut ForkProgress,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
verify_recyclers: &VerifyRecyclers,
|
verify_recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: &GenesisConfig,
|
||||||
) -> result::Result<usize, BlockstoreProcessorError> {
|
) -> result::Result<usize, BlockstoreProcessorError> {
|
||||||
let tx_count_before = bank_progress.replay_progress.num_txs;
|
let tx_count_before = bank_progress.replay_progress.num_txs;
|
||||||
let confirm_result = blockstore_processor::confirm_slot(
|
let confirm_result = blockstore_processor::confirm_slot(
|
||||||
@@ -559,6 +567,7 @@ impl ReplayStage {
|
|||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
None,
|
None,
|
||||||
verify_recyclers,
|
verify_recyclers,
|
||||||
|
Some(genesis_config),
|
||||||
);
|
);
|
||||||
let tx_count_after = bank_progress.replay_progress.num_txs;
|
let tx_count_after = bank_progress.replay_progress.num_txs;
|
||||||
let tx_count = tx_count_after - tx_count_before;
|
let tx_count = tx_count_after - tx_count_before;
|
||||||
@@ -647,7 +656,13 @@ impl ReplayStage {
|
|||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::update_commitment_cache(bank.clone(), total_staked, lockouts_sender);
|
|
||||||
|
Self::update_commitment_cache(
|
||||||
|
bank.clone(),
|
||||||
|
bank_forks.read().unwrap().root(),
|
||||||
|
total_staked,
|
||||||
|
lockouts_sender,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(ref voting_keypair) = voting_keypair {
|
if let Some(ref voting_keypair) = voting_keypair {
|
||||||
let node_keypair = cluster_info.read().unwrap().keypair.clone();
|
let node_keypair = cluster_info.read().unwrap().keypair.clone();
|
||||||
@@ -675,10 +690,13 @@ impl ReplayStage {
|
|||||||
|
|
||||||
fn update_commitment_cache(
|
fn update_commitment_cache(
|
||||||
bank: Arc<Bank>,
|
bank: Arc<Bank>,
|
||||||
|
root: Slot,
|
||||||
total_staked: u64,
|
total_staked: u64,
|
||||||
lockouts_sender: &Sender<CommitmentAggregationData>,
|
lockouts_sender: &Sender<CommitmentAggregationData>,
|
||||||
) {
|
) {
|
||||||
if let Err(e) = lockouts_sender.send(CommitmentAggregationData::new(bank, total_staked)) {
|
if let Err(e) =
|
||||||
|
lockouts_sender.send(CommitmentAggregationData::new(bank, root, total_staked))
|
||||||
|
{
|
||||||
trace!("lockouts_sender failed: {:?}", e);
|
trace!("lockouts_sender failed: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -725,6 +743,7 @@ impl ReplayStage {
|
|||||||
slot_full_senders: &[Sender<(u64, Pubkey)>],
|
slot_full_senders: &[Sender<(u64, Pubkey)>],
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
verify_recyclers: &VerifyRecyclers,
|
verify_recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: &GenesisConfig,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut did_complete_bank = false;
|
let mut did_complete_bank = false;
|
||||||
let mut tx_count = 0;
|
let mut tx_count = 0;
|
||||||
@@ -753,6 +772,7 @@ impl ReplayStage {
|
|||||||
bank_progress,
|
bank_progress,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
verify_recyclers,
|
verify_recyclers,
|
||||||
|
genesis_config,
|
||||||
);
|
);
|
||||||
match replay_result {
|
match replay_result {
|
||||||
Ok(replay_tx_count) => tx_count += replay_tx_count,
|
Ok(replay_tx_count) => tx_count += replay_tx_count,
|
||||||
@@ -1397,7 +1417,10 @@ pub(crate) mod tests {
|
|||||||
let bank0 = Bank::new(&genesis_config);
|
let bank0 = Bank::new(&genesis_config);
|
||||||
let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank0));
|
let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank0));
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
|
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
||||||
|
));
|
||||||
let bank_forks = BankForks::new(0, bank0);
|
let bank_forks = BankForks::new(0, bank0);
|
||||||
bank_forks.working_bank().freeze();
|
bank_forks.working_bank().freeze();
|
||||||
|
|
||||||
@@ -1694,6 +1717,7 @@ pub(crate) mod tests {
|
|||||||
&mut bank0_progress,
|
&mut bank0_progress,
|
||||||
None,
|
None,
|
||||||
&VerifyRecyclers::default(),
|
&VerifyRecyclers::default(),
|
||||||
|
&genesis_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check that the erroring bank was marked as dead in the progress map
|
// Check that the erroring bank was marked as dead in the progress map
|
||||||
@@ -1766,7 +1790,12 @@ pub(crate) mod tests {
|
|||||||
bank_forks.write().unwrap().insert(bank1);
|
bank_forks.write().unwrap().insert(bank1);
|
||||||
let arc_bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
|
let arc_bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
|
||||||
leader_vote(&arc_bank1, &leader_voting_pubkey);
|
leader_vote(&arc_bank1, &leader_voting_pubkey);
|
||||||
ReplayStage::update_commitment_cache(arc_bank1.clone(), leader_lamports, &lockouts_sender);
|
ReplayStage::update_commitment_cache(
|
||||||
|
arc_bank1.clone(),
|
||||||
|
0,
|
||||||
|
leader_lamports,
|
||||||
|
&lockouts_sender,
|
||||||
|
);
|
||||||
|
|
||||||
let bank2 = Bank::new_from_parent(&arc_bank1, &Pubkey::default(), arc_bank1.slot() + 1);
|
let bank2 = Bank::new_from_parent(&arc_bank1, &Pubkey::default(), arc_bank1.slot() + 1);
|
||||||
let _res = bank2.transfer(10, &genesis_config_info.mint_keypair, &Pubkey::new_rand());
|
let _res = bank2.transfer(10, &genesis_config_info.mint_keypair, &Pubkey::new_rand());
|
||||||
@@ -1777,7 +1806,12 @@ pub(crate) mod tests {
|
|||||||
bank_forks.write().unwrap().insert(bank2);
|
bank_forks.write().unwrap().insert(bank2);
|
||||||
let arc_bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
let arc_bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
|
||||||
leader_vote(&arc_bank2, &leader_voting_pubkey);
|
leader_vote(&arc_bank2, &leader_voting_pubkey);
|
||||||
ReplayStage::update_commitment_cache(arc_bank2.clone(), leader_lamports, &lockouts_sender);
|
ReplayStage::update_commitment_cache(
|
||||||
|
arc_bank2.clone(),
|
||||||
|
0,
|
||||||
|
leader_lamports,
|
||||||
|
&lockouts_sender,
|
||||||
|
);
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(200));
|
||||||
|
|
||||||
let mut expected0 = BlockCommitment::default();
|
let mut expected0 = BlockCommitment::default();
|
||||||
@@ -1907,10 +1941,20 @@ pub(crate) mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == signatures[0].to_string() {
|
if transaction.signatures[0] == signatures[0].to_string() {
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
let meta = meta.unwrap();
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
|
assert_eq!(meta.status, Ok(()));
|
||||||
} else if transaction.signatures[0] == signatures[1].to_string() {
|
} else if transaction.signatures[0] == signatures[1].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
439
core/src/rpc.rs
439
core/src/rpc.rs
@@ -12,7 +12,7 @@ use solana_faucet::faucet::request_airdrop_transaction;
|
|||||||
use solana_ledger::{
|
use solana_ledger::{
|
||||||
bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator,
|
bank_forks::BankForks, blockstore::Blockstore, rooted_slot_iterator::RootedSlotIterator,
|
||||||
};
|
};
|
||||||
use solana_runtime::{bank::Bank, status_cache::SignatureConfirmationStatus};
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, UnixTimestamp},
|
clock::{Slot, UnixTimestamp},
|
||||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||||
@@ -22,9 +22,11 @@ use solana_sdk::{
|
|||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
timing::slot_duration_from_slots_per_year,
|
timing::slot_duration_from_slots_per_year,
|
||||||
transaction::Transaction,
|
transaction::{self, Transaction},
|
||||||
|
};
|
||||||
|
use solana_transaction_status::{
|
||||||
|
ConfirmedBlock, ConfirmedTransaction, TransactionEncoding, TransactionStatus,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{ConfirmedBlock, TransactionEncoding, TransactionStatus};
|
|
||||||
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -35,6 +37,9 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAX_QUERY_ITEMS: usize = 256;
|
||||||
|
const MAX_SLOT_RANGE: u64 = 10_000;
|
||||||
|
|
||||||
type RpcResponse<T> = Result<Response<T>>;
|
type RpcResponse<T> = Result<Response<T>>;
|
||||||
|
|
||||||
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
|
||||||
@@ -51,6 +56,15 @@ pub struct JsonRpcConfig {
|
|||||||
pub faucet_addr: Option<SocketAddr>,
|
pub faucet_addr: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcSignatureStatusConfig {
|
||||||
|
pub search_transaction_history: Option<bool>,
|
||||||
|
// DEPRECATED
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub commitment: Option<CommitmentConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct JsonRpcRequestProcessor {
|
pub struct JsonRpcRequestProcessor {
|
||||||
bank_forks: Arc<RwLock<BankForks>>,
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
@@ -195,11 +209,9 @@ impl JsonRpcRequestProcessor {
|
|||||||
match signature {
|
match signature {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(sig) => {
|
Ok(sig) => {
|
||||||
let status = bank.get_signature_confirmation_status(&sig);
|
let status = bank.get_signature_status(&sig);
|
||||||
match status {
|
match status {
|
||||||
Some(SignatureConfirmationStatus { status, .. }) => {
|
Some(status) => new_response(bank, status.is_ok()),
|
||||||
new_response(bank, status.is_ok())
|
|
||||||
}
|
|
||||||
None => new_response(bank, false),
|
None => new_response(bank, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,31 +410,69 @@ impl JsonRpcRequestProcessor {
|
|||||||
.unwrap_or(None))
|
.unwrap_or(None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_signature_confirmation_status(
|
||||||
|
&self,
|
||||||
|
signature: Signature,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Option<RpcSignatureConfirmation> {
|
||||||
|
self.get_transaction_status(signature, &self.bank(commitment))
|
||||||
|
.map(
|
||||||
|
|TransactionStatus {
|
||||||
|
status,
|
||||||
|
confirmations,
|
||||||
|
..
|
||||||
|
}| RpcSignatureConfirmation {
|
||||||
|
confirmations: confirmations.unwrap_or(MAX_LOCKOUT_HISTORY + 1),
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_signature_status(
|
pub fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
signatures: Vec<Signature>,
|
signature: Signature,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Option<transaction::Result<()>> {
|
||||||
|
self.bank(commitment).get_signature_status(&signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_signature_statuses(
|
||||||
|
&self,
|
||||||
|
signatures: Vec<Signature>,
|
||||||
|
config: Option<RpcSignatureStatusConfig>,
|
||||||
) -> RpcResponse<Vec<Option<TransactionStatus>>> {
|
) -> RpcResponse<Vec<Option<TransactionStatus>>> {
|
||||||
let mut statuses: Vec<Option<TransactionStatus>> = vec![];
|
let mut statuses: Vec<Option<TransactionStatus>> = vec![];
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
let commitment = config
|
||||||
|
.clone()
|
||||||
|
.and_then(|x| x.commitment)
|
||||||
|
.or_else(|| Some(CommitmentConfig::recent()));
|
||||||
|
|
||||||
|
let search_transaction_history = config
|
||||||
|
.and_then(|x| x.search_transaction_history)
|
||||||
|
.unwrap_or(false);
|
||||||
let bank = self.bank(commitment);
|
let bank = self.bank(commitment);
|
||||||
|
|
||||||
for signature in signatures {
|
for signature in signatures {
|
||||||
let status = bank.get_signature_confirmation_status(&signature).map(
|
let status = if let Some(status) = self.get_transaction_status(signature, &bank) {
|
||||||
|SignatureConfirmationStatus {
|
Some(status)
|
||||||
slot,
|
} else if self.config.enable_rpc_transaction_history && search_transaction_history {
|
||||||
status,
|
self.blockstore
|
||||||
confirmations,
|
.get_transaction_status(signature)
|
||||||
}| TransactionStatus {
|
.map_err(|_| Error::internal_error())?
|
||||||
slot,
|
.map(|(slot, status_meta)| {
|
||||||
status,
|
let err = status_meta.status.clone().err();
|
||||||
confirmations: if confirmations <= MAX_LOCKOUT_HISTORY {
|
TransactionStatus {
|
||||||
Some(confirmations)
|
slot,
|
||||||
} else {
|
status: status_meta.status,
|
||||||
None
|
confirmations: None,
|
||||||
},
|
err,
|
||||||
},
|
}
|
||||||
);
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
statuses.push(status);
|
statuses.push(status);
|
||||||
}
|
}
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
@@ -430,6 +480,63 @@ impl JsonRpcRequestProcessor {
|
|||||||
value: statuses,
|
value: statuses,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_transaction_status(
|
||||||
|
&self,
|
||||||
|
signature: Signature,
|
||||||
|
bank: &Arc<Bank>,
|
||||||
|
) -> Option<TransactionStatus> {
|
||||||
|
bank.get_signature_status_slot(&signature)
|
||||||
|
.map(|(slot, status)| {
|
||||||
|
let r_block_commitment_cache = self.block_commitment_cache.read().unwrap();
|
||||||
|
|
||||||
|
let confirmations = if r_block_commitment_cache.root() >= slot {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
r_block_commitment_cache
|
||||||
|
.get_confirmation_count(slot)
|
||||||
|
.or(Some(0))
|
||||||
|
};
|
||||||
|
let err = status.clone().err();
|
||||||
|
TransactionStatus {
|
||||||
|
slot,
|
||||||
|
status,
|
||||||
|
confirmations,
|
||||||
|
err,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_transaction(
|
||||||
|
&self,
|
||||||
|
signature: Signature,
|
||||||
|
encoding: Option<TransactionEncoding>,
|
||||||
|
) -> Result<Option<ConfirmedTransaction>> {
|
||||||
|
if self.config.enable_rpc_transaction_history {
|
||||||
|
Ok(self
|
||||||
|
.blockstore
|
||||||
|
.get_confirmed_transaction(signature, encoding)
|
||||||
|
.unwrap_or(None))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
pubkey: Pubkey,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<Signature>> {
|
||||||
|
if self.config.enable_rpc_transaction_history {
|
||||||
|
Ok(self
|
||||||
|
.blockstore
|
||||||
|
.get_confirmed_signatures_for_address(pubkey, start_slot, end_slot)
|
||||||
|
.unwrap_or_else(|_| vec![]))
|
||||||
|
} else {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
||||||
@@ -457,6 +564,7 @@ impl Metadata for Meta {}
|
|||||||
pub trait RpcSol {
|
pub trait RpcSol {
|
||||||
type Metadata;
|
type Metadata;
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
#[rpc(meta, name = "confirmTransaction")]
|
#[rpc(meta, name = "confirmTransaction")]
|
||||||
fn confirm_transaction(
|
fn confirm_transaction(
|
||||||
&self,
|
&self,
|
||||||
@@ -465,6 +573,24 @@ pub trait RpcSol {
|
|||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
) -> RpcResponse<bool>;
|
) -> RpcResponse<bool>;
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
#[rpc(meta, name = "getSignatureStatus")]
|
||||||
|
fn get_signature_status(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_str: String,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Option<transaction::Result<()>>>;
|
||||||
|
|
||||||
|
// DEPRECATED (used by Trust Wallet)
|
||||||
|
#[rpc(meta, name = "getSignatureConfirmation")]
|
||||||
|
fn get_signature_confirmation(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_str: String,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Option<RpcSignatureConfirmation>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getAccountInfo")]
|
#[rpc(meta, name = "getAccountInfo")]
|
||||||
fn get_account_info(
|
fn get_account_info(
|
||||||
&self,
|
&self,
|
||||||
@@ -552,12 +678,12 @@ pub trait RpcSol {
|
|||||||
#[rpc(meta, name = "getFeeRateGovernor")]
|
#[rpc(meta, name = "getFeeRateGovernor")]
|
||||||
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor>;
|
fn get_fee_rate_governor(&self, meta: Self::Metadata) -> RpcResponse<RpcFeeRateGovernor>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSignatureStatus")]
|
#[rpc(meta, name = "getSignatureStatuses")]
|
||||||
fn get_signature_status(
|
fn get_signature_statuses(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_strs: Vec<String>,
|
signature_strs: Vec<String>,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcSignatureStatusConfig>,
|
||||||
) -> RpcResponse<Vec<Option<TransactionStatus>>>;
|
) -> RpcResponse<Vec<Option<TransactionStatus>>>;
|
||||||
|
|
||||||
#[rpc(meta, name = "getSlot")]
|
#[rpc(meta, name = "getSlot")]
|
||||||
@@ -652,6 +778,23 @@ pub trait RpcSol {
|
|||||||
start_slot: Slot,
|
start_slot: Slot,
|
||||||
end_slot: Option<Slot>,
|
end_slot: Option<Slot>,
|
||||||
) -> Result<Vec<Slot>>;
|
) -> Result<Vec<Slot>>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getConfirmedTransaction")]
|
||||||
|
fn get_confirmed_transaction(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_str: String,
|
||||||
|
encoding: Option<TransactionEncoding>,
|
||||||
|
) -> Result<Option<ConfirmedTransaction>>;
|
||||||
|
|
||||||
|
#[rpc(meta, name = "getConfirmedSignaturesForAddress")]
|
||||||
|
fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
pubkey_str: String,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<String>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RpcSolImpl;
|
pub struct RpcSolImpl;
|
||||||
@@ -883,12 +1026,50 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.get_fee_rate_governor()
|
.get_fee_rate_governor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_signature_confirmation(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_str: String,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Option<RpcSignatureConfirmation>> {
|
||||||
|
debug!(
|
||||||
|
"get_signature_confirmation rpc request received: {:?}",
|
||||||
|
signature_str
|
||||||
|
);
|
||||||
|
let signature = verify_signature(&signature_str)?;
|
||||||
|
Ok(meta
|
||||||
|
.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_signature_confirmation_status(signature, commitment))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_signature_status(
|
fn get_signature_status(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
signature_strs: Vec<String>,
|
signature_str: String,
|
||||||
commitment: Option<CommitmentConfig>,
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Option<transaction::Result<()>>> {
|
||||||
|
let signature = verify_signature(&signature_str)?;
|
||||||
|
Ok(meta
|
||||||
|
.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_signature_status(signature, commitment))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_signature_statuses(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_strs: Vec<String>,
|
||||||
|
config: Option<RpcSignatureStatusConfig>,
|
||||||
) -> RpcResponse<Vec<Option<TransactionStatus>>> {
|
) -> RpcResponse<Vec<Option<TransactionStatus>>> {
|
||||||
|
if signature_strs.len() > MAX_QUERY_ITEMS {
|
||||||
|
return Err(Error::invalid_params(format!(
|
||||||
|
"Too many inputs provided; max {}",
|
||||||
|
MAX_QUERY_ITEMS
|
||||||
|
)));
|
||||||
|
}
|
||||||
let mut signatures: Vec<Signature> = vec![];
|
let mut signatures: Vec<Signature> = vec![];
|
||||||
for signature_str in signature_strs {
|
for signature_str in signature_strs {
|
||||||
signatures.push(verify_signature(&signature_str)?);
|
signatures.push(verify_signature(&signature_str)?);
|
||||||
@@ -896,7 +1077,7 @@ impl RpcSol for RpcSolImpl {
|
|||||||
meta.request_processor
|
meta.request_processor
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_signature_status(signatures, commitment)
|
.get_signature_statuses(signatures, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
||||||
@@ -989,9 +1170,10 @@ impl RpcSol for RpcSolImpl {
|
|||||||
.request_processor
|
.request_processor
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_signature_status(vec![signature], commitment.clone())?
|
.get_signature_statuses(vec![signature], None)?
|
||||||
.value[0]
|
.value[0]
|
||||||
.clone()
|
.clone()
|
||||||
|
.filter(|result| result.satisfies_commitment(commitment.unwrap_or_default()))
|
||||||
.map(|x| x.status);
|
.map(|x| x.status);
|
||||||
|
|
||||||
if signature_status == Some(Ok(())) {
|
if signature_status == Some(Ok(())) {
|
||||||
@@ -1156,6 +1338,51 @@ impl RpcSol for RpcSolImpl {
|
|||||||
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>> {
|
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>> {
|
||||||
meta.request_processor.read().unwrap().get_block_time(slot)
|
meta.request_processor.read().unwrap().get_block_time(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_confirmed_transaction(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
signature_str: String,
|
||||||
|
encoding: Option<TransactionEncoding>,
|
||||||
|
) -> Result<Option<ConfirmedTransaction>> {
|
||||||
|
let signature = verify_signature(&signature_str)?;
|
||||||
|
meta.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_confirmed_transaction(signature, encoding)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_confirmed_signatures_for_address(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
pubkey_str: String,
|
||||||
|
start_slot: Slot,
|
||||||
|
end_slot: Slot,
|
||||||
|
) -> Result<Vec<String>> {
|
||||||
|
let pubkey = verify_pubkey(pubkey_str)?;
|
||||||
|
if end_slot <= start_slot {
|
||||||
|
return Err(Error::invalid_params(format!(
|
||||||
|
"start_slot {} must be smaller than end_slot {}",
|
||||||
|
start_slot, end_slot
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
if end_slot - start_slot > MAX_SLOT_RANGE {
|
||||||
|
return Err(Error::invalid_params(format!(
|
||||||
|
"Slot range too large; max {}",
|
||||||
|
MAX_SLOT_RANGE
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
meta.request_processor
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.get_confirmed_signatures_for_address(pubkey, start_slot, end_slot)
|
||||||
|
.map(|signatures| {
|
||||||
|
signatures
|
||||||
|
.iter()
|
||||||
|
.map(|signature| signature.to_string())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -1220,18 +1447,6 @@ pub mod tests {
|
|||||||
) -> RpcHandler {
|
) -> RpcHandler {
|
||||||
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
|
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
|
||||||
let bank = bank_forks.read().unwrap().working_bank();
|
let bank = bank_forks.read().unwrap().working_bank();
|
||||||
|
|
||||||
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
|
||||||
let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY]);
|
|
||||||
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
|
||||||
block_commitment
|
|
||||||
.entry(0)
|
|
||||||
.or_insert(commitment_slot0.clone());
|
|
||||||
block_commitment
|
|
||||||
.entry(1)
|
|
||||||
.or_insert(commitment_slot1.clone());
|
|
||||||
let block_commitment_cache =
|
|
||||||
Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42)));
|
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
||||||
let blockstore = Arc::new(blockstore);
|
let blockstore = Arc::new(blockstore);
|
||||||
@@ -1247,6 +1462,24 @@ pub mod tests {
|
|||||||
blockstore.clone(),
|
blockstore.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut commitment_slot0 = BlockCommitment::default();
|
||||||
|
commitment_slot0.increase_confirmation_stake(2, 9);
|
||||||
|
let mut commitment_slot1 = BlockCommitment::default();
|
||||||
|
commitment_slot1.increase_confirmation_stake(1, 9);
|
||||||
|
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
||||||
|
block_commitment
|
||||||
|
.entry(0)
|
||||||
|
.or_insert(commitment_slot0.clone());
|
||||||
|
block_commitment
|
||||||
|
.entry(1)
|
||||||
|
.or_insert(commitment_slot1.clone());
|
||||||
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new(
|
||||||
|
block_commitment,
|
||||||
|
10,
|
||||||
|
bank.clone(),
|
||||||
|
0,
|
||||||
|
)));
|
||||||
|
|
||||||
// Add timestamp vote to blockstore
|
// Add timestamp vote to blockstore
|
||||||
let vote = Vote {
|
let vote = Vote {
|
||||||
slots: vec![1],
|
slots: vec![1],
|
||||||
@@ -1748,6 +1981,76 @@ pub mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rpc_get_signature_status() {
|
fn test_rpc_get_signature_status() {
|
||||||
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
|
let RpcHandler {
|
||||||
|
io,
|
||||||
|
meta,
|
||||||
|
blockhash,
|
||||||
|
alice,
|
||||||
|
..
|
||||||
|
} = start_rpc_handler_with_tx(&bob_pubkey);
|
||||||
|
|
||||||
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
|
tx.signatures[0]
|
||||||
|
);
|
||||||
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
|
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
||||||
|
let expected = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": expected_res,
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected: Response =
|
||||||
|
serde_json::from_value(expected).expect("expected response deserialization");
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
|
||||||
|
// Test getSignatureStatus request on unprocessed tx
|
||||||
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
|
tx.signatures[0]
|
||||||
|
);
|
||||||
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
|
let expected_res: Option<String> = None;
|
||||||
|
let expected = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": expected_res,
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected: Response =
|
||||||
|
serde_json::from_value(expected).expect("expected response deserialization");
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
|
||||||
|
// Test getSignatureStatus request on a TransactionError
|
||||||
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, std::u64::MAX, blockhash);
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
||||||
|
tx.signatures[0]
|
||||||
|
);
|
||||||
|
let res = io.handle_request_sync(&req, meta);
|
||||||
|
let expected_res: Option<transaction::Result<()>> = Some(Err(
|
||||||
|
TransactionError::InstructionError(0, InstructionError::CustomError(1)),
|
||||||
|
));
|
||||||
|
let expected = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": expected_res,
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected: Response =
|
||||||
|
serde_json::from_value(expected).expect("expected response deserialization");
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_get_signature_statuses() {
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
let RpcHandler {
|
let RpcHandler {
|
||||||
io,
|
io,
|
||||||
@@ -1759,7 +2062,7 @@ pub mod tests {
|
|||||||
} = start_rpc_handler_with_tx(&bob_pubkey);
|
} = start_rpc_handler_with_tx(&bob_pubkey);
|
||||||
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
|
||||||
confirmed_block_signatures[0]
|
confirmed_block_signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
@@ -1768,12 +2071,14 @@ pub mod tests {
|
|||||||
let result: Option<TransactionStatus> =
|
let result: Option<TransactionStatus> =
|
||||||
serde_json::from_value(json["result"]["value"][0].clone())
|
serde_json::from_value(json["result"]["value"][0].clone())
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
assert_eq!(expected_res, result.as_ref().unwrap().status);
|
let result = result.as_ref().unwrap();
|
||||||
|
assert_eq!(expected_res, result.status);
|
||||||
|
assert_eq!(None, result.confirmations);
|
||||||
|
|
||||||
// Test getSignatureStatus request on unprocessed tx
|
// Test getSignatureStatus request on unprocessed tx
|
||||||
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 10, blockhash);
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
|
||||||
tx.signatures[0]
|
tx.signatures[0]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
@@ -1785,7 +2090,7 @@ pub mod tests {
|
|||||||
|
|
||||||
// Test getSignatureStatus request on a TransactionError
|
// Test getSignatureStatus request on a TransactionError
|
||||||
let req = format!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":[["{}"]]}}"#,
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
|
||||||
confirmed_block_signatures[1]
|
confirmed_block_signatures[1]
|
||||||
);
|
);
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
@@ -2117,6 +2422,8 @@ pub mod tests {
|
|||||||
fn test_rpc_processor_get_block_commitment() {
|
fn test_rpc_processor_get_block_commitment() {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let validator_exit = create_validator_exit(&exit);
|
let validator_exit = create_validator_exit(&exit);
|
||||||
|
let bank_forks = new_bank_forks().0;
|
||||||
|
|
||||||
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
||||||
let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY]);
|
let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY]);
|
||||||
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
||||||
@@ -2126,8 +2433,12 @@ pub mod tests {
|
|||||||
block_commitment
|
block_commitment
|
||||||
.entry(1)
|
.entry(1)
|
||||||
.or_insert(commitment_slot1.clone());
|
.or_insert(commitment_slot1.clone());
|
||||||
let block_commitment_cache =
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new(
|
||||||
Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42)));
|
block_commitment,
|
||||||
|
42,
|
||||||
|
bank_forks.read().unwrap().working_bank(),
|
||||||
|
0,
|
||||||
|
)));
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
||||||
|
|
||||||
@@ -2135,7 +2446,7 @@ pub mod tests {
|
|||||||
config.enable_validator_exit = true;
|
config.enable_validator_exit = true;
|
||||||
let request_processor = JsonRpcRequestProcessor::new(
|
let request_processor = JsonRpcRequestProcessor::new(
|
||||||
config,
|
config,
|
||||||
new_bank_forks().0,
|
bank_forks,
|
||||||
block_commitment_cache,
|
block_commitment_cache,
|
||||||
Arc::new(blockstore),
|
Arc::new(blockstore),
|
||||||
StorageState::default(),
|
StorageState::default(),
|
||||||
@@ -2199,7 +2510,7 @@ pub mod tests {
|
|||||||
.get_block_commitment(0)
|
.get_block_commitment(0)
|
||||||
.map(|block_commitment| block_commitment.commitment)
|
.map(|block_commitment| block_commitment.commitment)
|
||||||
);
|
);
|
||||||
assert_eq!(total_stake, 42);
|
assert_eq!(total_stake, 10);
|
||||||
|
|
||||||
let req =
|
let req =
|
||||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}}"#);
|
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}}"#);
|
||||||
@@ -2217,7 +2528,7 @@ pub mod tests {
|
|||||||
panic!("Expected single response");
|
panic!("Expected single response");
|
||||||
};
|
};
|
||||||
assert_eq!(commitment_response.commitment, None);
|
assert_eq!(commitment_response.commitment, None);
|
||||||
assert_eq!(commitment_response.total_stake, 42);
|
assert_eq!(commitment_response.total_stake, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2246,11 +2557,21 @@ pub mod tests {
|
|||||||
{
|
{
|
||||||
if let EncodedTransaction::Json(transaction) = transaction {
|
if let EncodedTransaction::Json(transaction) = transaction {
|
||||||
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
assert_eq!(transaction.message.recent_blockhash, blockhash.to_string());
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
assert_eq!(meta.status, Ok(()));
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
} else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
@@ -2280,11 +2601,21 @@ pub mod tests {
|
|||||||
let decoded_transaction: Transaction =
|
let decoded_transaction: Transaction =
|
||||||
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
||||||
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
assert_eq!(decoded_transaction.message.recent_blockhash, blockhash);
|
||||||
assert_eq!(meta.unwrap().status, Ok(()));
|
assert_eq!(meta.status, Ok(()));
|
||||||
|
assert_eq!(meta.err, None);
|
||||||
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
} else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
|
||||||
|
let meta = meta.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.unwrap().status,
|
meta.err,
|
||||||
|
Some(TransactionError::InstructionError(
|
||||||
|
0,
|
||||||
|
InstructionError::CustomError(1)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
meta.status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
0,
|
0,
|
||||||
InstructionError::CustomError(1)
|
InstructionError::CustomError(1)
|
||||||
|
@@ -4,8 +4,10 @@ use crate::rpc_subscriptions::{Confirmations, RpcSubscriptions, SlotInfo};
|
|||||||
use jsonrpc_core::{Error, ErrorCode, Result};
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
||||||
use jsonrpc_derive::rpc;
|
use jsonrpc_derive::rpc;
|
||||||
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
||||||
use solana_client::rpc_response::{Response as RpcResponse, RpcAccount, RpcKeyedAccount};
|
use solana_client::rpc_response::{
|
||||||
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature, transaction};
|
Response as RpcResponse, RpcAccount, RpcKeyedAccount, RpcSignatureResult,
|
||||||
|
};
|
||||||
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
use std::sync::{atomic, Arc};
|
use std::sync::{atomic, Arc};
|
||||||
|
|
||||||
// Suppress needless_return due to
|
// Suppress needless_return due to
|
||||||
@@ -74,7 +76,7 @@ pub trait RpcSolPubSub {
|
|||||||
fn signature_subscribe(
|
fn signature_subscribe(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<transaction::Result<()>>>,
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
);
|
);
|
||||||
@@ -225,7 +227,7 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||||||
fn signature_subscribe(
|
fn signature_subscribe(
|
||||||
&self,
|
&self,
|
||||||
_meta: Self::Metadata,
|
_meta: Self::Metadata,
|
||||||
subscriber: Subscriber<RpcResponse<transaction::Result<()>>>,
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
||||||
signature_str: String,
|
signature_str: String,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
) {
|
) {
|
||||||
@@ -312,8 +314,11 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
use crate::{
|
||||||
use crate::rpc_subscriptions::tests::robust_poll_or_panic;
|
commitment::{BlockCommitment, BlockCommitmentCache},
|
||||||
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
|
rpc_subscriptions::tests::robust_poll_or_panic,
|
||||||
|
};
|
||||||
use jsonrpc_core::{futures::sync::mpsc, Response};
|
use jsonrpc_core::{futures::sync::mpsc, Response};
|
||||||
use jsonrpc_pubsub::{PubSubHandler, Session};
|
use jsonrpc_pubsub::{PubSubHandler, Session};
|
||||||
use solana_budget_program::{self, budget_instruction};
|
use solana_budget_program::{self, budget_instruction};
|
||||||
@@ -325,7 +330,12 @@ mod tests {
|
|||||||
system_program, system_transaction,
|
system_program, system_transaction,
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
};
|
};
|
||||||
use std::{sync::RwLock, thread::sleep, time::Duration};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{atomic::AtomicBool, RwLock},
|
||||||
|
thread::sleep,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
fn process_transaction_and_notify(
|
fn process_transaction_and_notify(
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
@@ -358,8 +368,13 @@ mod tests {
|
|||||||
let bank = Bank::new(&genesis_config);
|
let bank = Bank::new(&genesis_config);
|
||||||
let blockhash = bank.last_blockhash();
|
let blockhash = bank.last_blockhash();
|
||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
||||||
|
let rpc = RpcSolPubSubImpl {
|
||||||
let rpc = RpcSolPubSubImpl::default();
|
subscriptions: Arc::new(RpcSubscriptions::new(
|
||||||
|
&Arc::new(AtomicBool::new(false)),
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
)),
|
||||||
|
..RpcSolPubSubImpl::default()
|
||||||
|
};
|
||||||
|
|
||||||
// Test signature subscriptions
|
// Test signature subscriptions
|
||||||
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
||||||
@@ -372,7 +387,7 @@ mod tests {
|
|||||||
|
|
||||||
// Test signature confirmation notification
|
// Test signature confirmation notification
|
||||||
let (response, _) = robust_poll_or_panic(receiver);
|
let (response, _) = robust_poll_or_panic(receiver);
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
let expected_res = RpcSignatureResult { err: None };
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "signatureNotification",
|
"method": "signatureNotification",
|
||||||
@@ -457,7 +472,13 @@ mod tests {
|
|||||||
let blockhash = bank.last_blockhash();
|
let blockhash = bank.last_blockhash();
|
||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
||||||
|
|
||||||
let rpc = RpcSolPubSubImpl::default();
|
let rpc = RpcSolPubSubImpl {
|
||||||
|
subscriptions: Arc::new(RpcSubscriptions::new(
|
||||||
|
&Arc::new(AtomicBool::new(false)),
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
)),
|
||||||
|
..RpcSolPubSubImpl::default()
|
||||||
|
};
|
||||||
let session = create_session();
|
let session = create_session();
|
||||||
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
||||||
rpc.account_subscribe(
|
rpc.account_subscribe(
|
||||||
@@ -591,7 +612,13 @@ mod tests {
|
|||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
||||||
let bob = Keypair::new();
|
let bob = Keypair::new();
|
||||||
|
|
||||||
let rpc = RpcSolPubSubImpl::default();
|
let mut rpc = RpcSolPubSubImpl::default();
|
||||||
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
let subscriptions = RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
);
|
||||||
|
rpc.subscriptions = Arc::new(subscriptions);
|
||||||
let session = create_session();
|
let session = create_session();
|
||||||
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
||||||
rpc.account_subscribe(session, subscriber, bob.pubkey().to_string(), Some(2));
|
rpc.account_subscribe(session, subscriber, bob.pubkey().to_string(), Some(2));
|
||||||
@@ -622,7 +649,12 @@ mod tests {
|
|||||||
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
||||||
let bob = Keypair::new();
|
let bob = Keypair::new();
|
||||||
|
|
||||||
let rpc = RpcSolPubSubImpl::default();
|
let mut rpc = RpcSolPubSubImpl::default();
|
||||||
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests()));
|
||||||
|
|
||||||
|
let subscriptions = RpcSubscriptions::new(&exit, block_commitment_cache.clone());
|
||||||
|
rpc.subscriptions = Arc::new(subscriptions);
|
||||||
let session = create_session();
|
let session = create_session();
|
||||||
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
||||||
rpc.account_subscribe(session, subscriber, bob.pubkey().to_string(), Some(2));
|
rpc.account_subscribe(session, subscriber, bob.pubkey().to_string(), Some(2));
|
||||||
@@ -640,10 +672,32 @@ mod tests {
|
|||||||
let bank0 = bank_forks.read().unwrap()[0].clone();
|
let bank0 = bank_forks.read().unwrap()[0].clone();
|
||||||
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||||
bank_forks.write().unwrap().insert(bank1);
|
bank_forks.write().unwrap().insert(bank1);
|
||||||
rpc.subscriptions.notify_subscribers(1, &bank_forks);
|
|
||||||
let bank1 = bank_forks.read().unwrap()[1].clone();
|
let bank1 = bank_forks.read().unwrap()[1].clone();
|
||||||
|
|
||||||
|
let mut cache0 = BlockCommitment::default();
|
||||||
|
cache0.increase_confirmation_stake(1, 10);
|
||||||
|
let mut block_commitment = HashMap::new();
|
||||||
|
block_commitment.entry(0).or_insert(cache0.clone());
|
||||||
|
let mut new_block_commitment =
|
||||||
|
BlockCommitmentCache::new(block_commitment, 10, bank1.clone(), 0);
|
||||||
|
let mut w_block_commitment_cache = block_commitment_cache.write().unwrap();
|
||||||
|
std::mem::swap(&mut *w_block_commitment_cache, &mut new_block_commitment);
|
||||||
|
drop(w_block_commitment_cache);
|
||||||
|
|
||||||
|
rpc.subscriptions.notify_subscribers(1, &bank_forks);
|
||||||
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
||||||
bank_forks.write().unwrap().insert(bank2);
|
bank_forks.write().unwrap().insert(bank2);
|
||||||
|
let bank2 = bank_forks.read().unwrap()[2].clone();
|
||||||
|
|
||||||
|
let mut cache0 = BlockCommitment::default();
|
||||||
|
cache0.increase_confirmation_stake(2, 10);
|
||||||
|
let mut block_commitment = HashMap::new();
|
||||||
|
block_commitment.entry(0).or_insert(cache0.clone());
|
||||||
|
let mut new_block_commitment = BlockCommitmentCache::new(block_commitment, 10, bank2, 0);
|
||||||
|
let mut w_block_commitment_cache = block_commitment_cache.write().unwrap();
|
||||||
|
std::mem::swap(&mut *w_block_commitment_cache, &mut new_block_commitment);
|
||||||
|
drop(w_block_commitment_cache);
|
||||||
|
|
||||||
rpc.subscriptions.notify_subscribers(2, &bank_forks);
|
rpc.subscriptions.notify_subscribers(2, &bank_forks);
|
||||||
let expected = json!({
|
let expected = json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
|
@@ -1,14 +1,20 @@
|
|||||||
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
||||||
|
|
||||||
use crate::rpc_pubsub::{RpcSolPubSub, RpcSolPubSubImpl};
|
use crate::{
|
||||||
use crate::rpc_subscriptions::RpcSubscriptions;
|
rpc_pubsub::{RpcSolPubSub, RpcSolPubSubImpl},
|
||||||
|
rpc_subscriptions::RpcSubscriptions,
|
||||||
|
};
|
||||||
use jsonrpc_pubsub::{PubSubHandler, Session};
|
use jsonrpc_pubsub::{PubSubHandler, Session};
|
||||||
use jsonrpc_ws_server::{RequestContext, ServerBuilder};
|
use jsonrpc_ws_server::{RequestContext, ServerBuilder};
|
||||||
use std::net::SocketAddr;
|
use std::{
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
net::SocketAddr,
|
||||||
use std::sync::Arc;
|
sync::{
|
||||||
use std::thread::{self, sleep, Builder, JoinHandle};
|
atomic::{AtomicBool, Ordering},
|
||||||
use std::time::Duration;
|
Arc,
|
||||||
|
},
|
||||||
|
thread::{self, sleep, Builder, JoinHandle},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct PubSubService {
|
pub struct PubSubService {
|
||||||
thread_hdl: JoinHandle<()>,
|
thread_hdl: JoinHandle<()>,
|
||||||
@@ -66,13 +72,20 @@ impl PubSubService {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use crate::commitment::BlockCommitmentCache;
|
||||||
|
use std::{
|
||||||
|
net::{IpAddr, Ipv4Addr},
|
||||||
|
sync::RwLock,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pubsub_new() {
|
fn test_pubsub_new() {
|
||||||
let pubsub_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
let pubsub_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
|
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
));
|
||||||
let pubsub_service = PubSubService::new(&subscriptions, pubsub_addr, &exit);
|
let pubsub_service = PubSubService::new(&subscriptions, pubsub_addr, &exit);
|
||||||
let thread = pubsub_service.thread_hdl.thread();
|
let thread = pubsub_service.thread_hdl.thread();
|
||||||
assert_eq!(thread.name().unwrap(), "solana-pubsub");
|
assert_eq!(thread.name().unwrap(), "solana-pubsub");
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
||||||
|
|
||||||
|
use crate::commitment::BlockCommitmentCache;
|
||||||
use core::hash::Hash;
|
use core::hash::Hash;
|
||||||
use jsonrpc_core::futures::Future;
|
use jsonrpc_core::futures::Future;
|
||||||
use jsonrpc_pubsub::{
|
use jsonrpc_pubsub::{
|
||||||
@@ -7,18 +8,23 @@ use jsonrpc_pubsub::{
|
|||||||
SubscriptionId,
|
SubscriptionId,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_client::rpc_response::{Response, RpcAccount, RpcKeyedAccount, RpcResponseContext};
|
use solana_client::rpc_response::{
|
||||||
|
Response, RpcAccount, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult,
|
||||||
|
};
|
||||||
use solana_ledger::bank_forks::BankForks;
|
use solana_ledger::bank_forks::BankForks;
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account, clock::Slot, pubkey::Pubkey, signature::Signature, transaction,
|
account::Account, clock::Slot, pubkey::Pubkey, signature::Signature, transaction,
|
||||||
};
|
};
|
||||||
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::{
|
||||||
use std::sync::mpsc::{Receiver, RecvTimeoutError, SendError, Sender};
|
atomic::{AtomicBool, Ordering},
|
||||||
|
mpsc::{Receiver, RecvTimeoutError, SendError, Sender},
|
||||||
|
};
|
||||||
use std::thread::{Builder, JoinHandle};
|
use std::thread::{Builder, JoinHandle};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{
|
use std::{
|
||||||
|
cmp::min,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
iter,
|
iter,
|
||||||
sync::{Arc, Mutex, RwLock},
|
sync::{Arc, Mutex, RwLock},
|
||||||
@@ -62,7 +68,7 @@ type RpcProgramSubscriptions = RwLock<
|
|||||||
type RpcSignatureSubscriptions = RwLock<
|
type RpcSignatureSubscriptions = RwLock<
|
||||||
HashMap<
|
HashMap<
|
||||||
Signature,
|
Signature,
|
||||||
HashMap<SubscriptionId, (Sink<Response<transaction::Result<()>>>, Confirmations)>,
|
HashMap<SubscriptionId, (Sink<Response<RpcSignatureResult>>, Confirmations)>,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
type RpcSlotSubscriptions = RwLock<HashMap<SubscriptionId, Sink<SlotInfo>>>;
|
type RpcSlotSubscriptions = RwLock<HashMap<SubscriptionId, Sink<SlotInfo>>>;
|
||||||
@@ -80,11 +86,7 @@ fn add_subscription<K, S>(
|
|||||||
{
|
{
|
||||||
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
||||||
let confirmations = confirmations.unwrap_or(0);
|
let confirmations = confirmations.unwrap_or(0);
|
||||||
let confirmations = if confirmations > MAX_LOCKOUT_HISTORY {
|
let confirmations = min(confirmations, MAX_LOCKOUT_HISTORY + 1);
|
||||||
MAX_LOCKOUT_HISTORY
|
|
||||||
} else {
|
|
||||||
confirmations
|
|
||||||
};
|
|
||||||
if let Some(current_hashmap) = subscriptions.get_mut(&hashmap_key) {
|
if let Some(current_hashmap) = subscriptions.get_mut(&hashmap_key) {
|
||||||
current_hashmap.insert(sub_id, (sink, confirmations));
|
current_hashmap.insert(sub_id, (sink, confirmations));
|
||||||
return;
|
return;
|
||||||
@@ -120,8 +122,8 @@ where
|
|||||||
fn check_confirmations_and_notify<K, S, B, F, X>(
|
fn check_confirmations_and_notify<K, S, B, F, X>(
|
||||||
subscriptions: &HashMap<K, HashMap<SubscriptionId, (Sink<Response<S>>, Confirmations)>>,
|
subscriptions: &HashMap<K, HashMap<SubscriptionId, (Sink<Response<S>>, Confirmations)>>,
|
||||||
hashmap_key: &K,
|
hashmap_key: &K,
|
||||||
current_slot: Slot,
|
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
bank_method: B,
|
bank_method: B,
|
||||||
filter_results: F,
|
filter_results: F,
|
||||||
notifier: &RpcNotifier,
|
notifier: &RpcNotifier,
|
||||||
@@ -133,6 +135,10 @@ where
|
|||||||
F: Fn(X, u64) -> Box<dyn Iterator<Item = S>>,
|
F: Fn(X, u64) -> Box<dyn Iterator<Item = S>>,
|
||||||
X: Clone + Serialize,
|
X: Clone + Serialize,
|
||||||
{
|
{
|
||||||
|
let mut confirmation_slots: HashMap<usize, Slot> = HashMap::new();
|
||||||
|
let r_block_commitment_cache = block_commitment_cache.read().unwrap();
|
||||||
|
let current_slot = r_block_commitment_cache.slot();
|
||||||
|
let root = r_block_commitment_cache.root();
|
||||||
let current_ancestors = bank_forks
|
let current_ancestors = bank_forks
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -140,27 +146,29 @@ where
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.ancestors
|
.ancestors
|
||||||
.clone();
|
.clone();
|
||||||
|
for (slot, _) in current_ancestors.iter() {
|
||||||
|
if let Some(confirmations) = r_block_commitment_cache.get_confirmation_count(*slot) {
|
||||||
|
confirmation_slots.entry(confirmations).or_insert(*slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop(r_block_commitment_cache);
|
||||||
|
|
||||||
let mut notified_set: HashSet<SubscriptionId> = HashSet::new();
|
let mut notified_set: HashSet<SubscriptionId> = HashSet::new();
|
||||||
if let Some(hashmap) = subscriptions.get(hashmap_key) {
|
if let Some(hashmap) = subscriptions.get(hashmap_key) {
|
||||||
for (sub_id, (sink, confirmations)) in hashmap.iter() {
|
for (sub_id, (sink, confirmations)) in hashmap.iter() {
|
||||||
let desired_slot: Vec<u64> = current_ancestors
|
let desired_slot = if *confirmations == 0 {
|
||||||
.iter()
|
Some(¤t_slot)
|
||||||
.filter(|(_, &v)| v == *confirmations)
|
} else if *confirmations == MAX_LOCKOUT_HISTORY + 1 {
|
||||||
.map(|(k, _)| k)
|
Some(&root)
|
||||||
.cloned()
|
} else {
|
||||||
.collect();
|
confirmation_slots.get(confirmations)
|
||||||
let root: Vec<u64> = current_ancestors
|
};
|
||||||
.iter()
|
if let Some(&slot) = desired_slot {
|
||||||
.filter(|(_, &v)| v == 32)
|
let results = {
|
||||||
.map(|(k, _)| k)
|
let bank_forks = bank_forks.read().unwrap();
|
||||||
.cloned()
|
let desired_bank = bank_forks.get(slot).unwrap();
|
||||||
.collect();
|
bank_method(&desired_bank, hashmap_key)
|
||||||
let root = if root.len() == 1 { root[0] } else { 0 };
|
};
|
||||||
if desired_slot.len() == 1 {
|
|
||||||
let slot = desired_slot[0];
|
|
||||||
let desired_bank = bank_forks.read().unwrap().get(slot).unwrap().clone();
|
|
||||||
let results = bank_method(&desired_bank, hashmap_key);
|
|
||||||
for result in filter_results(results, root) {
|
for result in filter_results(results, root) {
|
||||||
notifier.notify(
|
notifier.notify(
|
||||||
Response {
|
Response {
|
||||||
@@ -201,11 +209,15 @@ fn filter_account_result(
|
|||||||
Box::new(iter::empty())
|
Box::new(iter::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_signature_result<S>(result: Option<S>, _root: Slot) -> Box<dyn Iterator<Item = S>>
|
fn filter_signature_result(
|
||||||
where
|
result: Option<transaction::Result<()>>,
|
||||||
S: 'static + Clone + Serialize,
|
_root: Slot,
|
||||||
{
|
) -> Box<dyn Iterator<Item = RpcSignatureResult>> {
|
||||||
Box::new(result.into_iter())
|
Box::new(
|
||||||
|
result
|
||||||
|
.into_iter()
|
||||||
|
.map(|result| RpcSignatureResult { err: result.err() }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_program_results(
|
fn filter_program_results(
|
||||||
@@ -236,7 +248,10 @@ pub struct RpcSubscriptions {
|
|||||||
|
|
||||||
impl Default for RpcSubscriptions {
|
impl Default for RpcSubscriptions {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(&Arc::new(AtomicBool::new(false)))
|
Self::new(
|
||||||
|
&Arc::new(AtomicBool::new(false)),
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +264,10 @@ impl Drop for RpcSubscriptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RpcSubscriptions {
|
impl RpcSubscriptions {
|
||||||
pub fn new(exit: &Arc<AtomicBool>) -> Self {
|
pub fn new(
|
||||||
|
exit: &Arc<AtomicBool>,
|
||||||
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
|
) -> Self {
|
||||||
let (notification_sender, notification_receiver): (
|
let (notification_sender, notification_receiver): (
|
||||||
Sender<NotificationEntry>,
|
Sender<NotificationEntry>,
|
||||||
Receiver<NotificationEntry>,
|
Receiver<NotificationEntry>,
|
||||||
@@ -288,6 +306,7 @@ impl RpcSubscriptions {
|
|||||||
signature_subscriptions_clone,
|
signature_subscriptions_clone,
|
||||||
slot_subscriptions_clone,
|
slot_subscriptions_clone,
|
||||||
root_subscriptions_clone,
|
root_subscriptions_clone,
|
||||||
|
block_commitment_cache,
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -307,8 +326,8 @@ impl RpcSubscriptions {
|
|||||||
|
|
||||||
fn check_account(
|
fn check_account(
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
current_slot: Slot,
|
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
account_subscriptions: Arc<RpcAccountSubscriptions>,
|
account_subscriptions: Arc<RpcAccountSubscriptions>,
|
||||||
notifier: &RpcNotifier,
|
notifier: &RpcNotifier,
|
||||||
) {
|
) {
|
||||||
@@ -316,8 +335,8 @@ impl RpcSubscriptions {
|
|||||||
check_confirmations_and_notify(
|
check_confirmations_and_notify(
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
pubkey,
|
pubkey,
|
||||||
current_slot,
|
|
||||||
bank_forks,
|
bank_forks,
|
||||||
|
block_commitment_cache,
|
||||||
Bank::get_account_modified_since_parent,
|
Bank::get_account_modified_since_parent,
|
||||||
filter_account_result,
|
filter_account_result,
|
||||||
notifier,
|
notifier,
|
||||||
@@ -326,8 +345,8 @@ impl RpcSubscriptions {
|
|||||||
|
|
||||||
fn check_program(
|
fn check_program(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
current_slot: Slot,
|
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
program_subscriptions: Arc<RpcProgramSubscriptions>,
|
program_subscriptions: Arc<RpcProgramSubscriptions>,
|
||||||
notifier: &RpcNotifier,
|
notifier: &RpcNotifier,
|
||||||
) {
|
) {
|
||||||
@@ -335,8 +354,8 @@ impl RpcSubscriptions {
|
|||||||
check_confirmations_and_notify(
|
check_confirmations_and_notify(
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
program_id,
|
program_id,
|
||||||
current_slot,
|
|
||||||
bank_forks,
|
bank_forks,
|
||||||
|
block_commitment_cache,
|
||||||
Bank::get_program_accounts_modified_since_parent,
|
Bank::get_program_accounts_modified_since_parent,
|
||||||
filter_program_results,
|
filter_program_results,
|
||||||
notifier,
|
notifier,
|
||||||
@@ -345,8 +364,8 @@ impl RpcSubscriptions {
|
|||||||
|
|
||||||
fn check_signature(
|
fn check_signature(
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
current_slot: Slot,
|
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
signature_subscriptions: Arc<RpcSignatureSubscriptions>,
|
signature_subscriptions: Arc<RpcSignatureSubscriptions>,
|
||||||
notifier: &RpcNotifier,
|
notifier: &RpcNotifier,
|
||||||
) {
|
) {
|
||||||
@@ -354,8 +373,8 @@ impl RpcSubscriptions {
|
|||||||
let notified_ids = check_confirmations_and_notify(
|
let notified_ids = check_confirmations_and_notify(
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
signature,
|
signature,
|
||||||
current_slot,
|
|
||||||
bank_forks,
|
bank_forks,
|
||||||
|
block_commitment_cache,
|
||||||
Bank::get_signature_status_processed_since_parent,
|
Bank::get_signature_status_processed_since_parent,
|
||||||
filter_signature_result,
|
filter_signature_result,
|
||||||
notifier,
|
notifier,
|
||||||
@@ -417,7 +436,7 @@ impl RpcSubscriptions {
|
|||||||
signature: Signature,
|
signature: Signature,
|
||||||
confirmations: Option<Confirmations>,
|
confirmations: Option<Confirmations>,
|
||||||
sub_id: SubscriptionId,
|
sub_id: SubscriptionId,
|
||||||
subscriber: Subscriber<Response<transaction::Result<()>>>,
|
subscriber: Subscriber<Response<RpcSignatureResult>>,
|
||||||
) {
|
) {
|
||||||
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
||||||
add_subscription(
|
add_subscription(
|
||||||
@@ -499,6 +518,7 @@ impl RpcSubscriptions {
|
|||||||
signature_subscriptions: Arc<RpcSignatureSubscriptions>,
|
signature_subscriptions: Arc<RpcSignatureSubscriptions>,
|
||||||
slot_subscriptions: Arc<RpcSlotSubscriptions>,
|
slot_subscriptions: Arc<RpcSlotSubscriptions>,
|
||||||
root_subscriptions: Arc<RpcRootSubscriptions>,
|
root_subscriptions: Arc<RpcRootSubscriptions>,
|
||||||
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
if exit.load(Ordering::Relaxed) {
|
if exit.load(Ordering::Relaxed) {
|
||||||
@@ -518,7 +538,7 @@ impl RpcSubscriptions {
|
|||||||
notifier.notify(root, sink);
|
notifier.notify(root, sink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NotificationEntry::Bank((current_slot, bank_forks)) => {
|
NotificationEntry::Bank((_current_slot, bank_forks)) => {
|
||||||
let pubkeys: Vec<_> = {
|
let pubkeys: Vec<_> = {
|
||||||
let subs = account_subscriptions.read().unwrap();
|
let subs = account_subscriptions.read().unwrap();
|
||||||
subs.keys().cloned().collect()
|
subs.keys().cloned().collect()
|
||||||
@@ -526,8 +546,8 @@ impl RpcSubscriptions {
|
|||||||
for pubkey in &pubkeys {
|
for pubkey in &pubkeys {
|
||||||
Self::check_account(
|
Self::check_account(
|
||||||
pubkey,
|
pubkey,
|
||||||
current_slot,
|
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
|
&block_commitment_cache,
|
||||||
account_subscriptions.clone(),
|
account_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
);
|
);
|
||||||
@@ -540,8 +560,8 @@ impl RpcSubscriptions {
|
|||||||
for program_id in &programs {
|
for program_id in &programs {
|
||||||
Self::check_program(
|
Self::check_program(
|
||||||
program_id,
|
program_id,
|
||||||
current_slot,
|
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
|
&block_commitment_cache,
|
||||||
program_subscriptions.clone(),
|
program_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
);
|
);
|
||||||
@@ -554,8 +574,8 @@ impl RpcSubscriptions {
|
|||||||
for signature in &signatures {
|
for signature in &signatures {
|
||||||
Self::check_signature(
|
Self::check_signature(
|
||||||
signature,
|
signature,
|
||||||
current_slot,
|
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
|
&block_commitment_cache,
|
||||||
signature_subscriptions.clone(),
|
signature_subscriptions.clone(),
|
||||||
¬ifier,
|
¬ifier,
|
||||||
);
|
);
|
||||||
@@ -596,7 +616,10 @@ impl RpcSubscriptions {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
use crate::{
|
||||||
|
commitment::BlockCommitment,
|
||||||
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
|
};
|
||||||
use jsonrpc_core::futures::{self, stream::Stream};
|
use jsonrpc_core::futures::{self, stream::Stream};
|
||||||
use jsonrpc_pubsub::typed::Subscriber;
|
use jsonrpc_pubsub::typed::Subscriber;
|
||||||
use solana_budget_program;
|
use solana_budget_program;
|
||||||
@@ -663,7 +686,10 @@ pub(crate) mod tests {
|
|||||||
Subscriber::new_test("accountNotification");
|
Subscriber::new_test("accountNotification");
|
||||||
let sub_id = SubscriptionId::Number(0 as u64);
|
let sub_id = SubscriptionId::Number(0 as u64);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = RpcSubscriptions::new(&exit);
|
let subscriptions = RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
);
|
||||||
subscriptions.add_account_subscription(alice.pubkey(), None, sub_id.clone(), subscriber);
|
subscriptions.add_account_subscription(alice.pubkey(), None, sub_id.clone(), subscriber);
|
||||||
|
|
||||||
assert!(subscriptions
|
assert!(subscriptions
|
||||||
@@ -732,7 +758,10 @@ pub(crate) mod tests {
|
|||||||
Subscriber::new_test("programNotification");
|
Subscriber::new_test("programNotification");
|
||||||
let sub_id = SubscriptionId::Number(0 as u64);
|
let sub_id = SubscriptionId::Number(0 as u64);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = RpcSubscriptions::new(&exit);
|
let subscriptions = RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
);
|
||||||
subscriptions.add_program_subscription(
|
subscriptions.add_program_subscription(
|
||||||
solana_budget_program::id(),
|
solana_budget_program::id(),
|
||||||
None,
|
None,
|
||||||
@@ -812,27 +841,41 @@ pub(crate) mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.process_transaction(&processed_tx)
|
.process_transaction(&processed_tx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let bank1 = bank_forks[1].clone();
|
||||||
|
|
||||||
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
||||||
|
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let mut cache0 = BlockCommitment::default();
|
||||||
let subscriptions = RpcSubscriptions::new(&exit);
|
cache0.increase_confirmation_stake(1, 10);
|
||||||
|
let cache1 = BlockCommitment::default();
|
||||||
|
|
||||||
let (past_bank_sub, _id_receiver, past_bank_recv) =
|
let mut block_commitment = HashMap::new();
|
||||||
|
block_commitment.entry(0).or_insert(cache0.clone());
|
||||||
|
block_commitment.entry(1).or_insert(cache1.clone());
|
||||||
|
let block_commitment_cache = BlockCommitmentCache::new(block_commitment, 10, bank1, 0);
|
||||||
|
|
||||||
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
let subscriptions =
|
||||||
|
RpcSubscriptions::new(&exit, Arc::new(RwLock::new(block_commitment_cache)));
|
||||||
|
|
||||||
|
let (past_bank_sub1, _id_receiver, past_bank_recv1) =
|
||||||
|
Subscriber::new_test("signatureNotification");
|
||||||
|
let (past_bank_sub2, _id_receiver, past_bank_recv2) =
|
||||||
Subscriber::new_test("signatureNotification");
|
Subscriber::new_test("signatureNotification");
|
||||||
let (processed_sub, _id_receiver, processed_recv) =
|
let (processed_sub, _id_receiver, processed_recv) =
|
||||||
Subscriber::new_test("signatureNotification");
|
Subscriber::new_test("signatureNotification");
|
||||||
|
|
||||||
subscriptions.add_signature_subscription(
|
subscriptions.add_signature_subscription(
|
||||||
past_bank_tx.signatures[0],
|
past_bank_tx.signatures[0],
|
||||||
Some(0),
|
Some(0),
|
||||||
SubscriptionId::Number(1 as u64),
|
SubscriptionId::Number(1 as u64),
|
||||||
Subscriber::new_test("signatureNotification").0,
|
past_bank_sub1,
|
||||||
);
|
);
|
||||||
subscriptions.add_signature_subscription(
|
subscriptions.add_signature_subscription(
|
||||||
past_bank_tx.signatures[0],
|
past_bank_tx.signatures[0],
|
||||||
Some(1),
|
Some(1),
|
||||||
SubscriptionId::Number(2 as u64),
|
SubscriptionId::Number(2 as u64),
|
||||||
past_bank_sub,
|
past_bank_sub2,
|
||||||
);
|
);
|
||||||
subscriptions.add_signature_subscription(
|
subscriptions.add_signature_subscription(
|
||||||
processed_tx.signatures[0],
|
processed_tx.signatures[0],
|
||||||
@@ -855,43 +898,48 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
subscriptions.notify_subscribers(1, &bank_forks);
|
subscriptions.notify_subscribers(1, &bank_forks);
|
||||||
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
let expected_res = RpcSignatureResult { err: None };
|
||||||
|
|
||||||
let expected = json!({
|
struct Notification {
|
||||||
"jsonrpc": "2.0",
|
slot: Slot,
|
||||||
"method": "signatureNotification",
|
id: u64,
|
||||||
"params": {
|
}
|
||||||
"result": {
|
|
||||||
"context": { "slot": 0 },
|
|
||||||
"value": expected_res,
|
|
||||||
},
|
|
||||||
"subscription": 2,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let (response, _) = robust_poll_or_panic(past_bank_recv);
|
|
||||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
|
||||||
|
|
||||||
let expected = json!({
|
let expected_notification = |exp: Notification| -> String {
|
||||||
"jsonrpc": "2.0",
|
let json = json!({
|
||||||
"method": "signatureNotification",
|
"jsonrpc": "2.0",
|
||||||
"params": {
|
"method": "signatureNotification",
|
||||||
"result": {
|
"params": {
|
||||||
"context": { "slot": 1 },
|
"result": {
|
||||||
"value": expected_res,
|
"context": { "slot": exp.slot },
|
||||||
},
|
"value": &expected_res,
|
||||||
"subscription": 3,
|
},
|
||||||
}
|
"subscription": exp.id,
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
serde_json::to_string(&json).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expect to receive a notification from bank 1 because this subscription is
|
||||||
|
// looking for 0 confirmations and so checks the current bank
|
||||||
|
let expected = expected_notification(Notification { slot: 1, id: 1 });
|
||||||
|
let (response, _) = robust_poll_or_panic(past_bank_recv1);
|
||||||
|
assert_eq!(expected, response);
|
||||||
|
|
||||||
|
// Expect to receive a notification from bank 0 because this subscription is
|
||||||
|
// looking for 1 confirmation and so checks the past bank
|
||||||
|
let expected = expected_notification(Notification { slot: 0, id: 2 });
|
||||||
|
let (response, _) = robust_poll_or_panic(past_bank_recv2);
|
||||||
|
assert_eq!(expected, response);
|
||||||
|
|
||||||
|
let expected = expected_notification(Notification { slot: 1, id: 3 });
|
||||||
let (response, _) = robust_poll_or_panic(processed_recv);
|
let (response, _) = robust_poll_or_panic(processed_recv);
|
||||||
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
assert_eq!(expected, response);
|
||||||
|
|
||||||
let sig_subs = subscriptions.signature_subscriptions.read().unwrap();
|
|
||||||
|
|
||||||
// Subscription should be automatically removed after notification
|
// Subscription should be automatically removed after notification
|
||||||
|
let sig_subs = subscriptions.signature_subscriptions.read().unwrap();
|
||||||
assert!(!sig_subs.contains_key(&processed_tx.signatures[0]));
|
assert!(!sig_subs.contains_key(&processed_tx.signatures[0]));
|
||||||
|
assert!(!sig_subs.contains_key(&past_bank_tx.signatures[0]));
|
||||||
// Only one notification is expected for signature processed in previous bank
|
|
||||||
assert_eq!(sig_subs.get(&past_bank_tx.signatures[0]).unwrap().len(), 1);
|
|
||||||
|
|
||||||
// Unprocessed signature subscription should not be removed
|
// Unprocessed signature subscription should not be removed
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -906,7 +954,10 @@ pub(crate) mod tests {
|
|||||||
Subscriber::new_test("slotNotification");
|
Subscriber::new_test("slotNotification");
|
||||||
let sub_id = SubscriptionId::Number(0 as u64);
|
let sub_id = SubscriptionId::Number(0 as u64);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = RpcSubscriptions::new(&exit);
|
let subscriptions = RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
);
|
||||||
subscriptions.add_slot_subscription(sub_id.clone(), subscriber);
|
subscriptions.add_slot_subscription(sub_id.clone(), subscriber);
|
||||||
|
|
||||||
assert!(subscriptions
|
assert!(subscriptions
|
||||||
@@ -944,7 +995,10 @@ pub(crate) mod tests {
|
|||||||
Subscriber::new_test("rootNotification");
|
Subscriber::new_test("rootNotification");
|
||||||
let sub_id = SubscriptionId::Number(0 as u64);
|
let sub_id = SubscriptionId::Number(0 as u64);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = RpcSubscriptions::new(&exit);
|
let subscriptions = RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
||||||
|
);
|
||||||
subscriptions.add_root_subscription(sub_id.clone(), subscriber);
|
subscriptions.add_root_subscription(sub_id.clone(), subscriber);
|
||||||
|
|
||||||
assert!(subscriptions
|
assert!(subscriptions
|
||||||
|
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use solana_ledger::blockstore::Blockstore;
|
use solana_ledger::blockstore::Blockstore;
|
||||||
|
use solana_measure::measure::Measure;
|
||||||
use solana_measure::thread_mem_usage;
|
use solana_measure::thread_mem_usage;
|
||||||
use solana_metrics::{datapoint_debug, inc_new_counter_debug};
|
use solana_metrics::{datapoint_debug, inc_new_counter_debug};
|
||||||
use solana_perf::packet::{Packets, PacketsRecycler};
|
use solana_perf::packet::{Packets, PacketsRecycler};
|
||||||
@@ -184,12 +185,33 @@ impl ServeRepair {
|
|||||||
blockstore: Option<&Arc<Blockstore>>,
|
blockstore: Option<&Arc<Blockstore>>,
|
||||||
requests_receiver: &PacketReceiver,
|
requests_receiver: &PacketReceiver,
|
||||||
response_sender: &PacketSender,
|
response_sender: &PacketSender,
|
||||||
|
max_packets: &mut usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
//TODO cache connections
|
//TODO cache connections
|
||||||
let timeout = Duration::new(1, 0);
|
let timeout = Duration::new(1, 0);
|
||||||
let reqs = requests_receiver.recv_timeout(timeout)?;
|
let mut reqs_v = vec![requests_receiver.recv_timeout(timeout)?];
|
||||||
|
let mut total_packets = reqs_v[0].packets.len();
|
||||||
|
|
||||||
Self::handle_packets(obj, &recycler, blockstore, reqs, response_sender);
|
while let Ok(more) = requests_receiver.try_recv() {
|
||||||
|
total_packets += more.packets.len();
|
||||||
|
if total_packets < *max_packets {
|
||||||
|
// Drop the rest in the channel in case of dos
|
||||||
|
reqs_v.push(more);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut time = Measure::start("repair::handle_packets");
|
||||||
|
for reqs in reqs_v {
|
||||||
|
Self::handle_packets(obj, &recycler, blockstore, reqs, response_sender);
|
||||||
|
}
|
||||||
|
time.stop();
|
||||||
|
if total_packets >= *max_packets {
|
||||||
|
if time.as_ms() > 1000 {
|
||||||
|
*max_packets = (*max_packets * 9) / 10;
|
||||||
|
} else {
|
||||||
|
*max_packets = (*max_packets * 10) / 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,22 +226,26 @@ impl ServeRepair {
|
|||||||
let recycler = PacketsRecycler::default();
|
let recycler = PacketsRecycler::default();
|
||||||
Builder::new()
|
Builder::new()
|
||||||
.name("solana-repair-listen".to_string())
|
.name("solana-repair-listen".to_string())
|
||||||
.spawn(move || loop {
|
.spawn(move || {
|
||||||
let result = Self::run_listen(
|
let mut max_packets = 1024;
|
||||||
&me,
|
loop {
|
||||||
&recycler,
|
let result = Self::run_listen(
|
||||||
blockstore.as_ref(),
|
&me,
|
||||||
&requests_receiver,
|
&recycler,
|
||||||
&response_sender,
|
blockstore.as_ref(),
|
||||||
);
|
&requests_receiver,
|
||||||
match result {
|
&response_sender,
|
||||||
Err(Error::RecvTimeoutError(_)) | Ok(_) => {}
|
&mut max_packets,
|
||||||
Err(err) => info!("repair listener error: {:?}", err),
|
);
|
||||||
};
|
match result {
|
||||||
if exit.load(Ordering::Relaxed) {
|
Err(Error::RecvTimeoutError(_)) | Ok(_) => {}
|
||||||
return;
|
Err(err) => info!("repair listener error: {:?}", err),
|
||||||
|
};
|
||||||
|
if exit.load(Ordering::Relaxed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thread_mem_usage::datapoint("solana-repair-listen");
|
||||||
}
|
}
|
||||||
thread_mem_usage::datapoint("solana-repair-listen");
|
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cluster_info::ClusterInfo,
|
cluster_info::ClusterInfo,
|
||||||
|
commitment::BlockCommitmentCache,
|
||||||
contact_info::ContactInfo,
|
contact_info::ContactInfo,
|
||||||
result::{Error, Result},
|
result::{Error, Result},
|
||||||
};
|
};
|
||||||
@@ -11,9 +12,7 @@ use rand::{Rng, SeedableRng};
|
|||||||
use rand_chacha::ChaChaRng;
|
use rand_chacha::ChaChaRng;
|
||||||
use solana_chacha_cuda::chacha_cuda::chacha_cbc_encrypt_file_many_keys;
|
use solana_chacha_cuda::chacha_cuda::chacha_cbc_encrypt_file_many_keys;
|
||||||
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
use solana_ledger::{bank_forks::BankForks, blockstore::Blockstore};
|
||||||
use solana_runtime::{
|
use solana_runtime::{bank::Bank, storage_utils::archiver_accounts};
|
||||||
bank::Bank, status_cache::SignatureConfirmationStatus, storage_utils::archiver_accounts,
|
|
||||||
};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
@@ -30,6 +29,7 @@ use solana_storage_program::{
|
|||||||
storage_instruction,
|
storage_instruction,
|
||||||
storage_instruction::proof_validation,
|
storage_instruction::proof_validation,
|
||||||
};
|
};
|
||||||
|
use solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY;
|
||||||
use std::{
|
use std::{
|
||||||
cmp,
|
cmp,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -185,6 +185,7 @@ impl StorageStage {
|
|||||||
exit: &Arc<AtomicBool>,
|
exit: &Arc<AtomicBool>,
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
||||||
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (instruction_sender, instruction_receiver) = channel();
|
let (instruction_sender, instruction_receiver) = channel();
|
||||||
|
|
||||||
@@ -256,6 +257,7 @@ impl StorageStage {
|
|||||||
&keypair,
|
&keypair,
|
||||||
&storage_keypair,
|
&storage_keypair,
|
||||||
&transactions_socket,
|
&transactions_socket,
|
||||||
|
&block_commitment_cache,
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
info!("failed to send storage transaction: {:?}", err)
|
info!("failed to send storage transaction: {:?}", err)
|
||||||
@@ -289,6 +291,7 @@ impl StorageStage {
|
|||||||
keypair: &Arc<Keypair>,
|
keypair: &Arc<Keypair>,
|
||||||
storage_keypair: &Arc<Keypair>,
|
storage_keypair: &Arc<Keypair>,
|
||||||
transactions_socket: &UdpSocket,
|
transactions_socket: &UdpSocket,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let working_bank = bank_forks.read().unwrap().working_bank();
|
let working_bank = bank_forks.read().unwrap().working_bank();
|
||||||
let blockhash = working_bank.confirmed_last_blockhash().0;
|
let blockhash = working_bank.confirmed_last_blockhash().0;
|
||||||
@@ -323,8 +326,13 @@ impl StorageStage {
|
|||||||
cluster_info.read().unwrap().my_data().tpu,
|
cluster_info.read().unwrap().my_data().tpu,
|
||||||
)?;
|
)?;
|
||||||
sleep(Duration::from_millis(100));
|
sleep(Duration::from_millis(100));
|
||||||
if Self::poll_for_signature_confirmation(bank_forks, &transaction.signatures[0], 0)
|
if Self::poll_for_signature_confirmation(
|
||||||
.is_ok()
|
bank_forks,
|
||||||
|
block_commitment_cache,
|
||||||
|
&transaction.signatures[0],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
@@ -334,23 +342,24 @@ impl StorageStage {
|
|||||||
|
|
||||||
fn poll_for_signature_confirmation(
|
fn poll_for_signature_confirmation(
|
||||||
bank_forks: &Arc<RwLock<BankForks>>,
|
bank_forks: &Arc<RwLock<BankForks>>,
|
||||||
|
block_commitment_cache: &Arc<RwLock<BlockCommitmentCache>>,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
min_confirmed_blocks: usize,
|
min_confirmed_blocks: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut now = Instant::now();
|
let mut now = Instant::now();
|
||||||
let mut confirmed_blocks = 0;
|
let mut confirmed_blocks = 0;
|
||||||
loop {
|
loop {
|
||||||
let response = bank_forks
|
let working_bank = bank_forks.read().unwrap().working_bank();
|
||||||
.read()
|
let response = working_bank.get_signature_status_slot(signature);
|
||||||
.unwrap()
|
if let Some((slot, status)) = response {
|
||||||
.working_bank()
|
let confirmations = if working_bank.src.roots().contains(&slot) {
|
||||||
.get_signature_confirmation_status(signature);
|
MAX_LOCKOUT_HISTORY + 1
|
||||||
if let Some(SignatureConfirmationStatus {
|
} else {
|
||||||
confirmations,
|
let r_block_commitment_cache = block_commitment_cache.read().unwrap();
|
||||||
status,
|
r_block_commitment_cache
|
||||||
..
|
.get_confirmation_count(slot)
|
||||||
}) = response
|
.unwrap_or(0)
|
||||||
{
|
};
|
||||||
if status.is_ok() {
|
if status.is_ok() {
|
||||||
if confirmed_blocks != confirmations {
|
if confirmed_blocks != confirmations {
|
||||||
now = Instant::now();
|
now = Instant::now();
|
||||||
@@ -655,12 +664,18 @@ mod tests {
|
|||||||
use crate::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
use crate::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::hash::Hasher;
|
use solana_sdk::{
|
||||||
use solana_sdk::signature::{Keypair, Signer};
|
hash::Hasher,
|
||||||
use std::cmp::{max, min};
|
signature::{Keypair, Signer},
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
};
|
||||||
use std::sync::mpsc::channel;
|
use std::{
|
||||||
use std::sync::{Arc, RwLock};
|
cmp::{max, min},
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||||
|
mpsc::channel,
|
||||||
|
Arc, RwLock,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_storage_stage_none_ledger() {
|
fn test_storage_stage_none_ledger() {
|
||||||
@@ -675,6 +690,7 @@ mod tests {
|
|||||||
&[bank.clone()],
|
&[bank.clone()],
|
||||||
vec![0],
|
vec![0],
|
||||||
)));
|
)));
|
||||||
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
||||||
let (_slot_sender, slot_receiver) = channel();
|
let (_slot_sender, slot_receiver) = channel();
|
||||||
let storage_state = StorageState::new(
|
let storage_state = StorageState::new(
|
||||||
&bank.last_blockhash(),
|
&bank.last_blockhash(),
|
||||||
@@ -690,6 +706,7 @@ mod tests {
|
|||||||
&exit.clone(),
|
&exit.clone(),
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
|
block_commitment_cache,
|
||||||
);
|
);
|
||||||
exit.store(true, Ordering::Relaxed);
|
exit.store(true, Ordering::Relaxed);
|
||||||
storage_stage.join().unwrap();
|
storage_stage.join().unwrap();
|
||||||
|
@@ -70,9 +70,14 @@ impl TransactionStatusService {
|
|||||||
}
|
}
|
||||||
.expect("FeeCalculator must exist");
|
.expect("FeeCalculator must exist");
|
||||||
let fee = fee_calculator.calculate_fee(transaction.message());
|
let fee = fee_calculator.calculate_fee(transaction.message());
|
||||||
|
let (writable_keys, readonly_keys) =
|
||||||
|
transaction.message.get_account_keys_by_lock_type();
|
||||||
blockstore
|
blockstore
|
||||||
.write_transaction_status(
|
.write_transaction_status(
|
||||||
(slot, transaction.signatures[0]),
|
slot,
|
||||||
|
transaction.signatures[0],
|
||||||
|
writable_keys,
|
||||||
|
readonly_keys,
|
||||||
&TransactionStatusMeta {
|
&TransactionStatusMeta {
|
||||||
status,
|
status,
|
||||||
fee,
|
fee,
|
||||||
|
@@ -26,6 +26,7 @@ use solana_ledger::{
|
|||||||
snapshot_package::SnapshotPackageSender,
|
snapshot_package::SnapshotPackageSender,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
genesis_config::GenesisConfig,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signer},
|
||||||
};
|
};
|
||||||
@@ -67,6 +68,7 @@ pub struct TvuConfig {
|
|||||||
pub halt_on_trusted_validators_accounts_hash_mismatch: bool,
|
pub halt_on_trusted_validators_accounts_hash_mismatch: bool,
|
||||||
pub trusted_validators: Option<HashSet<Pubkey>>,
|
pub trusted_validators: Option<HashSet<Pubkey>>,
|
||||||
pub accounts_hash_fault_injection_slots: u64,
|
pub accounts_hash_fault_injection_slots: u64,
|
||||||
|
pub genesis_config: GenesisConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tvu {
|
impl Tvu {
|
||||||
@@ -182,9 +184,10 @@ impl Tvu {
|
|||||||
slot_full_senders: vec![blockstream_slot_sender],
|
slot_full_senders: vec![blockstream_slot_sender],
|
||||||
latest_root_senders: vec![ledger_cleanup_slot_sender],
|
latest_root_senders: vec![ledger_cleanup_slot_sender],
|
||||||
accounts_hash_sender: Some(accounts_hash_sender),
|
accounts_hash_sender: Some(accounts_hash_sender),
|
||||||
block_commitment_cache,
|
block_commitment_cache: block_commitment_cache.clone(),
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
rewards_recorder_sender,
|
rewards_recorder_sender,
|
||||||
|
genesis_config: tvu_config.genesis_config,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (replay_stage, root_bank_receiver) = ReplayStage::new(
|
let (replay_stage, root_bank_receiver) = ReplayStage::new(
|
||||||
@@ -226,6 +229,7 @@ impl Tvu {
|
|||||||
&exit,
|
&exit,
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
|
block_commitment_cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
Tvu {
|
Tvu {
|
||||||
@@ -314,7 +318,10 @@ pub mod tests {
|
|||||||
&StorageState::default(),
|
&StorageState::default(),
|
||||||
None,
|
None,
|
||||||
l_receiver,
|
l_receiver,
|
||||||
&Arc::new(RpcSubscriptions::new(&exit)),
|
&Arc::new(RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
||||||
|
)),
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
&leader_schedule_cache,
|
&leader_schedule_cache,
|
||||||
&exit,
|
&exit,
|
||||||
|
@@ -239,7 +239,7 @@ impl Validator {
|
|||||||
|
|
||||||
let blockstore = Arc::new(blockstore);
|
let blockstore = Arc::new(blockstore);
|
||||||
|
|
||||||
let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
|
let subscriptions = Arc::new(RpcSubscriptions::new(&exit, block_commitment_cache.clone()));
|
||||||
|
|
||||||
let rpc_service = config.rpc_ports.map(|(rpc_port, rpc_pubsub_port)| {
|
let rpc_service = config.rpc_ports.map(|(rpc_port, rpc_pubsub_port)| {
|
||||||
if ContactInfo::is_valid_address(&node.info.rpc) {
|
if ContactInfo::is_valid_address(&node.info.rpc) {
|
||||||
@@ -316,7 +316,7 @@ impl Validator {
|
|||||||
std::thread::park();
|
std::thread::park();
|
||||||
}
|
}
|
||||||
|
|
||||||
let poh_config = Arc::new(genesis_config.poh_config);
|
let poh_config = Arc::new(genesis_config.poh_config.clone());
|
||||||
let (mut poh_recorder, entry_receiver) = PohRecorder::new_with_clear_signal(
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new_with_clear_signal(
|
||||||
bank.tick_height(),
|
bank.tick_height(),
|
||||||
bank.last_blockhash(),
|
bank.last_blockhash(),
|
||||||
@@ -443,6 +443,7 @@ impl Validator {
|
|||||||
shred_version: node.info.shred_version,
|
shred_version: node.info.shred_version,
|
||||||
trusted_validators: config.trusted_validators.clone(),
|
trusted_validators: config.trusted_validators.clone(),
|
||||||
accounts_hash_fault_injection_slots: config.accounts_hash_fault_injection_slots,
|
accounts_hash_fault_injection_slots: config.accounts_hash_fault_injection_slots,
|
||||||
|
genesis_config,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -3,8 +3,8 @@ use solana_client::{
|
|||||||
rpc_client::RpcClient,
|
rpc_client::RpcClient,
|
||||||
};
|
};
|
||||||
use solana_core::{
|
use solana_core::{
|
||||||
rpc_pubsub_service::PubSubService, rpc_subscriptions::RpcSubscriptions,
|
commitment::BlockCommitmentCache, rpc_pubsub_service::PubSubService,
|
||||||
validator::TestValidator,
|
rpc_subscriptions::RpcSubscriptions, validator::TestValidator,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
commitment_config::CommitmentConfig, pubkey::Pubkey, rpc_port, signature::Signer,
|
commitment_config::CommitmentConfig, pubkey::Pubkey, rpc_port, signature::Signer,
|
||||||
@@ -15,7 +15,7 @@ use std::{
|
|||||||
net::{IpAddr, SocketAddr},
|
net::{IpAddr, SocketAddr},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc, RwLock,
|
||||||
},
|
},
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@@ -58,7 +58,7 @@ fn test_rpc_client() {
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
while now.elapsed().as_secs() <= 20 {
|
while now.elapsed().as_secs() <= 20 {
|
||||||
let response = client
|
let response = client
|
||||||
.confirm_transaction_with_commitment(signature.as_str(), CommitmentConfig::default())
|
.confirm_transaction_with_commitment(&signature, CommitmentConfig::default())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if response.value {
|
if response.value {
|
||||||
@@ -85,7 +85,10 @@ fn test_slot_subscription() {
|
|||||||
rpc_port::DEFAULT_RPC_PUBSUB_PORT,
|
rpc_port::DEFAULT_RPC_PUBSUB_PORT,
|
||||||
);
|
);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
|
let subscriptions = Arc::new(RpcSubscriptions::new(
|
||||||
|
&exit,
|
||||||
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
||||||
|
));
|
||||||
let pubsub_service = PubSubService::new(&subscriptions, pubsub_addr, &exit);
|
let pubsub_service = PubSubService::new(&subscriptions, pubsub_addr, &exit);
|
||||||
std::thread::sleep(Duration::from_millis(400));
|
std::thread::sleep(Duration::from_millis(400));
|
||||||
|
|
||||||
|
@@ -9,15 +9,12 @@ use reqwest::{self, header::CONTENT_TYPE};
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
rpc_client::{get_rpc_request_str, RpcClient},
|
rpc_client::{get_rpc_request_str, RpcClient},
|
||||||
rpc_response::Response,
|
rpc_response::{Response, RpcSignatureResult},
|
||||||
};
|
};
|
||||||
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig, hash::Hash, pubkey::Pubkey, system_transaction,
|
||||||
hash::Hash,
|
transaction::Transaction,
|
||||||
pubkey::Pubkey,
|
|
||||||
system_transaction,
|
|
||||||
transaction::{self, Transaction},
|
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
@@ -224,7 +221,7 @@ fn test_rpc_subscriptions() {
|
|||||||
let mut rt = Runtime::new().unwrap();
|
let mut rt = Runtime::new().unwrap();
|
||||||
let rpc_pubsub_url = format!("ws://{}/", leader_data.rpc_pubsub);
|
let rpc_pubsub_url = format!("ws://{}/", leader_data.rpc_pubsub);
|
||||||
|
|
||||||
let (status_sender, status_receiver) = channel::<(String, Response<transaction::Result<()>>)>();
|
let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
|
||||||
let status_sender = Arc::new(Mutex::new(status_sender));
|
let status_sender = Arc::new(Mutex::new(status_sender));
|
||||||
let (sent_sender, sent_receiver) = channel::<()>();
|
let (sent_sender, sent_receiver) = channel::<()>();
|
||||||
let sent_sender = Arc::new(Mutex::new(sent_sender));
|
let sent_sender = Arc::new(Mutex::new(sent_sender));
|
||||||
@@ -296,7 +293,7 @@ fn test_rpc_subscriptions() {
|
|||||||
let timeout = deadline.saturating_duration_since(Instant::now());
|
let timeout = deadline.saturating_duration_since(Instant::now());
|
||||||
match status_receiver.recv_timeout(timeout) {
|
match status_receiver.recv_timeout(timeout) {
|
||||||
Ok((sig, result)) => {
|
Ok((sig, result)) => {
|
||||||
assert!(result.value.is_ok());
|
assert!(result.value.err.is_none());
|
||||||
assert!(signature_set.remove(&sig));
|
assert!(signature_set.remove(&sig));
|
||||||
}
|
}
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
|
@@ -3,28 +3,35 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use log::*;
|
use log::*;
|
||||||
use solana_core::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
use solana_core::{
|
||||||
use solana_core::storage_stage::{test_cluster_info, SLOTS_PER_TURN_TEST};
|
commitment::BlockCommitmentCache,
|
||||||
use solana_core::storage_stage::{StorageStage, StorageState};
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
use solana_ledger::bank_forks::BankForks;
|
storage_stage::{test_cluster_info, StorageStage, StorageState, SLOTS_PER_TURN_TEST},
|
||||||
use solana_ledger::blockstore_processor;
|
};
|
||||||
use solana_ledger::entry;
|
use solana_ledger::{
|
||||||
use solana_ledger::{blockstore::Blockstore, create_new_tmp_ledger};
|
bank_forks::BankForks, blockstore::Blockstore, blockstore_processor, create_new_tmp_ledger,
|
||||||
|
entry,
|
||||||
|
};
|
||||||
use solana_runtime::bank::Bank;
|
use solana_runtime::bank::Bank;
|
||||||
use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
|
use solana_sdk::{
|
||||||
use solana_sdk::hash::Hash;
|
clock::DEFAULT_TICKS_PER_SLOT,
|
||||||
use solana_sdk::message::Message;
|
hash::Hash,
|
||||||
use solana_sdk::pubkey::Pubkey;
|
message::Message,
|
||||||
use solana_sdk::signature::{Keypair, Signer};
|
pubkey::Pubkey,
|
||||||
use solana_sdk::transaction::Transaction;
|
signature::{Keypair, Signer},
|
||||||
use solana_storage_program::storage_instruction;
|
transaction::Transaction,
|
||||||
use solana_storage_program::storage_instruction::StorageAccountType;
|
};
|
||||||
use std::fs::remove_dir_all;
|
use solana_storage_program::storage_instruction::{self, StorageAccountType};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::{
|
||||||
use std::sync::mpsc::channel;
|
fs::remove_dir_all,
|
||||||
use std::sync::{Arc, RwLock};
|
sync::{
|
||||||
use std::thread::sleep;
|
atomic::{AtomicBool, Ordering},
|
||||||
use std::time::Duration;
|
mpsc::channel,
|
||||||
|
Arc, RwLock,
|
||||||
|
},
|
||||||
|
thread::sleep,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_storage_stage_process_account_proofs() {
|
fn test_storage_stage_process_account_proofs() {
|
||||||
@@ -52,6 +59,7 @@ mod tests {
|
|||||||
&[bank.clone()],
|
&[bank.clone()],
|
||||||
vec![0],
|
vec![0],
|
||||||
)));
|
)));
|
||||||
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
||||||
let cluster_info = test_cluster_info(&keypair.pubkey());
|
let cluster_info = test_cluster_info(&keypair.pubkey());
|
||||||
|
|
||||||
let (bank_sender, bank_receiver) = channel();
|
let (bank_sender, bank_receiver) = channel();
|
||||||
@@ -69,6 +77,7 @@ mod tests {
|
|||||||
&exit.clone(),
|
&exit.clone(),
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
|
block_commitment_cache,
|
||||||
);
|
);
|
||||||
bank_sender.send(vec![bank.clone()]).unwrap();
|
bank_sender.send(vec![bank.clone()]).unwrap();
|
||||||
|
|
||||||
@@ -171,6 +180,7 @@ mod tests {
|
|||||||
&[bank.clone()],
|
&[bank.clone()],
|
||||||
vec![0],
|
vec![0],
|
||||||
)));
|
)));
|
||||||
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
||||||
|
|
||||||
let cluster_info = test_cluster_info(&keypair.pubkey());
|
let cluster_info = test_cluster_info(&keypair.pubkey());
|
||||||
let (bank_sender, bank_receiver) = channel();
|
let (bank_sender, bank_receiver) = channel();
|
||||||
@@ -188,6 +198,7 @@ mod tests {
|
|||||||
&exit.clone(),
|
&exit.clone(),
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&cluster_info,
|
&cluster_info,
|
||||||
|
block_commitment_cache,
|
||||||
);
|
);
|
||||||
bank_sender.send(vec![bank.clone()]).unwrap();
|
bank_sender.send(vec![bank.clone()]).unwrap();
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-crate-features"
|
name = "solana-crate-features"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Crate Features"
|
description = "Solana Crate Features"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
BIN
docs/src/.gitbook/assets/ledger-live-enable-developer-mode.png
Normal file
BIN
docs/src/.gitbook/assets/ledger-live-enable-developer-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 KiB |
BIN
docs/src/.gitbook/assets/ledger-live-install-solana-app.png
Normal file
BIN
docs/src/.gitbook/assets/ledger-live-install-solana-app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 195 KiB |
@@ -6,10 +6,11 @@
|
|||||||
* [Trust Wallet](wallet/trust-wallet.md)
|
* [Trust Wallet](wallet/trust-wallet.md)
|
||||||
* [Ledger Live](wallet/ledger-live.md)
|
* [Ledger Live](wallet/ledger-live.md)
|
||||||
* [Command-line Wallets](wallet/cli-wallets.md)
|
* [Command-line Wallets](wallet/cli-wallets.md)
|
||||||
* [Hardware Wallets](remote-wallet/README.md)
|
|
||||||
* [Ledger Hardware Wallet](remote-wallet/ledger.md)
|
|
||||||
* [Paper Wallet](paper-wallet/README.md)
|
* [Paper Wallet](paper-wallet/README.md)
|
||||||
* [Paper Wallet Usage](paper-wallet/paper-wallet-usage.md)
|
* [Paper Wallet Usage](paper-wallet/paper-wallet-usage.md)
|
||||||
|
* [Hardware Wallets](remote-wallet/README.md)
|
||||||
|
* [Ledger Hardware Wallet](remote-wallet/ledger.md)
|
||||||
|
* [Support / Troubleshooting](wallet/support.md)
|
||||||
* [Command Line Guide](cli/README.md)
|
* [Command Line Guide](cli/README.md)
|
||||||
* [Install the Solana Command Line Tool Suite](cli/install-solana-cli-tools.md)
|
* [Install the Solana Command Line Tool Suite](cli/install-solana-cli-tools.md)
|
||||||
* [Generate Keys](cli/generate-keys.md)
|
* [Generate Keys](cli/generate-keys.md)
|
||||||
|
@@ -14,7 +14,6 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
* [confirmTransaction](jsonrpc-api.md#confirmtransaction)
|
|
||||||
* [getAccountInfo](jsonrpc-api.md#getaccountinfo)
|
* [getAccountInfo](jsonrpc-api.md#getaccountinfo)
|
||||||
* [getBalance](jsonrpc-api.md#getbalance)
|
* [getBalance](jsonrpc-api.md#getbalance)
|
||||||
* [getBlockCommitment](jsonrpc-api.md#getblockcommitment)
|
* [getBlockCommitment](jsonrpc-api.md#getblockcommitment)
|
||||||
@@ -22,6 +21,8 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
|
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
|
||||||
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
|
||||||
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
|
||||||
|
* [getConfirmedSignaturesForAddress](jsonrpc-api.md#getconfirmedsignaturesforaddress)
|
||||||
|
* [getConfirmedTransaction](jsonrpc-api.md#getconfirmedtransaction)
|
||||||
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
|
||||||
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
|
||||||
* [getFeeCalculatorForBlockhash](jsonrpc-api.md#getfeecalculatorforblockhash)
|
* [getFeeCalculatorForBlockhash](jsonrpc-api.md#getfeecalculatorforblockhash)
|
||||||
@@ -33,7 +34,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||||||
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
|
* [getMinimumBalanceForRentExemption](jsonrpc-api.md#getminimumbalanceforrentexemption)
|
||||||
* [getProgramAccounts](jsonrpc-api.md#getprogramaccounts)
|
* [getProgramAccounts](jsonrpc-api.md#getprogramaccounts)
|
||||||
* [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash)
|
* [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash)
|
||||||
* [getSignatureStatus](jsonrpc-api.md#getsignaturestatus)
|
* [getSignatureStatuses](jsonrpc-api.md#getsignaturestatuses)
|
||||||
* [getSlot](jsonrpc-api.md#getslot)
|
* [getSlot](jsonrpc-api.md#getslot)
|
||||||
* [getSlotLeader](jsonrpc-api.md#getslotleader)
|
* [getSlotLeader](jsonrpc-api.md#getslotleader)
|
||||||
* [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment)
|
* [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment)
|
||||||
@@ -116,29 +117,6 @@ Many methods that take a commitment parameter return an RpcResponse JSON object
|
|||||||
|
|
||||||
## JSON RPC API Reference
|
## JSON RPC API Reference
|
||||||
|
|
||||||
### confirmTransaction
|
|
||||||
|
|
||||||
Returns a transaction receipt
|
|
||||||
|
|
||||||
#### Parameters:
|
|
||||||
|
|
||||||
* `<string>` - Signature of Transaction to confirm, as base-58 encoded string
|
|
||||||
* `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
|
||||||
|
|
||||||
#### Results:
|
|
||||||
|
|
||||||
* `RpcResponse<bool>` - RpcResponse JSON object with `value` field set to Transaction status, boolean true if Transaction is confirmed
|
|
||||||
|
|
||||||
#### Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
// Request
|
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"confirmTransaction", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
|
|
||||||
|
|
||||||
// Result
|
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":true},"id":1}
|
|
||||||
```
|
|
||||||
|
|
||||||
### getAccountInfo
|
### getAccountInfo
|
||||||
|
|
||||||
Returns all information associated with the account of provided Pubkey
|
Returns all information associated with the account of provided Pubkey
|
||||||
@@ -298,12 +276,13 @@ The result field will be an object with the following fields:
|
|||||||
* `transactions: <array>` - an array of JSON objects containing:
|
* `transactions: <array>` - an array of JSON objects containing:
|
||||||
* `transaction: <object|string>` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
* `transaction: <object|string>` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||||
* `meta: <object>` - transaction status metadata object, containing `null` or:
|
* `meta: <object>` - transaction status metadata object, containing `null` or:
|
||||||
* `status: <object>` - Transaction status:
|
* `err: <object | null>` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
* `"Ok": null` - Transaction was successful
|
* `fee: <u64>` - fee this transaction was charged, as u64 integer
|
||||||
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L18)
|
* `preBalances: <array>` - array of u64 account balances from before the transaction was processed
|
||||||
* `fee: <u64>` - fee this transaction was charged, as u64 integer
|
* `postBalances: <array>` - array of u64 account balances after the transaction was processed
|
||||||
* `preBalances: <array>` - array of u64 account balances from before the transaction was processed
|
* DEPRECATED: `status: <object>` - Transaction status
|
||||||
* `postBalances: <array>` - array of u64 account balances after the transaction was processed
|
* `"Ok": <null>` - Transaction was successful
|
||||||
|
* `"Err": <ERR>` - Transaction failed with TransactionError
|
||||||
* `rewards: <array>` - an array of JSON objects containing:
|
* `rewards: <array>` - an array of JSON objects containing:
|
||||||
* `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
* `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
||||||
* `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
* `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
||||||
@@ -315,13 +294,13 @@ The result field will be an object with the following fields:
|
|||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]}' localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"fee":1000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary"]}' localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"fee":1000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Transaction Structure
|
#### Transaction Structure
|
||||||
@@ -368,6 +347,72 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m
|
|||||||
{"jsonrpc":"2.0","result":[5,6,7,8,9,10],"id":1}
|
{"jsonrpc":"2.0","result":[5,6,7,8,9,10],"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### getConfirmedSignaturesForAddress
|
||||||
|
|
||||||
|
Returns a list of all the confirmed signatures for transactions involving an address, within a specified Slot range. Max range allowed is 10_000 Slots.
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
|
||||||
|
* `<string>` - account address as base-58 encoded string
|
||||||
|
* `<u64>` - start slot, inclusive
|
||||||
|
* `<u64>` - end slot, inclusive
|
||||||
|
|
||||||
|
#### Results:
|
||||||
|
|
||||||
|
The result field will be an array of:
|
||||||
|
* `<string>` - transaction signature as base-58 encoded string
|
||||||
|
|
||||||
|
The signatures will be ordered based on the Slot in which they were confirmed in, from lowest to highest Slot
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", 0, 100]}' localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","4LQ14a7BYY27578Uj8LPCaVhSdJGLn9DJqnUJHpy95FMqdKf9acAhUhecPQNjNUy6VoNFUbvwYkPociFSf87cWbG"]},"id":1}
|
||||||
|
```
|
||||||
|
|
||||||
|
### getConfirmedTransaction
|
||||||
|
|
||||||
|
Returns transaction details for a confirmed transaction
|
||||||
|
|
||||||
|
#### Parameters:
|
||||||
|
|
||||||
|
* `<string>` - transaction signature as base-58 encoded string
|
||||||
|
* `<string>` - (optional) encoding for the returned Transaction, either "json" or "binary". If not provided, the default encoding is JSON.
|
||||||
|
|
||||||
|
#### Results:
|
||||||
|
|
||||||
|
The result field will be an object with the following fields:
|
||||||
|
* `slot: <u64>` - the slot this transaction was processed in
|
||||||
|
* `transaction: <object|string>` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter
|
||||||
|
* `meta: <object>` - transaction status metadata object, containing `null` or:
|
||||||
|
* `err: <object | null>` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
|
* `fee: <u64>` - fee this transaction was charged, as u64 integer
|
||||||
|
* `preBalances: <array>` - array of u64 account balances from before the transaction was processed
|
||||||
|
* `postBalances: <array>` - array of u64 account balances after the transaction was processed
|
||||||
|
* DEPRECATED: `status: <object>` - Transaction status
|
||||||
|
* `"Ok": <null>` - Transaction was successful
|
||||||
|
* `"Err": <ERR>` - Transaction failed with TransactionError
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", "json"]}' localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":{"slot":430,"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}},"id":1}
|
||||||
|
|
||||||
|
// Request
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", "binary"]}' localhost:8899
|
||||||
|
|
||||||
|
// Result
|
||||||
|
{"jsonrpc":"2.0","result":{"slot":430,"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}},"id":1}
|
||||||
|
```
|
||||||
|
|
||||||
### getEpochInfo
|
### getEpochInfo
|
||||||
|
|
||||||
Returns information about the current epoch
|
Returns information about the current epoch
|
||||||
@@ -654,16 +699,18 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
|||||||
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"blockhash":"CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR","feeCalculator":{"burnPercent":50,"lamportsPerSignature":5000,"maxLamportsPerSignature":10000,"minLamportsPerSignature":5000,"targetLamportsPerSignature":1000,"targetSignaturesPerSlot":20000}}},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"blockhash":"CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR","feeCalculator":{"burnPercent":50,"lamportsPerSignature":5000,"maxLamportsPerSignature":10000,"minLamportsPerSignature":5000,"targetLamportsPerSignature":1000,"targetSignaturesPerSlot":20000}}},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getSignatureStatus
|
### getSignatureStatuses
|
||||||
|
|
||||||
Returns the status of a given signature. This method is similar to [confirmTransaction](jsonrpc-api.md#confirmtransaction) but provides more resolution for error events.
|
Returns the statuses of a list of signatures. Unless the
|
||||||
|
`searchTransactionHistory` configuration parameter is included, this method only
|
||||||
|
searches the recent status cache of signatures, which retains statuses for all
|
||||||
|
active slots plus `MAX_RECENT_BLOCKHASHES` rooted slots.
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
* `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings
|
* `<array>` - An array of transaction signatures to confirm, as base-58 encoded strings
|
||||||
* `<object>` - (optional) Extended Rpc configuration, containing the following optional fields:
|
* `<object>` - (optional) Configuration object containing the following field:
|
||||||
* `commitment: <string>` - [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
* `searchTransactionHistory: <bool>` - if true, a Solana node will search its ledger cache for any signatures not found in the recent status cache
|
||||||
* `searchTransactionHistory: <bool>` - whether to search the ledger transaction status cache, which may be expensive
|
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
@@ -677,21 +724,25 @@ An array of:
|
|||||||
* `<object>`
|
* `<object>`
|
||||||
* `slot: <u64>` - The slot the transaction was processed
|
* `slot: <u64>` - The slot the transaction was processed
|
||||||
* `confirmations: <usize | null>` - Number of blocks since signature confirmation, null if rooted
|
* `confirmations: <usize | null>` - Number of blocks since signature confirmation, null if rooted
|
||||||
* `status: <object>` - Transaction status
|
* `err: <object | null>` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
||||||
|
* DEPRECATED: `status: <object>` - Transaction status
|
||||||
* `"Ok": <null>` - Transaction was successful
|
* `"Ok": <null>` - Transaction was successful
|
||||||
* `"Err": <ERR>` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
|
* `"Err": <ERR>` - Transaction failed with TransactionError
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]]}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatuses", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]}' http://localhost:8899
|
||||||
|
|
||||||
|
// Request with configuration
|
||||||
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatuses", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"], {"searchTransactionHistory": true}]}' http://localhost:8899
|
||||||
|
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 72, "confirmations": 10, "status": {"Ok": null}}, null]},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 72, "confirmations": 10, "err": null, "status": {"Ok": null}}, null]},"id":1}
|
||||||
|
|
||||||
// Result, first transaction rooted
|
// Result, first transaction rooted
|
||||||
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 48, "confirmations": null, "status": {"Ok": null}}, null]},"id":1}
|
{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 48, "confirmations": null, "err": null, "status": {"Ok": null}}, null]},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getSlot
|
### getSlot
|
||||||
@@ -889,7 +940,7 @@ The result field will be a JSON object with the following fields:
|
|||||||
// Request
|
// Request
|
||||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
|
||||||
// Result
|
// Result
|
||||||
{"jsonrpc":"2.0","result":{"solana-core": "1.0.12"},"id":1}
|
{"jsonrpc":"2.0","result":{"solana-core": "1.0.17"},"id":1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### getVoteAccounts
|
### getVoteAccounts
|
||||||
@@ -1200,7 +1251,7 @@ Subscribe to a transaction signature to receive notification when the transactio
|
|||||||
#### Notification Format:
|
#### Notification Format:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": "Confirmed","subscription":0}}
|
{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": {"err": null}, "subscription":0}}
|
||||||
```
|
```
|
||||||
|
|
||||||
### signatureUnsubscribe
|
### signatureUnsubscribe
|
||||||
|
@@ -33,11 +33,13 @@ want to perform an action on the stake account you create next.
|
|||||||
Now, create a stake account:
|
Now, create a stake account:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana create-stake-account --from <KEYPAIR> stake-account.json <AMOUNT> --stake-authority <KEYPAIR> --withdraw-authority <KEYPAIR>
|
solana create-stake-account --from <KEYPAIR> stake-account.json <AMOUNT> \
|
||||||
|
--stake-authority <KEYPAIR> --withdraw-authority <KEYPAIR> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<AMOUNT>` tokens are transferred from the account at `<KEYPAIR>` to a new
|
`<AMOUNT>` tokens are transferred from the account at the "from" `<KEYPAIR>` to
|
||||||
stake account at the public key of stake-account.json.
|
a new stake account at the public key of stake-account.json.
|
||||||
|
|
||||||
The stake-account.json file can now be discarded. To authorize additional
|
The stake-account.json file can now be discarded. To authorize additional
|
||||||
actions, you will use the `--stake-authority` or `withdraw-authority` keypair,
|
actions, you will use the `--stake-authority` or `withdraw-authority` keypair,
|
||||||
@@ -72,7 +74,9 @@ Stake and withdraw authorities can be set when creating an account via the
|
|||||||
run:
|
run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana stake-authorize <STAKE_ACCOUNT_ADDRESS> --stake-authority <KEYPAIR> --new-stake-authority <PUBKEY>
|
solana stake-authorize <STAKE_ACCOUNT_ADDRESS> \
|
||||||
|
--stake-authority <KEYPAIR> --new-stake-authority <PUBKEY> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
This will use the existing stake authority `<KEYPAIR>` to authorize a new stake
|
This will use the existing stake authority `<KEYPAIR>` to authorize a new stake
|
||||||
@@ -87,7 +91,8 @@ addresses can be cumbersome. Fortunately, you can derive stake addresses using
|
|||||||
the `--seed` option:
|
the `--seed` option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana create-stake-account --from <KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed <STRING> <AMOUNT> --stake-authority <PUBKEY> --withdraw-authority <PUBKEY>
|
solana create-stake-account --from <KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed <STRING> <AMOUNT> \
|
||||||
|
--stake-authority <PUBKEY> --withdraw-authority <PUBKEY> --fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STRING>` is an arbitrary string up to 32 bytes, but will typically be a
|
`<STRING>` is an arbitrary string up to 32 bytes, but will typically be a
|
||||||
@@ -122,12 +127,13 @@ is the vote account address. Choose a validator and use its vote account
|
|||||||
address in `solana delegate-stake`:
|
address in `solana delegate-stake`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS>
|
solana delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<KEYPAIR>` authorizes the operation on the account with address
|
The stake authority `<KEYPAIR>` authorizes the operation on the account with
|
||||||
`<STAKE_ACCOUNT_ADDRESS>`. The stake is delegated to the vote account with
|
address `<STAKE_ACCOUNT_ADDRESS>`. The stake is delegated to the vote account
|
||||||
address `<VOTE_ACCOUNT_ADDRESS>`.
|
with address `<VOTE_ACCOUNT_ADDRESS>`.
|
||||||
|
|
||||||
After delegating stake, use `solana stake-account` to observe the changes
|
After delegating stake, use `solana stake-account` to observe the changes
|
||||||
to the stake account:
|
to the stake account:
|
||||||
@@ -155,11 +161,12 @@ Once delegated, you can undelegate stake with the `solana deactivate-stake`
|
|||||||
command:
|
command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana deactivate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS>
|
solana deactivate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<KEYPAIR>` authorizes the operation on the account with address
|
The stake authority `<KEYPAIR>` authorizes the operation on the account
|
||||||
`<STAKE_ACCOUNT_ADDRESS>`.
|
with address `<STAKE_ACCOUNT_ADDRESS>`.
|
||||||
|
|
||||||
Note that stake takes several epochs to "cool down". Attempts to delegate stake
|
Note that stake takes several epochs to "cool down". Attempts to delegate stake
|
||||||
in the cool down period will fail.
|
in the cool down period will fail.
|
||||||
@@ -169,12 +176,13 @@ in the cool down period will fail.
|
|||||||
Transfer tokens out of a stake account with the `solana withdraw-stake` command:
|
Transfer tokens out of a stake account with the `solana withdraw-stake` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana withdraw-stake --withdraw-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>
|
solana withdraw-stake --withdraw-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, the stake authority
|
||||||
withdraw authority, and `<AMOUNT>` is the number of tokens to transfer to
|
`<KEYPAIR>` is the withdraw authority, and `<AMOUNT>` is the number of tokens
|
||||||
`<RECIPIENT_ADDRESS>`.
|
to transfer to `<RECIPIENT_ADDRESS>`.
|
||||||
|
|
||||||
## Split Stake
|
## Split Stake
|
||||||
|
|
||||||
@@ -184,12 +192,14 @@ currently staked, cooling down, or locked up. To transfer tokens from an
|
|||||||
existing stake account to a new one, use the `solana split-stake` command:
|
existing stake account to a new one, use the `solana split-stake` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana split-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT>
|
solana split-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT> \
|
||||||
|
--fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, `<KEYPAIR>` is the
|
`<STAKE_ACCOUNT_ADDRESS>` is the existing stake account, the stake authority
|
||||||
stake authority, `<NEW_STAKE_ACCOUNT_KEYPAIR>` is the keypair for the new account,
|
`<KEYPAIR>` is the stake authority, `<NEW_STAKE_ACCOUNT_KEYPAIR>` is the
|
||||||
and `<AMOUNT>` is the number of tokens to transfer to the new account.
|
keypair for the new account, and `<AMOUNT>` is the number of tokens to transfer
|
||||||
|
to the new account.
|
||||||
|
|
||||||
To split a stake account into a derived account address, use the `--seed`
|
To split a stake account into a derived account address, use the `--seed`
|
||||||
option. See
|
option. See
|
||||||
|
@@ -84,10 +84,10 @@ pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana transfer --from <SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> 5 --url http://devnet.solana.com
|
solana transfer --from <KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> 5--url http://devnet.solana.com --fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
where you replace `<SENDER_KEYPAIR>` with the path to a keypair in your wallet,
|
where you replace `<KEYPAIR>` with the path to a keypair in your wallet,
|
||||||
and replace `<RECIPIENT_ACCOUNT_ADDRESS>` with the output of `solana-keygen new` above.
|
and replace `<RECIPIENT_ACCOUNT_ADDRESS>` with the output of `solana-keygen new` above.
|
||||||
|
|
||||||
Confirm the updated balances with `solana balance`:
|
Confirm the updated balances with `solana balance`:
|
||||||
@@ -107,7 +107,7 @@ tokens to transfer. Once you have that collected, you can transfer tokens
|
|||||||
with the `solana transfer` command:
|
with the `solana transfer` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
solana transfer --from <SENDER_KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> <AMOUNT>
|
solana transfer --from <KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> <AMOUNT> --fee-payer <KEYPAIR>
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm the updated balances with `solana balance`:
|
Confirm the updated balances with `solana balance`:
|
||||||
|
@@ -171,7 +171,7 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
|
|||||||
## Usage
|
## Usage
|
||||||
### solana-cli
|
### solana-cli
|
||||||
```text
|
```text
|
||||||
solana-cli 1.0.12 [channel=unknown commit=unknown]
|
solana-cli 1.0.17 [channel=unknown commit=unknown]
|
||||||
Blockchain, Rebuilt for Scale
|
Blockchain, Rebuilt for Scale
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
|
@@ -289,3 +289,7 @@ Refer to the following page for a comprehensive guide on delegating stake:
|
|||||||
---
|
---
|
||||||
|
|
||||||
{% page-ref page="../api-reference/cli.md" %}
|
{% page-ref page="../api-reference/cli.md" %}
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Check out our [Wallet Support Page](../wallet/support.md) for ways to get help.
|
||||||
|
@@ -6,64 +6,8 @@ secure transaction signing.
|
|||||||
|
|
||||||
## Before You Begin
|
## Before You Begin
|
||||||
|
|
||||||
|
- [Set up a Ledger Nano S with the Solana App](../wallet/ledger-live.md)
|
||||||
- [Install the Solana command-line tools](../cli/install-solana-cli-tools.md)
|
- [Install the Solana command-line tools](../cli/install-solana-cli-tools.md)
|
||||||
- [Initialize your Ledger Nano S](https://support.ledger.com/hc/en-us/articles/360000613793)
|
|
||||||
- [Install the latest device firmware](https://support.ledgerwallet.com/hc/en-us/articles/360002731113-Update-Ledger-Nano-S-firmware)
|
|
||||||
|
|
||||||
## Install the Solana App on Ledger Nano S
|
|
||||||
|
|
||||||
The Solana Ledger app is not yet available on Ledger Live. Until it is, you
|
|
||||||
can install a development version of the app from the command-line. Note that
|
|
||||||
because the app is not installed via Ledger Live, you will need to approve
|
|
||||||
installation from an "unsafe" manager, as well as see the message, "This app
|
|
||||||
is not genuine" each time you open the app. Once the app is available on
|
|
||||||
Ledger Live, you can reinstall the app from there, and the message will no
|
|
||||||
longer be displayed.
|
|
||||||
|
|
||||||
1. Connect your Ledger device via USB and enter your pin to unlock it
|
|
||||||
2. Download and run the Solana Ledger app installer:
|
|
||||||
```text
|
|
||||||
curl -sSLf https://github.com/solana-labs/ledger-app-solana/releases/download/v0.1.1/install.sh | sh
|
|
||||||
```
|
|
||||||
3. When prompted, approve the "unsafe" manager on your device
|
|
||||||
4. When prompted, approve the installation on your device
|
|
||||||
5. An installation window appears and your device will display Processing…
|
|
||||||
6. The app installation is confirmed
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
|
|
||||||
If you encounter the following error:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/runpy.py", line 193, in _run_module_as_main
|
|
||||||
"__main__", mod_spec)
|
|
||||||
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
|
|
||||||
exec(code, run_globals)
|
|
||||||
File "ledger-env/lib/python3.7/site-packages/ledgerblue/loadApp.py", line 197, in <module>
|
|
||||||
dongle = getDongle(args.apdu)
|
|
||||||
File "ledger-env/lib/python3.7/site-packages/ledgerblue/comm.py", line 216, in getDongle
|
|
||||||
dev.open_path(hidDevicePath)
|
|
||||||
File "hid.pyx", line 72, in hid.device.open_path
|
|
||||||
OSError: open failed
|
|
||||||
```
|
|
||||||
|
|
||||||
To fix, check the following:
|
|
||||||
|
|
||||||
1. Ensure your Ledger device is connected to USB
|
|
||||||
2. Ensure your Ledger device is unlocked and not waiting for you to enter your pin
|
|
||||||
3. Ensure the Ledger Live application is not open
|
|
||||||
|
|
||||||
### Future: Installation once the Solana app is on Ledger Live
|
|
||||||
|
|
||||||
- [Install Ledger Live](https://support.ledger.com/hc/en-us/articles/360006395553/) software on your computer
|
|
||||||
|
|
||||||
1. Open the Manager in Ledger Live
|
|
||||||
2. Connect your Ledger device via USB and enter your pin to unlock it
|
|
||||||
3. When prompted, approve the manager on your device
|
|
||||||
4. Find Solana in the app catalog and click Install
|
|
||||||
5. An installation window appears and your device will display Processing…
|
|
||||||
6. The app installation is confirmed
|
|
||||||
|
|
||||||
## Use Ledger Device with Solana CLI
|
## Use Ledger Device with Solana CLI
|
||||||
|
|
||||||
@@ -98,4 +42,4 @@ anywhere you see an option or argument that accepts a `<KEYPAIR>`.
|
|||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
Email maintainers@solana.com
|
Check out our [Wallet Support Page](../wallet/support.md) for ways to get help.
|
||||||
|
@@ -16,6 +16,7 @@ line tools](../remote-wallet/ledger.md).
|
|||||||
- Order a [Nano S from Ledger](https://shop.ledger.com/products/ledger-nano-s)
|
- Order a [Nano S from Ledger](https://shop.ledger.com/products/ledger-nano-s)
|
||||||
- Follow the instructions for device setup included in the package,
|
- Follow the instructions for device setup included in the package,
|
||||||
or [Ledger's Start page](https://www.ledger.com/start/)
|
or [Ledger's Start page](https://www.ledger.com/start/)
|
||||||
|
- [Install the latest device firmware](https://support.ledgerwallet.com/hc/en-us/articles/360002731113-Update-Ledger-Nano-S-firmware)
|
||||||
|
|
||||||
##Install Ledger Live
|
##Install Ledger Live
|
||||||
- Install [Ledger Live desktop software](https://www.ledger.com/ledger-live/),
|
- Install [Ledger Live desktop software](https://www.ledger.com/ledger-live/),
|
||||||
@@ -30,13 +31,20 @@ line tools](../remote-wallet/ledger.md).
|
|||||||
- Open Ledger Live
|
- Open Ledger Live
|
||||||
- Currently Ledger Live needs to be in "Developer Mode"
|
- Currently Ledger Live needs to be in "Developer Mode"
|
||||||
(Settings > Experimental Features > Developer Mode) to see our app.
|
(Settings > Experimental Features > Developer Mode) to see our app.
|
||||||
|

|
||||||
|
|
||||||
- Go to Manager in the app and find "Solana" in the App Catalog and
|
- Go to Manager in the app and find "Solana" in the App Catalog and
|
||||||
click Install
|
click Install
|
||||||
- Make sure your device is plugged in via USB and is unlocked with its PIN
|
- Make sure your device is plugged in via USB and is unlocked with its PIN
|
||||||
- You may be prompted on the Nano S to confirm the install of Solana App
|
- You may be prompted on the Nano S to confirm the install of Solana App
|
||||||
- "Solana" should now show as "Installed" in the Ledger Live Manager
|
- "Solana" should now show as "Installed" in the Ledger Live Manager
|
||||||
|

|
||||||
|
|
||||||
##Interact with Solana network
|
##Interact with Solana network
|
||||||
- To interact with your Ledger wallet on our live network, please see our
|
- To interact with your Ledger wallet on our live network, please see our
|
||||||
instructions on how to [use a Ledger Nano S with the Solana command
|
instructions on how to
|
||||||
line tools](../remote-wallet/ledger.md).
|
[use a Ledger Nano S with the Solana command line tools](../remote-wallet/ledger.md).
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Check out our [Wallet Support Page](../wallet/support.md) for ways to get help.
|
||||||
|
13
docs/src/wallet/support.md
Normal file
13
docs/src/wallet/support.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Support / Troubleshooting
|
||||||
|
If you have questions or are having trouble setting up or using your wallet
|
||||||
|
of choice, please make sure you've read through all the relevant pages in our
|
||||||
|
[Wallet Guide](README.md). The Solana team is working hard to support new
|
||||||
|
features on popular wallets, and we do our best to keep our documents up to date
|
||||||
|
with the latest available features.
|
||||||
|
|
||||||
|
If you have questions after reading the docs, feel free to reach out to us on
|
||||||
|
our [Telegram](https://t.me/solanaio).
|
||||||
|
|
||||||
|
For **technical support**, reach out to us on
|
||||||
|
[Discord](https://discordapp.com/invite/pquxPsq), using the #wallet-support
|
||||||
|
channel in our Community section.
|
@@ -1,16 +1,24 @@
|
|||||||
#Trust Wallet
|
# Trust Wallet
|
||||||
|
Trust Wallet is an app for your smartphone or tablet and is the fastest and
|
||||||
|
simplest way for most users to get started with a Solana wallet.
|
||||||
|
|
||||||
**NOTE: Trust Wallet currently only supports Solana on the iOS version of its
|
## Install Trust Wallet
|
||||||
app. Support for Android is coming very very soon!**
|
|
||||||
|
|
||||||
##Set Up Trust Wallet
|
#### iOS
|
||||||
- Open the App Store or Play Store
|
|
||||||
|
- Open the App Store
|
||||||
- Download “Trust: Crypto & Bitcoin Wallet” from Six Days LLC
|
- Download “Trust: Crypto & Bitcoin Wallet” from Six Days LLC
|
||||||
- Requires iOS 13.0 or higher
|
- Requires iOS 13.0 or higher
|
||||||
|
- Open Trust Wallet and follow the app prompts to get started
|
||||||
|
|
||||||
|
#### Android
|
||||||
|
|
||||||
|
- Open the Play Store
|
||||||
|
- Download “Trust Crypto Wallet” from Six Days LLC
|
||||||
- Requires Android 6.0 or higher
|
- Requires Android 6.0 or higher
|
||||||
- Open Trust Wallet and follow the app prompts to get started
|
- Open Trust Wallet and follow the app prompts to get started
|
||||||
|
|
||||||
##Add Solana (SOL) tokens to your wallet
|
## Add Solana (SOL) tokens to your wallet
|
||||||
- From the main page, go to the “Tokens” tab at the top of the screen
|
- From the main page, go to the “Tokens” tab at the top of the screen
|
||||||
- Tap the “+” icon at the top right corner
|
- Tap the “+” icon at the top right corner
|
||||||
- Search for “Solana” in the search page, and when the “Solana SOL” token is
|
- Search for “Solana” in the search page, and when the “Solana SOL” token is
|
||||||
@@ -19,7 +27,7 @@ shown, slide the slider to enable this token.
|
|||||||
|
|
||||||
[Trust Wallet Official Docs: How to Add or Remove a Coin](https://community.trustwallet.com/t/how-to-add-or-remove-a-coin/896)
|
[Trust Wallet Official Docs: How to Add or Remove a Coin](https://community.trustwallet.com/t/how-to-add-or-remove-a-coin/896)
|
||||||
|
|
||||||
##Receiving SOL tokens
|
## Receiving SOL tokens
|
||||||
- To receive SOL tokens that you’ve purchased or earned, you need to send your
|
- To receive SOL tokens that you’ve purchased or earned, you need to send your
|
||||||
Receive Address to whoever is sending you tokens.
|
Receive Address to whoever is sending you tokens.
|
||||||
- Tap “Receive” to view a QR code and your text address, which is a long string
|
- Tap “Receive” to view a QR code and your text address, which is a long string
|
||||||
@@ -32,6 +40,10 @@ to that address, **those tokens will be lost forever**.
|
|||||||
|
|
||||||
[Trust Wallet Official Docs: How to Find my Receiving Address](https://community.trustwallet.com/t/how-to-find-my-receiving-address/2006)
|
[Trust Wallet Official Docs: How to Find my Receiving Address](https://community.trustwallet.com/t/how-to-find-my-receiving-address/2006)
|
||||||
|
|
||||||
##Troubleshooting
|
## Troubleshooting
|
||||||
If you are having trouble setting up your Trust Wallet app, check out their
|
If you are having trouble setting up your Trust Wallet app, check out their
|
||||||
[Community Help Center](https://community.trustwallet.com/c/helpcenter)
|
[Community Help Center](https://community.trustwallet.com/c/helpcenter)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Check out our [Wallet Support Page](../wallet/support.md) for ways to get help.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-faucet"
|
name = "solana-faucet"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Faucet"
|
description = "Solana Faucet"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -19,10 +19,10 @@ clap = "2.33"
|
|||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
|
|
||||||
|
@@ -21,10 +21,20 @@ if [[ ! -f target/perf-libs/.$VERSION ]]; then
|
|||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
cd target/perf-libs
|
cd target/perf-libs
|
||||||
curl -L --retry 5 --retry-delay 2 --retry-connrefused -o solana-perf.tgz \
|
|
||||||
https://github.com/solana-labs/solana-perf-libs/releases/download/$PERF_LIBS_VERSION/solana-perf.tgz
|
if [[ -r ~/.cache/solana-perf-$PERF_LIBS_VERSION.tgz ]]; then
|
||||||
|
cp ~/.cache/solana-perf-$PERF_LIBS_VERSION.tgz solana-perf.tgz
|
||||||
|
else
|
||||||
|
curl -L --retry 5 --retry-delay 2 --retry-connrefused -o solana-perf.tgz \
|
||||||
|
https://github.com/solana-labs/solana-perf-libs/releases/download/$PERF_LIBS_VERSION/solana-perf.tgz
|
||||||
|
fi
|
||||||
tar zxvf solana-perf.tgz
|
tar zxvf solana-perf.tgz
|
||||||
rm -f solana-perf.tgz
|
|
||||||
|
if [[ ! -r ~/.cache/solana-perf-$PERF_LIBS_VERSION.tgz ]]; then
|
||||||
|
# Save it for next time
|
||||||
|
mkdir -p ~/.cache
|
||||||
|
mv solana-perf.tgz ~/.cache/solana-perf-$PERF_LIBS_VERSION.tgz
|
||||||
|
fi
|
||||||
touch .$VERSION
|
touch .$VERSION
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-genesis-programs"
|
name = "solana-genesis-programs"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana genesis programs"
|
description = "Solana genesis programs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -10,16 +10,16 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4.8" }
|
log = { version = "0.4.8" }
|
||||||
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.0.12" }
|
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.0.17" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.0.12" }
|
solana-config-program = { path = "../programs/config", version = "1.0.17" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.0.12" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
solana-vest-program = { path = "../programs/vest", version = "1.0.12" }
|
solana-vest-program = { path = "../programs/vest", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["lib"]
|
crate-type = ["lib"]
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-genesis"
|
name = "solana-genesis"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -15,13 +15,13 @@ chrono = "0.4"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.12" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -3,19 +3,19 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-gossip"
|
name = "solana-gossip"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.0.12" }
|
solana-net-utils = { path = "../net-utils", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-install"
|
name = "solana-install"
|
||||||
description = "The solana cluster software installer"
|
description = "The solana cluster software installer"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -24,11 +24,11 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.0.12" }
|
solana-config-program = { path = "../programs/config", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
semver = "0.9.0"
|
semver = "0.9.0"
|
||||||
tar = "0.4.26"
|
tar = "0.4.26"
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-keygen"
|
name = "solana-keygen"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana key generation utility"
|
description = "Solana key generation utility"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,10 +13,10 @@ bs58 = "0.3.0"
|
|||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
num_cpus = "1.12.0"
|
num_cpus = "1.12.0"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.0.12" }
|
solana-cli-config = { path = "../cli-config", version = "1.0.17" }
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.12" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
tiny-bip39 = "0.7.0"
|
tiny-bip39 = "0.7.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-ledger-tool"
|
name = "solana-ledger-tool"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -14,13 +14,13 @@ clap = "2.33.0"
|
|||||||
histogram = "*"
|
histogram = "*"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
serde_yaml = "0.8.11"
|
serde_yaml = "0.8.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@@ -144,7 +144,7 @@ fn output_slot(
|
|||||||
println!(" Data: {:?}", instruction.data);
|
println!(" Data: {:?}", instruction.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match blockstore.read_transaction_status((slot, transaction.signatures[0])) {
|
match blockstore.read_transaction_status((transaction.signatures[0], slot)) {
|
||||||
Ok(transaction_status) => {
|
Ok(transaction_status) => {
|
||||||
if let Some(transaction_status) = transaction_status {
|
if let Some(transaction_status) = transaction_status {
|
||||||
println!(
|
println!(
|
||||||
@@ -808,6 +808,12 @@ fn main() {
|
|||||||
.arg(&account_paths_arg)
|
.arg(&account_paths_arg)
|
||||||
.arg(&halt_at_slot_arg)
|
.arg(&halt_at_slot_arg)
|
||||||
.arg(&hard_forks_arg)
|
.arg(&hard_forks_arg)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("include_sysvars")
|
||||||
|
.long("include-sysvars")
|
||||||
|
.takes_value(false)
|
||||||
|
.help("Include sysvars too"),
|
||||||
|
)
|
||||||
).subcommand(
|
).subcommand(
|
||||||
SubCommand::with_name("prune")
|
SubCommand::with_name("prune")
|
||||||
.about("Prune the ledger at the block height")
|
.about("Prune the ledger at the block height")
|
||||||
@@ -1090,6 +1096,7 @@ fn main() {
|
|||||||
..ProcessOptions::default()
|
..ProcessOptions::default()
|
||||||
};
|
};
|
||||||
let genesis_config = open_genesis_config(&ledger_path);
|
let genesis_config = open_genesis_config(&ledger_path);
|
||||||
|
let include_sysvars = arg_matches.is_present("include_sysvars");
|
||||||
match load_bank_forks(arg_matches, &ledger_path, &genesis_config, process_options) {
|
match load_bank_forks(arg_matches, &ledger_path, &genesis_config, process_options) {
|
||||||
Ok((bank_forks, bank_forks_info, _leader_schedule_cache, _snapshot_hash)) => {
|
Ok((bank_forks, bank_forks_info, _leader_schedule_cache, _snapshot_hash)) => {
|
||||||
let slot = dev_halt_at_slot.unwrap_or_else(|| {
|
let slot = dev_halt_at_slot.unwrap_or_else(|| {
|
||||||
@@ -1105,19 +1112,23 @@ fn main() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
let accounts: Vec<_> = bank
|
let accounts: BTreeMap<_, _> = bank
|
||||||
.get_program_accounts(None)
|
.get_program_accounts(None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(pubkey, _account)| !solana_sdk::sysvar::is_sysvar_id(pubkey))
|
.filter(|(pubkey, _account)| {
|
||||||
|
include_sysvars || !solana_sdk::sysvar::is_sysvar_id(pubkey)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
println!("---");
|
println!("---");
|
||||||
for (pubkey, account) in accounts.into_iter() {
|
for (pubkey, account) in accounts.into_iter() {
|
||||||
|
let data_len = account.data.len();
|
||||||
println!("{}:", pubkey);
|
println!("{}:", pubkey);
|
||||||
println!(" - lamports: {}", account.lamports);
|
println!(" - lamports: {}", account.lamports);
|
||||||
println!(" - owner: '{}'", account.owner);
|
println!(" - owner: '{}'", account.owner);
|
||||||
println!(" - executable: {}", account.executable);
|
println!(" - executable: {}", account.executable);
|
||||||
println!(" - data: '{}'", bs58::encode(account.data).into_string());
|
println!(" - data: '{}'", bs58::encode(account.data).into_string());
|
||||||
|
println!(" - data_len: {}", data_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-ledger"
|
name = "solana-ledger"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana ledger"
|
description = "Solana ledger"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -28,19 +28,19 @@ reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0
|
|||||||
regex = "1.3.4"
|
regex = "1.3.4"
|
||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_bytes = "0.11.3"
|
serde_bytes = "0.11.3"
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.0.12" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.0.17" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.12" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-measure = { path = "../measure", version = "1.0.12" }
|
solana-measure = { path = "../measure", version = "1.0.17" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.0.12" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
solana-perf = { path = "../perf", version = "1.0.12" }
|
solana-perf = { path = "../perf", version = "1.0.17" }
|
||||||
ed25519-dalek = "1.0.0-pre.1"
|
ed25519-dalek = "1.0.0-pre.1"
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.12" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
symlink = "0.1.0"
|
symlink = "0.1.0"
|
||||||
tar = "0.4.26"
|
tar = "0.4.26"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
@@ -57,7 +57,7 @@ features = ["lz4"]
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
matches = "0.1.6"
|
matches = "0.1.6"
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["lib"]
|
crate-type = ["lib"]
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ use rocksdb::{
|
|||||||
};
|
};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_sdk::{clock::Slot, signature::Signature};
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
use solana_transaction_status::{Rewards, TransactionStatusMeta};
|
use solana_transaction_status::{Rewards, TransactionStatusMeta};
|
||||||
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
use std::{collections::HashMap, fs, marker::PhantomData, path::Path, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -38,6 +38,10 @@ const DATA_SHRED_CF: &str = "data_shred";
|
|||||||
const CODE_SHRED_CF: &str = "code_shred";
|
const CODE_SHRED_CF: &str = "code_shred";
|
||||||
/// Column family for Transaction Status
|
/// Column family for Transaction Status
|
||||||
const TRANSACTION_STATUS_CF: &str = "transaction_status";
|
const TRANSACTION_STATUS_CF: &str = "transaction_status";
|
||||||
|
/// Column family for Address Signatures
|
||||||
|
const ADDRESS_SIGNATURES_CF: &str = "address_signatures";
|
||||||
|
/// Column family for Transaction Status Index
|
||||||
|
const TRANSACTION_STATUS_INDEX_CF: &str = "transaction_status_index";
|
||||||
/// Column family for Rewards
|
/// Column family for Rewards
|
||||||
const REWARDS_CF: &str = "rewards";
|
const REWARDS_CF: &str = "rewards";
|
||||||
|
|
||||||
@@ -108,6 +112,14 @@ pub mod columns {
|
|||||||
/// The transaction status column
|
/// The transaction status column
|
||||||
pub struct TransactionStatus;
|
pub struct TransactionStatus;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// The address signatures column
|
||||||
|
pub struct AddressSignatures;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// The transaction status index column
|
||||||
|
pub struct TransactionStatusIndex;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// The rewards column
|
/// The rewards column
|
||||||
pub struct Rewards;
|
pub struct Rewards;
|
||||||
@@ -119,8 +131,8 @@ struct Rocks(rocksdb::DB);
|
|||||||
impl Rocks {
|
impl Rocks {
|
||||||
fn open(path: &Path) -> Result<Rocks> {
|
fn open(path: &Path) -> Result<Rocks> {
|
||||||
use columns::{
|
use columns::{
|
||||||
DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, Rewards, Root, ShredCode,
|
AddressSignatures, DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, Rewards,
|
||||||
ShredData, SlotMeta, TransactionStatus,
|
Root, ShredCode, ShredData, SlotMeta, TransactionStatus, TransactionStatusIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
fs::create_dir_all(&path)?;
|
fs::create_dir_all(&path)?;
|
||||||
@@ -145,6 +157,10 @@ impl Rocks {
|
|||||||
ColumnFamilyDescriptor::new(ShredCode::NAME, get_cf_options());
|
ColumnFamilyDescriptor::new(ShredCode::NAME, get_cf_options());
|
||||||
let transaction_status_cf_descriptor =
|
let transaction_status_cf_descriptor =
|
||||||
ColumnFamilyDescriptor::new(TransactionStatus::NAME, get_cf_options());
|
ColumnFamilyDescriptor::new(TransactionStatus::NAME, get_cf_options());
|
||||||
|
let address_signatures_cf_descriptor =
|
||||||
|
ColumnFamilyDescriptor::new(AddressSignatures::NAME, get_cf_options());
|
||||||
|
let transaction_status_index_cf_descriptor =
|
||||||
|
ColumnFamilyDescriptor::new(TransactionStatusIndex::NAME, get_cf_options());
|
||||||
let rewards_cf_descriptor = ColumnFamilyDescriptor::new(Rewards::NAME, get_cf_options());
|
let rewards_cf_descriptor = ColumnFamilyDescriptor::new(Rewards::NAME, get_cf_options());
|
||||||
|
|
||||||
let cfs = vec![
|
let cfs = vec![
|
||||||
@@ -158,6 +174,8 @@ impl Rocks {
|
|||||||
shred_data_cf_descriptor,
|
shred_data_cf_descriptor,
|
||||||
shred_code_cf_descriptor,
|
shred_code_cf_descriptor,
|
||||||
transaction_status_cf_descriptor,
|
transaction_status_cf_descriptor,
|
||||||
|
address_signatures_cf_descriptor,
|
||||||
|
transaction_status_index_cf_descriptor,
|
||||||
rewards_cf_descriptor,
|
rewards_cf_descriptor,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -169,8 +187,8 @@ impl Rocks {
|
|||||||
|
|
||||||
fn columns(&self) -> Vec<&'static str> {
|
fn columns(&self) -> Vec<&'static str> {
|
||||||
use columns::{
|
use columns::{
|
||||||
DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, Rewards, Root, ShredCode,
|
AddressSignatures, DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, Rewards,
|
||||||
ShredData, SlotMeta, TransactionStatus,
|
Root, ShredCode, ShredData, SlotMeta, TransactionStatus, TransactionStatusIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
@@ -184,6 +202,8 @@ impl Rocks {
|
|||||||
ShredData::NAME,
|
ShredData::NAME,
|
||||||
ShredCode::NAME,
|
ShredCode::NAME,
|
||||||
TransactionStatus::NAME,
|
TransactionStatus::NAME,
|
||||||
|
AddressSignatures::NAME,
|
||||||
|
TransactionStatusIndex::NAME,
|
||||||
Rewards::NAME,
|
Rewards::NAME,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -256,7 +276,7 @@ pub trait Column {
|
|||||||
|
|
||||||
fn key(index: Self::Index) -> Vec<u8>;
|
fn key(index: Self::Index) -> Vec<u8>;
|
||||||
fn index(key: &[u8]) -> Self::Index;
|
fn index(key: &[u8]) -> Self::Index;
|
||||||
fn slot(index: Self::Index) -> Slot;
|
fn primary_index(index: Self::Index) -> Slot;
|
||||||
fn as_index(slot: Slot) -> Self::Index;
|
fn as_index(slot: Slot) -> Self::Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +292,14 @@ impl TypedColumn for columns::TransactionStatus {
|
|||||||
type Type = TransactionStatusMeta;
|
type Type = TransactionStatusMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypedColumn for columns::AddressSignatures {
|
||||||
|
type Type = blockstore_meta::AddressSignatureMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypedColumn for columns::TransactionStatusIndex {
|
||||||
|
type Type = blockstore_meta::TransactionStatusIndexMeta;
|
||||||
|
}
|
||||||
|
|
||||||
pub trait SlotColumn<Index = u64> {}
|
pub trait SlotColumn<Index = u64> {}
|
||||||
|
|
||||||
impl<T: SlotColumn> Column for T {
|
impl<T: SlotColumn> Column for T {
|
||||||
@@ -287,7 +315,7 @@ impl<T: SlotColumn> Column for T {
|
|||||||
BigEndian::read_u64(&key[..8])
|
BigEndian::read_u64(&key[..8])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(index: u64) -> Slot {
|
fn primary_index(index: u64) -> Slot {
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,27 +325,29 @@ impl<T: SlotColumn> Column for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Column for columns::TransactionStatus {
|
impl Column for columns::TransactionStatus {
|
||||||
type Index = (Slot, Signature);
|
type Index = (u64, Signature, Slot);
|
||||||
|
|
||||||
fn key((slot, index): (Slot, Signature)) -> Vec<u8> {
|
fn key((index, signature, slot): (u64, Signature, Slot)) -> Vec<u8> {
|
||||||
let mut key = vec![0; 8 + 64];
|
let mut key = vec![0; 8 + 64 + 8]; // size_of u64 + size_of Signature + size_of Slot
|
||||||
BigEndian::write_u64(&mut key[..8], slot);
|
BigEndian::write_u64(&mut key[0..8], index);
|
||||||
key[8..72].clone_from_slice(&index.as_ref()[0..64]);
|
key[8..72].clone_from_slice(&signature.as_ref()[0..64]);
|
||||||
|
BigEndian::write_u64(&mut key[72..80], slot);
|
||||||
key
|
key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(key: &[u8]) -> (Slot, Signature) {
|
fn index(key: &[u8]) -> (u64, Signature, Slot) {
|
||||||
let slot = BigEndian::read_u64(&key[..8]);
|
let index = BigEndian::read_u64(&key[0..8]);
|
||||||
let index = Signature::new(&key[8..72]);
|
let signature = Signature::new(&key[8..72]);
|
||||||
(slot, index)
|
let slot = BigEndian::read_u64(&key[72..80]);
|
||||||
|
(index, signature, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(index: Self::Index) -> Slot {
|
fn primary_index(index: Self::Index) -> u64 {
|
||||||
index.0
|
index.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_index(slot: Slot) -> Self::Index {
|
fn as_index(index: u64) -> Self::Index {
|
||||||
(slot, Signature::default())
|
(index, Signature::default(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,6 +355,65 @@ impl ColumnName for columns::TransactionStatus {
|
|||||||
const NAME: &'static str = TRANSACTION_STATUS_CF;
|
const NAME: &'static str = TRANSACTION_STATUS_CF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Column for columns::AddressSignatures {
|
||||||
|
type Index = (u64, Pubkey, Slot, Signature);
|
||||||
|
|
||||||
|
fn key((index, pubkey, slot, signature): (u64, Pubkey, Slot, Signature)) -> Vec<u8> {
|
||||||
|
let mut key = vec![0; 8 + 32 + 8 + 64]; // size_of u64 + size_of Pubkey + size_of Slot + size_of Signature
|
||||||
|
BigEndian::write_u64(&mut key[0..8], index);
|
||||||
|
key[8..40].clone_from_slice(&pubkey.as_ref()[0..32]);
|
||||||
|
BigEndian::write_u64(&mut key[40..48], slot);
|
||||||
|
key[48..112].clone_from_slice(&signature.as_ref()[0..64]);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(key: &[u8]) -> (u64, Pubkey, Slot, Signature) {
|
||||||
|
let index = BigEndian::read_u64(&key[0..8]);
|
||||||
|
let pubkey = Pubkey::new(&key[8..40]);
|
||||||
|
let slot = BigEndian::read_u64(&key[40..48]);
|
||||||
|
let signature = Signature::new(&key[48..112]);
|
||||||
|
(index, pubkey, slot, signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn primary_index(index: Self::Index) -> u64 {
|
||||||
|
index.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_index(index: u64) -> Self::Index {
|
||||||
|
(index, Pubkey::default(), 0, Signature::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColumnName for columns::AddressSignatures {
|
||||||
|
const NAME: &'static str = ADDRESS_SIGNATURES_CF;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Column for columns::TransactionStatusIndex {
|
||||||
|
type Index = u64;
|
||||||
|
|
||||||
|
fn key(index: u64) -> Vec<u8> {
|
||||||
|
let mut key = vec![0; 8];
|
||||||
|
BigEndian::write_u64(&mut key[..], index);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(key: &[u8]) -> u64 {
|
||||||
|
BigEndian::read_u64(&key[..8])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn primary_index(index: u64) -> u64 {
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_index(slot: u64) -> u64 {
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColumnName for columns::TransactionStatusIndex {
|
||||||
|
const NAME: &'static str = TRANSACTION_STATUS_INDEX_CF;
|
||||||
|
}
|
||||||
|
|
||||||
impl SlotColumn for columns::Rewards {}
|
impl SlotColumn for columns::Rewards {}
|
||||||
impl ColumnName for columns::Rewards {
|
impl ColumnName for columns::Rewards {
|
||||||
const NAME: &'static str = REWARDS_CF;
|
const NAME: &'static str = REWARDS_CF;
|
||||||
@@ -344,7 +433,7 @@ impl Column for columns::ShredCode {
|
|||||||
columns::ShredData::index(key)
|
columns::ShredData::index(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(index: Self::Index) -> Slot {
|
fn primary_index(index: Self::Index) -> Slot {
|
||||||
index.0
|
index.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,7 +462,7 @@ impl Column for columns::ShredData {
|
|||||||
(slot, index)
|
(slot, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(index: Self::Index) -> Slot {
|
fn primary_index(index: Self::Index) -> Slot {
|
||||||
index.0
|
index.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +540,7 @@ impl Column for columns::ErasureMeta {
|
|||||||
key
|
key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slot(index: Self::Index) -> Slot {
|
fn primary_index(index: Self::Index) -> Slot {
|
||||||
index.0
|
index.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,7 +672,7 @@ impl Database {
|
|||||||
let max_slot = self
|
let max_slot = self
|
||||||
.iter::<C>(IteratorMode::End)?
|
.iter::<C>(IteratorMode::End)?
|
||||||
.next()
|
.next()
|
||||||
.map(|(i, _)| C::slot(i))
|
.map(|(i, _)| C::primary_index(i))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let end = max_slot <= to;
|
let end = max_slot <= to;
|
||||||
result.map(|_| end)
|
result.map(|_| end)
|
||||||
@@ -624,7 +713,7 @@ where
|
|||||||
let iter = self.iter(iter_config)?;
|
let iter = self.iter(iter_config)?;
|
||||||
for (index, _) in iter {
|
for (index, _) in iter {
|
||||||
if let Some(to) = to {
|
if let Some(to) = to {
|
||||||
if C::slot(index) > to {
|
if C::primary_index(index) > to {
|
||||||
end = false;
|
end = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -222,6 +222,17 @@ impl DuplicateSlotProof {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||||
|
pub struct TransactionStatusIndexMeta {
|
||||||
|
pub max_slot: Slot,
|
||||||
|
pub frozen: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||||
|
pub struct AddressSignatureMeta {
|
||||||
|
pub writeable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@@ -20,8 +20,8 @@ use solana_runtime::{
|
|||||||
transaction_batch::TransactionBatch,
|
transaction_batch::TransactionBatch,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, MAX_RECENT_BLOCKHASHES},
|
clock::{Epoch, Slot, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES},
|
||||||
genesis_config::GenesisConfig,
|
genesis_config::{GenesisConfig, OperatingMode},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Keypair,
|
signature::Keypair,
|
||||||
@@ -57,11 +57,22 @@ fn first_err(results: &[Result<()>]) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_AGE_CORRECTION_EPOCH: Epoch = 14;
|
||||||
|
|
||||||
fn execute_batch(
|
fn execute_batch(
|
||||||
batch: &TransactionBatch,
|
batch: &TransactionBatch,
|
||||||
bank: &Arc<Bank>,
|
bank: &Arc<Bank>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
genesis_config: Option<&GenesisConfig>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
// See https://github.com/solana-labs/solana/pull/9423
|
||||||
|
let max_age_reduced = if let Some(genesis_config) = genesis_config {
|
||||||
|
genesis_config.operating_mode == OperatingMode::Stable
|
||||||
|
&& bank.epoch() >= MAX_AGE_CORRECTION_EPOCH
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
let (
|
let (
|
||||||
TransactionResults {
|
TransactionResults {
|
||||||
fee_collection_results,
|
fee_collection_results,
|
||||||
@@ -70,7 +81,11 @@ fn execute_batch(
|
|||||||
balances,
|
balances,
|
||||||
) = batch.bank().load_execute_and_commit_transactions(
|
) = batch.bank().load_execute_and_commit_transactions(
|
||||||
batch,
|
batch,
|
||||||
MAX_RECENT_BLOCKHASHES,
|
if max_age_reduced {
|
||||||
|
MAX_PROCESSING_AGE
|
||||||
|
} else {
|
||||||
|
MAX_RECENT_BLOCKHASHES
|
||||||
|
},
|
||||||
transaction_status_sender.is_some(),
|
transaction_status_sender.is_some(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -112,6 +127,7 @@ fn execute_batches(
|
|||||||
batches: &[TransactionBatch],
|
batches: &[TransactionBatch],
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
genesis_config: Option<&GenesisConfig>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
inc_new_counter_debug!("bank-par_execute_entries-count", batches.len());
|
inc_new_counter_debug!("bank-par_execute_entries-count", batches.len());
|
||||||
let results: Vec<Result<()>> = PAR_THREAD_POOL.with(|thread_pool| {
|
let results: Vec<Result<()>> = PAR_THREAD_POOL.with(|thread_pool| {
|
||||||
@@ -119,7 +135,7 @@ fn execute_batches(
|
|||||||
batches
|
batches
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map_with(transaction_status_sender, |sender, batch| {
|
.map_with(transaction_status_sender, |sender, batch| {
|
||||||
let result = execute_batch(batch, bank, sender.clone());
|
let result = execute_batch(batch, bank, sender.clone(), genesis_config);
|
||||||
if let Some(entry_callback) = entry_callback {
|
if let Some(entry_callback) = entry_callback {
|
||||||
entry_callback(bank);
|
entry_callback(bank);
|
||||||
}
|
}
|
||||||
@@ -143,7 +159,14 @@ pub fn process_entries(
|
|||||||
randomize: bool,
|
randomize: bool,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
process_entries_with_callback(bank, entries, randomize, None, transaction_status_sender)
|
process_entries_with_callback(
|
||||||
|
bank,
|
||||||
|
entries,
|
||||||
|
randomize,
|
||||||
|
None,
|
||||||
|
transaction_status_sender,
|
||||||
|
Some(&GenesisConfig::default()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_entries_with_callback(
|
fn process_entries_with_callback(
|
||||||
@@ -152,6 +175,7 @@ fn process_entries_with_callback(
|
|||||||
randomize: bool,
|
randomize: bool,
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
|
genesis_config: Option<&GenesisConfig>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// accumulator for entries that can be processed in parallel
|
// accumulator for entries that can be processed in parallel
|
||||||
let mut batches = vec![];
|
let mut batches = vec![];
|
||||||
@@ -168,6 +192,7 @@ fn process_entries_with_callback(
|
|||||||
&batches,
|
&batches,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
genesis_config,
|
||||||
)?;
|
)?;
|
||||||
batches.clear();
|
batches.clear();
|
||||||
for hash in &tick_hashes {
|
for hash in &tick_hashes {
|
||||||
@@ -223,12 +248,19 @@ fn process_entries_with_callback(
|
|||||||
&batches,
|
&batches,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender.clone(),
|
transaction_status_sender.clone(),
|
||||||
|
genesis_config,
|
||||||
)?;
|
)?;
|
||||||
batches.clear();
|
batches.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
execute_batches(bank, &batches, entry_callback, transaction_status_sender)?;
|
execute_batches(
|
||||||
|
bank,
|
||||||
|
&batches,
|
||||||
|
entry_callback,
|
||||||
|
transaction_status_sender,
|
||||||
|
genesis_config,
|
||||||
|
)?;
|
||||||
for hash in tick_hashes {
|
for hash in tick_hashes {
|
||||||
bank.register_tick(&hash);
|
bank.register_tick(&hash);
|
||||||
}
|
}
|
||||||
@@ -363,6 +395,7 @@ pub fn process_blockstore_from_root(
|
|||||||
&mut rooted_path,
|
&mut rooted_path,
|
||||||
opts,
|
opts,
|
||||||
recyclers,
|
recyclers,
|
||||||
|
genesis_config,
|
||||||
)?;
|
)?;
|
||||||
let (banks, bank_forks_info): (Vec<_>, Vec<_>) =
|
let (banks, bank_forks_info): (Vec<_>, Vec<_>) =
|
||||||
fork_info.into_iter().map(|(_, v)| v).unzip();
|
fork_info.into_iter().map(|(_, v)| v).unzip();
|
||||||
@@ -456,6 +489,7 @@ fn confirm_full_slot(
|
|||||||
last_entry_hash: &Hash,
|
last_entry_hash: &Hash,
|
||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: Option<&GenesisConfig>,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
let mut timing = ConfirmationTiming::default();
|
let mut timing = ConfirmationTiming::default();
|
||||||
let mut progress = ConfirmationProgress::new(*last_entry_hash);
|
let mut progress = ConfirmationProgress::new(*last_entry_hash);
|
||||||
@@ -469,6 +503,7 @@ fn confirm_full_slot(
|
|||||||
None,
|
None,
|
||||||
opts.entry_callback.as_ref(),
|
opts.entry_callback.as_ref(),
|
||||||
recyclers,
|
recyclers,
|
||||||
|
genesis_config,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !bank.is_complete() {
|
if !bank.is_complete() {
|
||||||
@@ -527,6 +562,7 @@ pub fn confirm_slot(
|
|||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
entry_callback: Option<&ProcessCallback>,
|
entry_callback: Option<&ProcessCallback>,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: Option<&GenesisConfig>,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
|
|
||||||
@@ -592,6 +628,7 @@ pub fn confirm_slot(
|
|||||||
true,
|
true,
|
||||||
entry_callback,
|
entry_callback,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
genesis_config,
|
||||||
)
|
)
|
||||||
.map_err(BlockstoreProcessorError::from);
|
.map_err(BlockstoreProcessorError::from);
|
||||||
replay_elapsed.stop();
|
replay_elapsed.stop();
|
||||||
@@ -625,8 +662,15 @@ fn process_bank_0(
|
|||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
assert_eq!(bank0.slot(), 0);
|
assert_eq!(bank0.slot(), 0);
|
||||||
confirm_full_slot(blockstore, bank0, &bank0.last_blockhash(), opts, recyclers)
|
confirm_full_slot(
|
||||||
.expect("processing for bank 0 must succceed");
|
blockstore,
|
||||||
|
bank0,
|
||||||
|
&bank0.last_blockhash(),
|
||||||
|
opts,
|
||||||
|
recyclers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.expect("processing for bank 0 must succceed");
|
||||||
bank0.freeze();
|
bank0.freeze();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -701,6 +745,7 @@ fn process_pending_slots(
|
|||||||
rooted_path: &mut Vec<u64>,
|
rooted_path: &mut Vec<u64>,
|
||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: &GenesisConfig,
|
||||||
) -> result::Result<HashMap<u64, (Arc<Bank>, BankForksInfo)>, BlockstoreProcessorError> {
|
) -> result::Result<HashMap<u64, (Arc<Bank>, BankForksInfo)>, BlockstoreProcessorError> {
|
||||||
let mut fork_info = HashMap::new();
|
let mut fork_info = HashMap::new();
|
||||||
let mut last_status_report = Instant::now();
|
let mut last_status_report = Instant::now();
|
||||||
@@ -730,7 +775,16 @@ fn process_pending_slots(
|
|||||||
let allocated = thread_mem_usage::Allocatedp::default();
|
let allocated = thread_mem_usage::Allocatedp::default();
|
||||||
let initial_allocation = allocated.get();
|
let initial_allocation = allocated.get();
|
||||||
|
|
||||||
if process_single_slot(blockstore, &bank, &last_entry_hash, opts, recyclers).is_err() {
|
if process_single_slot(
|
||||||
|
blockstore,
|
||||||
|
&bank,
|
||||||
|
&last_entry_hash,
|
||||||
|
opts,
|
||||||
|
recyclers,
|
||||||
|
genesis_config,
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,10 +832,19 @@ fn process_single_slot(
|
|||||||
last_entry_hash: &Hash,
|
last_entry_hash: &Hash,
|
||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
|
genesis_config: &GenesisConfig,
|
||||||
) -> result::Result<(), BlockstoreProcessorError> {
|
) -> result::Result<(), BlockstoreProcessorError> {
|
||||||
// Mark corrupt slots as dead so validators don't replay this slot and
|
// Mark corrupt slots as dead so validators don't replay this slot and
|
||||||
// see DuplicateSignature errors later in ReplayStage
|
// see DuplicateSignature errors later in ReplayStage
|
||||||
confirm_full_slot(blockstore, bank, last_entry_hash, opts, recyclers).map_err(|err| {
|
confirm_full_slot(
|
||||||
|
blockstore,
|
||||||
|
bank,
|
||||||
|
last_entry_hash,
|
||||||
|
opts,
|
||||||
|
recyclers,
|
||||||
|
Some(genesis_config),
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
let slot = bank.slot();
|
let slot = bank.slot();
|
||||||
blockstore
|
blockstore
|
||||||
.set_dead_slot(slot)
|
.set_dead_slot(slot)
|
||||||
@@ -2444,6 +2507,7 @@ pub mod tests {
|
|||||||
&bank0.last_blockhash(),
|
&bank0.last_blockhash(),
|
||||||
&opts,
|
&opts,
|
||||||
&recyclers,
|
&recyclers,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
bank1.squash();
|
bank1.squash();
|
||||||
@@ -2609,7 +2673,7 @@ pub mod tests {
|
|||||||
let entry = next_entry(&new_blockhash, 1, vec![tx]);
|
let entry = next_entry(&new_blockhash, 1, vec![tx]);
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
|
|
||||||
process_entries_with_callback(&bank0, &entries, true, None, None).unwrap();
|
process_entries_with_callback(&bank0, &entries, true, None, None, None).unwrap();
|
||||||
assert_eq!(bank0.get_balance(&keypair.pubkey()), 1)
|
assert_eq!(bank0.get_balance(&keypair.pubkey()), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-local-cluster"
|
name = "solana-local-cluster"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -12,23 +12,23 @@ homepage = "https://solana.com/"
|
|||||||
itertools = "0.8.1"
|
itertools = "0.8.1"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
solana-archiver-lib = { path = "../archiver-lib", version = "1.0.12" }
|
solana-archiver-lib = { path = "../archiver-lib", version = "1.0.17" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.0.12" }
|
solana-config-program = { path = "../programs/config", version = "1.0.17" }
|
||||||
solana-core = { path = "../core", version = "1.0.12" }
|
solana-core = { path = "../core", version = "1.0.17" }
|
||||||
solana-client = { path = "../client", version = "1.0.12" }
|
solana-client = { path = "../client", version = "1.0.17" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.0.12" }
|
solana-faucet = { path = "../faucet", version = "1.0.17" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", version = "1.0.12" }
|
solana-exchange-program = { path = "../programs/exchange", version = "1.0.17" }
|
||||||
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.12" }
|
solana-genesis-programs = { path = "../genesis-programs", version = "1.0.17" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.0.12" }
|
solana-ledger = { path = "../ledger", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.0.12" }
|
solana-stake-program = { path = "../programs/stake", version = "1.0.17" }
|
||||||
solana-storage-program = { path = "../programs/storage", version = "1.0.12" }
|
solana-storage-program = { path = "../programs/storage", version = "1.0.17" }
|
||||||
solana-vest-program = { path = "../programs/vest", version = "1.0.12" }
|
solana-vest-program = { path = "../programs/vest", version = "1.0.17" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.0.12" }
|
solana-vote-program = { path = "../programs/vote", version = "1.0.17" }
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.12" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-log-analyzer"
|
name = "solana-log-analyzer"
|
||||||
description = "The solana cluster network analysis tool"
|
description = "The solana cluster network analysis tool"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -14,8 +14,8 @@ byte-unit = "3.0.3"
|
|||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "solana-log-analyzer"
|
name = "solana-log-analyzer"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-logger"
|
name = "solana-logger"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Logger"
|
description = "Solana Logger"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-measure"
|
name = "solana-measure"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "../README.md"
|
readme = "../README.md"
|
||||||
@@ -12,8 +12,8 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
|
|
||||||
[target."cfg(unix)".dependencies]
|
[target."cfg(unix)".dependencies]
|
||||||
jemallocator = "0.3.2"
|
jemallocator = "0.3.2"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-merkle-tree"
|
name = "solana-merkle-tree"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Merkle Tree"
|
description = "Solana Merkle Tree"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -9,7 +9,7 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-metrics"
|
name = "solana-metrics"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Metrics"
|
description = "Solana Metrics"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -14,7 +14,7 @@ gethostname = "0.2.1"
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
reqwest = { version = "0.10.1", default-features = false, features = ["blocking", "rustls-tls"] }
|
reqwest = { version = "0.10.1", default-features = false, features = ["blocking", "rustls-tls"] }
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
|
@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
name = "solana-net-shaper"
|
name = "solana-net-shaper"
|
||||||
description = "The solana cluster network shaping tool"
|
description = "The solana cluster network shaping tool"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
@@ -13,8 +13,8 @@ publish = false
|
|||||||
clap = "2.33.0"
|
clap = "2.33.0"
|
||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_json = "1.0.46"
|
serde_json = "1.0.46"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-net-utils"
|
name = "solana-net-utils"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Network Utilities"
|
description = "Solana Network Utilities"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -18,8 +18,8 @@ rand = "0.6.1"
|
|||||||
serde = "1.0.104"
|
serde = "1.0.104"
|
||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
socket2 = "0.3.11"
|
socket2 = "0.3.11"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.0.12" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-codec = "0.1"
|
tokio-codec = "0.1"
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-perf"
|
name = "solana-perf"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana Performance APIs"
|
description = "Solana Performance APIs"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -17,11 +17,11 @@ serde = "1.0.104"
|
|||||||
dlopen_derive = "0.1.4"
|
dlopen_derive = "0.1.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
solana-sdk = { path = "../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../sdk", version = "1.0.17" }
|
||||||
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.12" }
|
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.0.17" }
|
||||||
solana-budget-program = { path = "../programs/budget", version = "1.0.12" }
|
solana-budget-program = { path = "../programs/budget", version = "1.0.17" }
|
||||||
solana-logger = { path = "../logger", version = "1.0.12" }
|
solana-logger = { path = "../logger", version = "1.0.17" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.0.12" }
|
solana-metrics = { path = "../metrics", version = "1.0.17" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "solana_perf"
|
name = "solana_perf"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-programs"
|
name = "solana-bpf-programs"
|
||||||
description = "Blockchain, Rebuilt for Scale"
|
description = "Blockchain, Rebuilt for Scale"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
documentation = "https://docs.rs/solana"
|
documentation = "https://docs.rs/solana"
|
||||||
homepage = "https://solana.com/"
|
homepage = "https://solana.com/"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@@ -22,10 +22,10 @@ walkdir = "2"
|
|||||||
bincode = "1.1.4"
|
bincode = "1.1.4"
|
||||||
byteorder = "1.3.2"
|
byteorder = "1.3.2"
|
||||||
elf = "0.0.10"
|
elf = "0.0.10"
|
||||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.0.12" }
|
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.0.17" }
|
||||||
solana-logger = { path = "../../logger", version = "1.0.12" }
|
solana-logger = { path = "../../logger", version = "1.0.17" }
|
||||||
solana-runtime = { path = "../../runtime", version = "1.0.12" }
|
solana-runtime = { path = "../../runtime", version = "1.0.17" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.0.12" }
|
solana-sdk = { path = "../../sdk", version = "1.0.17" }
|
||||||
solana_rbpf = "=0.1.21"
|
solana_rbpf = "=0.1.21"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-128bit"
|
name = "solana-bpf-rust-128bit"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,11 +12,11 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.0.12" }
|
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "1.0.17" }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-128bit-dep"
|
name = "solana-bpf-rust-128bit-dep"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-alloc"
|
name = "solana-bpf-rust-alloc"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-dep-crate"
|
name = "solana-bpf-rust-dep-crate"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -13,10 +13,10 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = { version = "1", default-features = false }
|
byteorder = { version = "1", default-features = false }
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-dup-accounts"
|
name = "solana-bpf-rust-dup-accounts"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-error-handling"
|
name = "solana-bpf-rust-error-handling"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -14,11 +14,11 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
num-derive = "0.2"
|
num-derive = "0.2"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-external-spend"
|
name = "solana-bpf-rust-external-spend"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-iter"
|
name = "solana-bpf-rust-iter"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-many-args"
|
name = "solana-bpf-rust-many-args"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,11 +12,11 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.0.12" }
|
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "1.0.17" }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-many-args-dep"
|
name = "solana-bpf-rust-many-args-dep"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-noop"
|
name = "solana-bpf-rust-noop"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "solana-bpf-rust-panic"
|
name = "solana-bpf-rust-panic"
|
||||||
version = "1.0.12"
|
version = "1.0.17"
|
||||||
description = "Solana BPF test program written in Rust"
|
description = "Solana BPF test program written in Rust"
|
||||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||||
repository = "https://github.com/solana-labs/solana"
|
repository = "https://github.com/solana-labs/solana"
|
||||||
@@ -12,10 +12,10 @@ homepage = "https://solana.com/"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
solana-sdk = { path = "../../../../sdk/", version = "1.0.12", default-features = false }
|
solana-sdk = { path = "../../../../sdk/", version = "1.0.17", default-features = false }
|
||||||
|
|
||||||
[dev_dependencies]
|
[dev_dependencies]
|
||||||
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.12" }
|
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "1.0.17" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
program = ["solana-sdk/program"]
|
program = ["solana-sdk/program"]
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user