Compare commits

...

58 Commits

Author SHA1 Message Date
293bb63ed8 Reduce rpc client pre-flight requests by setting max-age header (#8082) (#8083)
automerge
2020-02-01 08:48:40 -08:00
8f8fb720af CLI: Fix stake-account auth withdrawer output (#8071)
automerge

(cherry picked from commit 9739be9ecf)
2020-02-01 08:58:13 -07:00
19f414d843 Use solana-cli config keypair in solana-keygen (bp #8074) (#8080)
* Use solana-cli config keypair in solana-keygen (#8074)

* Use solana-cli config keypair in solana-keygen

* s/infile/keypair for consistency across modules and more generality across access methods

* Move config into separate crate

(cherry picked from commit fab8ef379f)

# Conflicts:
#	Cargo.lock
#	cli/Cargo.toml
#	keygen/Cargo.toml

* Fixup version numbers for backport

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-01-31 23:08:08 -07:00
eaca1c3170 Add new colo test cases using reduced node count (#8078) (#8079)
automerge
2020-01-31 19:06:36 -08:00
9fc75925f9 CLI: De-replicode SigningAuthority instatiation (#8076) (#8077)
automerge
2020-01-31 17:42:15 -08:00
b5098ac87c Filter repairman peers based on shred_version (#8069) (#8073)
automerge
2020-01-31 15:29:30 -08:00
e23aec9728 Update key (#8062) (#8066)
automerge
2020-01-31 12:55:49 -08:00
57d490c84f Minor cli fixes (bp #8061) (#8065)
automerge
2020-01-31 12:36:35 -08:00
aa8c9f6a98 Remove asteroids and pacman from QA/dev testnet availability (#8050) (#8063)
automerge
2020-01-31 11:28:33 -08:00
57772dc73d s/mint/faucet 2020-01-31 12:15:20 -07:00
21706108e8 Don't exit early if add. validators not found during gce.sh config
(cherry picked from commit 9adf0d4ee0)
2020-01-31 08:36:03 -07:00
50d0caf00f Remove support for 0.22.3 snapshots (#8058)
automerge
2020-01-31 00:15:44 -08:00
2739332306 Fix stale gossip entrypoint (#8053) (#8057)
automerge
2020-01-30 23:13:26 -08:00
c85c4699aa validator: add --private-rpc flag (bp #8037) (#8054)
automerge
2020-01-30 20:44:53 -08:00
81add4d6bf Make tds slots-per-epoch configurable 2020-01-30 21:38:39 -07:00
8e31eeb696 Dial testnet down to a single node 2020-01-30 21:17:38 -07:00
e1ce8b37ff Minor --expected-shred fix, clean up shred-related gossip log messages (#8041) (#8045)
automerge
2020-01-30 14:41:21 -08:00
3f831c05f5 Add different shred test to test_tvu_peers_and_stakes
(cherry picked from commit 0c55b37976)
2020-01-30 11:28:45 -07:00
f0d7ce6bb6 CLI: Disallow blockhash/fee-calc lookups when offline (#7981)
* CLI: Add BlockhashSpec to tighten control over --blockhash

* Use BlockhashSpec

* Add a matches-free constructor

* More descriptive naming

(cherry picked from commit 966d077431)
2020-01-30 09:39:04 -07:00
6ba95b2545 Ignore slow archiver tests (#8032)
automerge

(cherry picked from commit 400412d76c)
2020-01-30 09:38:49 -07:00
6818e68542 Add shred version filters to Crds Accessors (#8027)
* Add shred version filters to Crds Accessors

* Adopt entrypoint shred_version if one isn't provided

(cherry picked from commit 64c42e28dc)
2020-01-30 08:58:36 -07:00
43659d7deb Remove support for stake redelegation (#7995) (#8024)
automerge
2020-01-29 23:46:42 -08:00
f24d8e7d2d Add set_lockup to stake (#7997)
(cherry picked from commit 0d6c233747)
2020-01-29 23:22:04 -07:00
e10fe5e125 Update and fix transaction error documentation (#7998)
(cherry picked from commit fed3817ed3)
2020-01-29 23:20:32 -07:00
0f8c9ab1c4 Various fixes/improvements resulting from SLP 1.1 restart debug (bp #8019) (#8026)
automerge
2020-01-29 20:11:23 -08:00
8a9a9cb991 Log solana-validator args on startup to aid debugging
(cherry picked from commit effe6e3ff3)
2020-01-29 09:40:33 -07:00
44208ffa67 refactored 2020-01-28 20:29:56 -07:00
5df0478fa3 refactored the thread loop
a thread will break if the atomic bool is true
2020-01-28 20:29:56 -07:00
d52567933e refactored grind_parse_args and grind_print_info 2020-01-28 20:29:56 -07:00
a32cdb9f4d updated to slice 2020-01-28 20:29:56 -07:00
eacd8d986c put some logic into functions 2020-01-28 20:29:56 -07:00
1d32603b49 taking care of errors from ./test-check.sh 2020-01-28 20:29:56 -07:00
8c6f7ee5a4 ran cargo fmt 2020-01-28 20:29:56 -07:00
be482eed3f removed whitespace 2020-01-28 20:29:56 -07:00
6e1c53cb0f simplified messaging and if blocks 2020-01-28 20:29:56 -07:00
af92f205cf simplified messaging 2020-01-28 20:29:56 -07:00
87047b08c8 removed found and changed count to AtomicU64 2020-01-28 20:29:56 -07:00
e282161872 updated bs58 decode check 2020-01-28 20:29:56 -07:00
01b1e287ed fixed prefix typo 2020-01-28 20:29:56 -07:00
d7fd1fa467 added informative print statements 2020-01-28 20:29:56 -07:00
bfa34cd494 it works
need to add print out to inform user
2020-01-28 20:29:56 -07:00
915835e224 this command works but wont exit right when the 6th key is found
cargo run grind --starts-with hj:2 --ends-with jk:2 --starts-and-ends-with nⓂ️2
2020-01-28 20:29:56 -07:00
659332e7ac progress on storing parameters 2020-01-28 20:29:56 -07:00
272986c6ac validator methods work 2020-01-28 20:29:56 -07:00
4d8ab45c56 removed includes
added ends-with and starts-and-ends-with
updated help messages
added expected number of values
updated .value_name for each option
2020-01-28 20:29:56 -07:00
932ae86d47 CLI: Fix tests. sign_only requires a blockhash (#8005) (#8007)
automerge
2020-01-28 19:07:47 -08:00
756e6334b0 Add lock to make sure slot-based locktree calls are safe (#7993) (#7999)
automerge
2020-01-28 14:57:37 -08:00
4e6eca9748 Update cargo files to 0.23.1 (#7994)
automerge
2020-01-27 20:44:44 -08:00
d9e37eb30c Fix compute_shred_version() (#7989)
automerge

(cherry picked from commit fd7d5cbe0d)
2020-01-27 19:06:20 -07:00
04d1b35926 Consensus fix, don't consider threshold check if.. (#7948) (#7991)
automerge
2020-01-27 17:52:48 -08:00
d13d609050 Reduce epoch duration from 2 weeks to 2 days (#7987)
automerge
2020-01-27 10:24:20 -08:00
20426cf251 Specify where VM images are coming from across GCE projects (#7985) (#7986)
automerge
2020-01-27 09:02:05 -08:00
4a220d7c8e Remove show- prefix 2020-01-26 21:01:18 -07:00
436eab41ca Remove stray key 2020-01-26 14:35:50 -07:00
c8472d0a96 CLI: --sign-only and --signer require --blockhash (#7982) (#7983)
automerge
2020-01-26 10:19:04 -08:00
1a7db9c17e CLI: Consolidate offline arg declarations (#7979) (#7980)
automerge
2020-01-26 01:24:01 -08:00
b468d9f17c CLI: Deterministic dummy keypair generation for SigningAuthority::Offline (#7971) (#7978)
automerge
2020-01-26 00:13:06 -08:00
41cf1d7d23 s/dervied/derived/ 2020-01-25 23:22:55 -07:00
138 changed files with 2539 additions and 1888 deletions

666
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ members = [
"chacha", "chacha",
"chacha-cuda", "chacha-cuda",
"chacha-sys", "chacha-sys",
"cli-config",
"client", "client",
"core", "core",
"faucet", "faucet",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-archiver-lib" name = "solana-archiver-lib"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.1" }
thiserror = "1.0" thiserror = "1.0"
serde = "1.0.104" serde = "1.0.104"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-chacha = { path = "../chacha", version = "0.23.0" } solana-chacha = { path = "../chacha", version = "0.23.1" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.0" } solana-archiver-utils = { path = "../archiver-utils", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
hex = "0.4.0" hex = "0.4.0"

View File

@ -522,6 +522,8 @@ impl Archiver {
let mut contact_info = node_info.clone(); let mut contact_info = node_info.clone();
contact_info.tvu = "0.0.0.0:0".parse().unwrap(); contact_info.tvu = "0.0.0.0:0".parse().unwrap();
contact_info.wallclock = timestamp(); contact_info.wallclock = timestamp();
// copy over the adopted shred_version from the entrypoint
contact_info.shred_version = cluster_info.read().unwrap().my_data().shred_version;
{ {
let mut cluster_info_w = cluster_info.write().unwrap(); let mut cluster_info_w = cluster_info.write().unwrap();
cluster_info_w.insert_self(contact_info); cluster_info_w.insert_self(contact_info);
@ -701,7 +703,7 @@ impl Archiver {
) -> Result<u64> { ) -> Result<u64> {
let rpc_peers = { let rpc_peers = {
let cluster_info = cluster_info.read().unwrap(); let cluster_info = cluster_info.read().unwrap();
cluster_info.rpc_peers() cluster_info.all_rpc_peers()
}; };
debug!("rpc peers: {:?}", rpc_peers); debug!("rpc peers: {:?}", rpc_peers);
if !rpc_peers.is_empty() { if !rpc_peers.is_empty() {
@ -757,7 +759,7 @@ impl Archiver {
loop { loop {
let rpc_peers = { let rpc_peers = {
let cluster_info = cluster_info.read().unwrap(); let cluster_info = cluster_info.read().unwrap();
cluster_info.rpc_peers() cluster_info.all_rpc_peers()
}; };
debug!("rpc peers: {:?}", rpc_peers); debug!("rpc peers: {:?}", rpc_peers);
if !rpc_peers.is_empty() { if !rpc_peers.is_empty() {

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-archiver-utils" name = "solana-archiver-utils"
version = "0.23.0" version = "0.23.1"
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"
@ -12,12 +12,12 @@ 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 = { path = "../chacha", version = "0.23.0" } solana-chacha = { path = "../chacha", version = "0.23.1" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
hex = "0.4.0" hex = "0.4.0"

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-archiver" name = "solana-archiver"
version = "0.23.0" version = "0.23.1"
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.1" console = "0.9.1"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.0" } solana-archiver-lib = { path = "../archiver-lib", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-banking-bench" name = "solana-banking-bench"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
rand = "0.6.5" rand = "0.6.5"
crossbeam-channel = "0.3" crossbeam-channel = "0.3"

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-exchange" name = "solana-bench-exchange"
version = "0.23.0" version = "0.23.1"
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/"
@ -23,19 +23,19 @@ serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-genesis = { path = "../genesis", version = "0.23.0" } solana-genesis = { path = "../genesis", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.1" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" } solana-exchange-program = { path = "../programs/exchange", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
untrusted = "0.7.0" untrusted = "0.7.0"
ws = "0.9.1" ws = "0.9.1"
[dev-dependencies] [dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "0.23.0" } solana-local-cluster = { path = "../local-cluster", version = "0.23.1" }

View File

@ -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 = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-tps" name = "solana-bench-tps"
version = "0.23.0" version = "0.23.1"
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/"
@ -16,24 +16,24 @@ serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-genesis = { path = "../genesis", version = "0.23.0" } solana-genesis = { path = "../genesis", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.1" }
solana-librapay = { path = "../programs/librapay", version = "0.23.0", optional = true } solana-librapay = { path = "../programs/librapay", version = "0.23.1", optional = true }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-move-loader-program = { path = "../programs/move_loader", version = "0.23.0", optional = true } solana-move-loader-program = { path = "../programs/move_loader", version = "0.23.1", optional = true }
[dev-dependencies] [dev-dependencies]
serial_test = "0.3.2" serial_test = "0.3.2"
serial_test_derive = "0.3.1" serial_test_derive = "0.3.1"
solana-local-cluster = { path = "../local-cluster", version = "0.23.0" } solana-local-cluster = { path = "../local-cluster", version = "0.23.1" }
[features] [features]
move = ["solana-librapay", "solana-move-loader-program"] move = ["solana-librapay", "solana-move-loader-program"]

View File

@ -827,7 +827,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": "0.23.0"},"id":1} {"jsonrpc":"2.0","result":{"solana-core": "0.23.1"},"id":1}
``` ```
### getVoteAccounts ### getVoteAccounts

View File

@ -177,7 +177,7 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
## Usage ## Usage
### solana-cli ### solana-cli
```text ```text
solana-cli 0.23.0 [channel=unknown commit=unknown] solana-cli 0.23.1 [channel=unknown commit=unknown]
Blockchain, Rebuilt for Scale Blockchain, Rebuilt for Scale
USAGE: USAGE:
@ -212,7 +212,7 @@ SUBCOMMANDS:
cluster-version Get the version of the cluster entrypoint cluster-version Get the version of the cluster entrypoint
config Solana command-line tool configuration settings config Solana command-line tool configuration settings
confirm Confirm transaction by signature confirm Confirm transaction by signature
create-address-with-seed Generate a dervied account address with a seed create-address-with-seed Generate a derived account address with a seed
create-archiver-storage-account Create an archiver storage account create-archiver-storage-account Create an archiver storage account
create-nonce-account Create a nonce account create-nonce-account Create a nonce account
create-stake-account Create a stake account create-stake-account Create a stake account
@ -618,7 +618,7 @@ ARGS:
#### solana-create-address-with-seed #### solana-create-address-with-seed
```text ```text
solana-create-address-with-seed solana-create-address-with-seed
Generate a dervied account address with a seed Generate a derived account address with a seed
USAGE: USAGE:
solana create-address-with-seed [FLAGS] [OPTIONS] <SEED_STRING> <PROGRAM_ID> solana create-address-with-seed [FLAGS] [OPTIONS] <SEED_STRING> <PROGRAM_ID>

View File

@ -94,12 +94,13 @@ The Stakes and the RewardsPool are accounts that are owned by the same `Stake` p
### StakeInstruction::DelegateStake ### StakeInstruction::DelegateStake
The Stake account is moved from Ininitialized to StakeState::Stake form. This is how stakers choose their initial delegate validator node and activate their stake account lamports. The transaction must be signed by the stake's `authorized_staker`. If the stake account is already StakeState::Stake \(i.e. already activated\), the stake is re-delegated. Stakes may be re-delegated at any time, and updated stakes are reflected immediately, but only one re-delegation is permitted per epoch. The Stake account is moved from Initialized to StakeState::Stake form, or from a deactivated (i.e. fully cooled-down) StakeState::Stake to activated StakeState::Stake. This is how stakers choose the vote account and validator node to which their stake account lamports are delegated. The transaction must be signed by the stake's `authorized_staker`.
* `account[0]` - RW - The StakeState::Stake instance. `StakeState::Stake::credits_observed` is initialized to `VoteState::credits`, `StakeState::Stake::voter_pubkey` is initialized to `account[1]`. If this is the initial delegation of stake, `StakeState::Stake::stake` is initialized to the account's balance in lamports, `StakeState::Stake::activated` is initialized to the current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX * `account[0]` - RW - The StakeState::Stake instance. `StakeState::Stake::credits_observed` is initialized to `VoteState::credits`, `StakeState::Stake::voter_pubkey` is initialized to `account[1]`. If this is the initial delegation of stake, `StakeState::Stake::stake` is initialized to the account's balance in lamports, `StakeState::Stake::activated` is initialized to the current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX
* `account[1]` - R - The VoteState instance. * `account[1]` - R - The VoteState instance.
* `account[2]` - R - sysvar::clock account, carries information about current Bank epoch * `account[2]` - R - sysvar::clock account, carries information about current Bank epoch
* `account[3]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration * `account[3]` - R - sysvar::stakehistory account, carries information about stake history
* `account[4]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration
### StakeInstruction::Authorize\(Pubkey, StakeAuthorize\) ### StakeInstruction::Authorize\(Pubkey, StakeAuthorize\)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-chacha-cuda" name = "solana-chacha-cuda"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-archiver-utils = { path = "../archiver-utils", version = "0.23.1" }
solana-chacha = { path = "../chacha", version = "0.23.0" } solana-chacha = { path = "../chacha", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
hex-literal = "0.2.1" hex-literal = "0.2.1"

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-chacha" name = "solana-chacha"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
hex-literal = "0.2.1" hex-literal = "0.2.1"

View File

@ -378,7 +378,7 @@ deploy() {
( (
set -x set -x
ci/testnet-deploy.sh -p testnet-solana-com -C gce -z us-west1-b \ ci/testnet-deploy.sh -p testnet-solana-com -C gce -z us-west1-b \
-t "$CHANNEL_OR_TAG" -n 1 -c 0 -u -P \ -t "$CHANNEL_OR_TAG" -n 0 -c 0 -u -P \
-a testnet-solana-com --letsencrypt testnet.solana.com \ -a testnet-solana-com --letsencrypt testnet.solana.com \
--limit-ledger-size \ --limit-ledger-size \
${skipCreate:+-e} \ ${skipCreate:+-e} \
@ -455,6 +455,10 @@ deploy() {
TDS_CLIENT_COUNT="1" TDS_CLIENT_COUNT="1"
fi fi
if [[ -n $TDS_SLOTS_PER_EPOCH ]]; then
maybeSlotsPerEpoch=(--slots-per-epoch "$TDS_SLOTS_PER_EPOCH")
fi
if [[ -z $ENABLE_GPU ]]; then if [[ -z $ENABLE_GPU ]]; then
maybeGpu=(-G "--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100") maybeGpu=(-G "--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100")
elif [[ $ENABLE_GPU == skip ]]; then elif [[ $ENABLE_GPU == skip ]]; then
@ -540,7 +544,7 @@ deploy() {
${maybeInternalNodesLamports} \ ${maybeInternalNodesLamports} \
${maybeExternalAccountsFile} \ ${maybeExternalAccountsFile} \
--target-lamports-per-signature 0 \ --target-lamports-per-signature 0 \
--slots-per-epoch 4096 \ "${maybeSlotsPerEpoch[@]}" \
${maybeAdditionalDisk} ${maybeAdditionalDisk}
) )
;; ;;

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-clap-utils" name = "solana-clap-utils"
version = "0.23.0" version = "0.23.1"
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"
@ -12,7 +12,7 @@ edition = "2018"
clap = "2.33.0" clap = "2.33.0"
rpassword = "4.0" rpassword = "4.0"
semver = "0.9.0" semver = "0.9.0"
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
tiny-bip39 = "0.7.0" tiny-bip39 = "0.7.0"
url = "2.1.0" url = "2.1.0"
chrono = "0.4" chrono = "0.4"

16
cli-config/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "0.23.1"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
dirs = "2.0.2"
lazy_static = "1.4.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_yaml = "0.8.11"

View File

@ -1,8 +1,10 @@
// 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::fs::{create_dir_all, File}; use std::{
use std::io::{self, Write}; fs::{create_dir_all, File},
use std::path::Path; io::{self, Write},
path::Path,
};
lazy_static! { lazy_static! {
pub static ref CONFIG_FILE: Option<String> = { pub static ref CONFIG_FILE: Option<String> = {

4
cli-config/src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
#[macro_use]
extern crate lazy_static;
pub mod config;

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-cli" name = "solana-cli"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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/"
@ -17,7 +17,6 @@ criterion-stats = "0.3.0"
ctrlc = { version = "3.1.3", features = ["termination"] } ctrlc = { version = "3.1.3", features = ["termination"] }
console = "0.9.1" console = "0.9.1"
dirs = "2.0.2" dirs = "2.0.2"
lazy_static = "1.4.0"
log = "0.4.8" log = "0.4.8"
indicatif = "0.13.0" indicatif = "0.13.0"
humantime = "2.0.0" humantime = "2.0.0"
@ -28,24 +27,25 @@ serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-cli-config = { path = "../cli-config", version = "0.23.1" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.1" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.1" }
url = "2.1.1" url = "2.1.1"
[dev-dependencies] [dev-dependencies]
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
tempfile = "3.1.0" tempfile = "3.1.0"
[[bin]] [[bin]]

View File

@ -2,6 +2,7 @@ use crate::{
cluster_query::*, cluster_query::*,
display::{println_name_value, println_signers}, display::{println_name_value, println_signers},
nonce::{self, *}, nonce::{self, *},
offline::*,
stake::*, stake::*,
storage::*, storage::*,
validator_info::*, validator_info::*,
@ -31,7 +32,7 @@ use solana_sdk::{
message::Message, message::Message,
native_token::lamports_to_sol, native_token::lamports_to_sol,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature}, signature::{keypair_from_seed, Keypair, KeypairUtil, Signature},
system_instruction::{create_address_with_seed, SystemError, MAX_ADDRESS_SEED_LEN}, system_instruction::{create_address_with_seed, SystemError, MAX_ADDRESS_SEED_LEN},
system_transaction, system_transaction,
transaction::{Transaction, TransactionError}, transaction::{Transaction, TransactionError},
@ -85,21 +86,26 @@ impl SigningAuthority {
matches: &ArgMatches<'_>, matches: &ArgMatches<'_>,
name: &str, name: &str,
signers: Option<&[(Pubkey, Signature)]>, signers: Option<&[(Pubkey, Signature)]>,
) -> Result<Self, CliError> { ) -> Result<Option<Self>, CliError> {
keypair_of(matches, name) if matches.is_present(name) {
.map(|keypair| keypair.into()) keypair_of(matches, name)
.or_else(|| { .map(|keypair| keypair.into())
pubkey_of(matches, name) .or_else(|| {
.filter(|pubkey| { pubkey_of(matches, name)
signers .filter(|pubkey| {
.and_then(|signers| { signers
signers.iter().find(|(signer, _sig)| *signer == *pubkey) .and_then(|signers| {
}) signers.iter().find(|(signer, _sig)| *signer == *pubkey)
.is_some() })
}) .is_some()
.map(|pubkey| pubkey.into()) })
}) .map(|pubkey| pubkey.into())
.ok_or_else(|| CliError::BadParameter("Invalid authority".to_string())) })
.ok_or_else(|| CliError::BadParameter("Invalid authority".to_string()))
.map(Some)
} else {
Ok(None)
}
} }
pub fn keypair(&self) -> &Keypair { pub fn keypair(&self) -> &Keypair {
@ -125,7 +131,7 @@ impl From<Keypair> for SigningAuthority {
impl From<Pubkey> for SigningAuthority { impl From<Pubkey> for SigningAuthority {
fn from(pubkey: Pubkey) -> Self { fn from(pubkey: Pubkey) -> Self {
SigningAuthority::Offline(pubkey, Keypair::new()) SigningAuthority::Offline(pubkey, keypair_from_seed(pubkey.as_ref()).unwrap())
} }
} }
@ -160,7 +166,7 @@ pub struct PayCommand {
pub cancelable: bool, pub cancelable: bool,
pub sign_only: bool, pub sign_only: bool,
pub signers: Option<Vec<(Pubkey, Signature)>>, pub signers: Option<Vec<(Pubkey, Signature)>>,
pub blockhash: Option<Hash>, pub blockhash_query: BlockhashQuery,
pub nonce_account: Option<Pubkey>, pub nonce_account: Option<Pubkey>,
pub nonce_authority: Option<SigningAuthority>, pub nonce_authority: Option<SigningAuthority>,
} }
@ -192,6 +198,7 @@ pub enum CliCommand {
GetTransactionCount { GetTransactionCount {
commitment_config: CommitmentConfig, commitment_config: CommitmentConfig,
}, },
LeaderSchedule,
Ping { Ping {
lamports: u64, lamports: u64,
interval: Duration, interval: Duration,
@ -254,7 +261,7 @@ pub enum CliCommand {
stake_authority: Option<SigningAuthority>, stake_authority: Option<SigningAuthority>,
sign_only: bool, sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>, signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<SigningAuthority>, nonce_authority: Option<SigningAuthority>,
}, },
@ -265,7 +272,7 @@ pub enum CliCommand {
force: bool, force: bool,
sign_only: bool, sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>, signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<SigningAuthority>, nonce_authority: Option<SigningAuthority>,
}, },
@ -283,7 +290,7 @@ pub enum CliCommand {
authority: Option<SigningAuthority>, authority: Option<SigningAuthority>,
sign_only: bool, sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>, signers: Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<SigningAuthority>, nonce_authority: Option<SigningAuthority>,
}, },
@ -455,6 +462,10 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
}), }),
("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 {
command: CliCommand::LeaderSchedule,
require_keypair: false,
}),
("ping", Some(matches)) => parse_cluster_ping(matches), ("ping", Some(matches)) => parse_cluster_ping(matches),
("block-production", Some(matches)) => parse_show_block_production(matches), ("block-production", Some(matches)) => parse_show_block_production(matches),
("gossip", Some(_matches)) => Ok(CliCommandInfo { ("gossip", Some(_matches)) => Ok(CliCommandInfo {
@ -488,8 +499,8 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
("stake-authorize-withdrawer", Some(matches)) => { ("stake-authorize-withdrawer", Some(matches)) => {
parse_stake_authorize(matches, StakeAuthorize::Withdrawer) parse_stake_authorize(matches, StakeAuthorize::Withdrawer)
} }
("show-stake-account", Some(matches)) => parse_show_stake_account(matches), ("stake-account", Some(matches)) => parse_show_stake_account(matches),
("show-stake-history", Some(matches)) => parse_show_stake_history(matches), ("stake-history", Some(matches)) => parse_show_stake_history(matches),
// Storage Commands // Storage Commands
("create-archiver-storage-account", Some(matches)) => { ("create-archiver-storage-account", Some(matches)) => {
parse_storage_create_archiver_account(matches) parse_storage_create_archiver_account(matches)
@ -599,19 +610,15 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
let timestamp_pubkey = value_of(&matches, "timestamp_pubkey"); let timestamp_pubkey = value_of(&matches, "timestamp_pubkey");
let witnesses = values_of(&matches, "witness"); let witnesses = values_of(&matches, "witness");
let cancelable = matches.is_present("cancelable"); let cancelable = matches.is_present("cancelable");
let sign_only = matches.is_present("sign_only"); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, "signer"); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(&matches, "blockhash"); let blockhash_query = BlockhashQuery::new_from_matches(&matches);
let nonce_account = pubkey_of(&matches, NONCE_ARG.name); let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) { let nonce_authority = SigningAuthority::new_from_matches(
Some(SigningAuthority::new_from_matches( &matches,
&matches, NONCE_AUTHORITY_ARG.name,
NONCE_AUTHORITY_ARG.name, signers.as_deref(),
signers.as_deref(), )?;
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
@ -623,7 +630,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
cancelable, cancelable,
sign_only, sign_only,
signers, signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
nonce_authority, nonce_authority,
}), }),
@ -1002,7 +1009,7 @@ fn process_pay(
cancelable: bool, cancelable: bool,
sign_only: bool, sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>, signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<&SigningAuthority>, nonce_authority: Option<&SigningAuthority>,
) -> ProcessResult { ) -> ProcessResult {
@ -1011,8 +1018,7 @@ fn process_pay(
(to, "to".to_string()), (to, "to".to_string()),
)?; )?;
let (blockhash, fee_calculator) = let (blockhash, fee_calculator) = blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?;
let cancelable = if cancelable { let cancelable = if cancelable {
Some(config.keypair.pubkey()) Some(config.keypair.pubkey())
@ -1260,6 +1266,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::GetTransactionCount { commitment_config } => { CliCommand::GetTransactionCount { commitment_config } => {
process_get_transaction_count(&rpc_client, commitment_config) process_get_transaction_count(&rpc_client, commitment_config)
} }
CliCommand::LeaderSchedule => process_leader_schedule(&rpc_client),
CliCommand::Ping { CliCommand::Ping {
lamports, lamports,
interval, interval,
@ -1381,7 +1388,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
ref stake_authority, ref stake_authority,
sign_only, sign_only,
ref signers, ref signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
ref nonce_authority, ref nonce_authority,
} => process_deactivate_stake_account( } => process_deactivate_stake_account(
@ -1391,7 +1398,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
stake_authority.as_ref(), stake_authority.as_ref(),
*sign_only, *sign_only,
signers, signers,
*blockhash, blockhash_query,
*nonce_account, *nonce_account,
nonce_authority.as_ref(), nonce_authority.as_ref(),
), ),
@ -1402,7 +1409,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
force, force,
sign_only, sign_only,
ref signers, ref signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
ref nonce_authority, ref nonce_authority,
} => process_delegate_stake( } => process_delegate_stake(
@ -1414,7 +1421,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*force, *force,
*sign_only, *sign_only,
signers, signers,
*blockhash, blockhash_query,
*nonce_account, *nonce_account,
nonce_authority.as_ref(), nonce_authority.as_ref(),
), ),
@ -1437,7 +1444,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
ref authority, ref authority,
sign_only, sign_only,
ref signers, ref signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
ref nonce_authority, ref nonce_authority,
} => process_stake_authorize( } => process_stake_authorize(
@ -1449,7 +1456,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
authority.as_ref(), authority.as_ref(),
*sign_only, *sign_only,
signers, signers,
*blockhash, blockhash_query,
*nonce_account, *nonce_account,
nonce_authority.as_ref(), nonce_authority.as_ref(),
), ),
@ -1621,7 +1628,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
cancelable, cancelable,
sign_only, sign_only,
ref signers, ref signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
ref nonce_authority, ref nonce_authority,
}) => process_pay( }) => process_pay(
@ -1635,7 +1642,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*cancelable, *cancelable,
*sign_only, *sign_only,
signers, signers,
*blockhash, blockhash_query,
*nonce_account, *nonce_account,
nonce_authority.as_ref(), nonce_authority.as_ref(),
), ),
@ -1871,7 +1878,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
) )
.subcommand( .subcommand(
SubCommand::with_name("create-address-with-seed") SubCommand::with_name("create-address-with-seed")
.about("Generate a dervied account address with a seed") .about("Generate a derived account address with a seed")
.arg( .arg(
Arg::with_name("seed") Arg::with_name("seed")
.index(1) .index(1)
@ -1973,31 +1980,9 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.long("cancelable") .long("cancelable")
.takes_value(false), .takes_value(false),
) )
.arg( .offline_args()
Arg::with_name("sign_only")
.long("sign-only")
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg()),
.arg(
Arg::with_name("signer")
.long("signer")
.value_name("PUBKEY=BASE58_SIG")
.takes_value(true)
.validator(is_pubkey_sig)
.multiple(true)
.help("Provide a public-key/signature pair for the transaction"),
)
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.value_name("BLOCKHASH")
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
),
) )
.subcommand( .subcommand(
SubCommand::with_name("send-signature") SubCommand::with_name("send-signature")
@ -2092,6 +2077,7 @@ mod tests {
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
nonce_state::{Meta as NonceMeta, NonceState}, nonce_state::{Meta as NonceMeta, NonceState},
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair_file}, signature::{read_keypair_file, write_keypair_file},
system_program, system_program,
transaction::TransactionError, transaction::TransactionError,
@ -2112,6 +2098,13 @@ mod tests {
path path
} }
#[test]
fn test_signing_authority_dummy_keypairs() {
let signing_authority: SigningAuthority = Pubkey::new(&[1u8; 32]).into();
assert_eq!(signing_authority, Pubkey::new(&[1u8; 32]).into());
assert_ne!(signing_authority, Pubkey::new(&[2u8; 32]).into());
}
#[test] #[test]
fn test_cli_parse_command() { fn test_cli_parse_command() {
let test_commands = app("test", "desc", "version"); let test_commands = app("test", "desc", "version");
@ -2375,12 +2368,16 @@ mod tests {
); );
// Test Pay Subcommand w/ sign-only // Test Pay Subcommand w/ sign-only
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let test_pay = test_commands.clone().get_matches_from(vec![ let test_pay = test_commands.clone().get_matches_from(vec![
"test", "test",
"pay", "pay",
&pubkey_string, &pubkey_string,
"50", "50",
"lamports", "lamports",
"--blockhash",
&blockhash_string,
"--sign-only", "--sign-only",
]); ]);
assert_eq!( assert_eq!(
@ -2389,6 +2386,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
sign_only: true, sign_only: true,
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2406,6 +2404,8 @@ mod tests {
&pubkey_string, &pubkey_string,
"50", "50",
"lamports", "lamports",
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
]); ]);
@ -2415,6 +2415,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
signers: Some(vec![(key1, sig1)]), signers: Some(vec![(key1, sig1)]),
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2432,6 +2433,8 @@ mod tests {
&pubkey_string, &pubkey_string,
"50", "50",
"lamports", "lamports",
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
"--signer", "--signer",
@ -2443,6 +2446,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
signers: Some(vec![(key1, sig1), (key2, sig2)]), signers: Some(vec![(key1, sig1), (key2, sig2)]),
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2451,8 +2455,6 @@ mod tests {
); );
// Test Pay Subcommand w/ Blockhash // Test Pay Subcommand w/ Blockhash
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let test_pay = test_commands.clone().get_matches_from(vec![ let test_pay = test_commands.clone().get_matches_from(vec![
"test", "test",
"pay", "pay",
@ -2468,7 +2470,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
..PayCommand::default() ..PayCommand::default()
}), }),
require_keypair: true require_keypair: true
@ -2495,7 +2497,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey), nonce_account: Some(pubkey),
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2526,7 +2528,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey), nonce_account: Some(pubkey),
nonce_authority: Some(keypair.into()), nonce_authority: Some(keypair.into()),
..PayCommand::default() ..PayCommand::default()
@ -2562,7 +2564,7 @@ mod tests {
command: CliCommand::Pay(PayCommand { command: CliCommand::Pay(PayCommand {
lamports: 50, lamports: 50,
to: pubkey, to: pubkey,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey), nonce_account: Some(pubkey),
nonce_authority: Some(authority_pubkey.into()), nonce_authority: Some(authority_pubkey.into()),
signers: Some(vec![(authority_pubkey, sig)]), signers: Some(vec![(authority_pubkey, sig)]),
@ -2766,7 +2768,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -2852,7 +2854,7 @@ mod tests {
lamports: 10, lamports: 10,
to: bob_pubkey, to: bob_pubkey,
nonce_account: Some(bob_pubkey), nonce_account: Some(bob_pubkey),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
..PayCommand::default() ..PayCommand::default()
}); });
let signature = process_command(&config); let signature = process_command(&config);
@ -2879,7 +2881,7 @@ mod tests {
config.command = CliCommand::Pay(PayCommand { config.command = CliCommand::Pay(PayCommand {
lamports: 10, lamports: 10,
to: bob_pubkey, to: bob_pubkey,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(bob_pubkey), nonce_account: Some(bob_pubkey),
nonce_authority: Some(bob_keypair.into()), nonce_authority: Some(bob_keypair.into()),
..PayCommand::default() ..PayCommand::default()

View File

@ -67,6 +67,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.help("Slot number of the block to query") .help("Slot number of the block to query")
) )
) )
.subcommand(SubCommand::with_name("leader-schedule").about("Display leader schedule"))
.subcommand( .subcommand(
SubCommand::with_name("epoch-info") SubCommand::with_name("epoch-info")
.about("Get information about the current epoch") .about("Get information about the current epoch")
@ -406,6 +407,41 @@ pub fn process_fees(rpc_client: &RpcClient) -> ProcessResult {
)) ))
} }
pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
let epoch_info = rpc_client.get_epoch_info()?;
let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index;
let leader_schedule = rpc_client.get_leader_schedule(Some(first_slot_in_epoch))?;
if leader_schedule.is_none() {
return Err(format!(
"Unable to fetch leader schedule for slot {}",
first_slot_in_epoch
)
.into());
}
let leader_schedule = leader_schedule.unwrap();
let mut leader_per_slot_index = Vec::new();
for (pubkey, leader_slots) in leader_schedule.iter() {
for slot_index in leader_slots.iter() {
if *slot_index >= leader_per_slot_index.len() {
leader_per_slot_index.resize(*slot_index + 1, "?");
}
leader_per_slot_index[*slot_index] = pubkey;
}
}
for (slot_index, leader) in leader_per_slot_index.iter().enumerate() {
println!(
" {:<15} {:<44}",
first_slot_in_epoch + slot_index as u64,
leader
);
}
Ok("".to_string())
}
pub fn process_get_block_time(rpc_client: &RpcClient, slot: Slot) -> ProcessResult { pub fn process_get_block_time(rpc_client: &RpcClient, slot: Slot) -> ProcessResult {
let timestamp = rpc_client.get_block_time(slot)?; let timestamp = rpc_client.get_block_time(slot)?;
Ok(timestamp.to_string()) Ok(timestamp.to_string())

View File

@ -1,11 +1,8 @@
#[macro_use]
extern crate lazy_static;
pub mod cli; pub mod cli;
pub mod cluster_query; pub mod cluster_query;
pub mod config;
pub mod display; pub mod display;
pub mod nonce; pub mod nonce;
pub mod offline;
pub mod stake; pub mod stake;
pub mod storage; pub mod storage;
pub mod validator_info; pub mod validator_info;

View File

@ -10,9 +10,9 @@ use solana_clap_utils::{
}; };
use solana_cli::{ use solana_cli::{
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError}, cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
config::{self, Config},
display::{println_name_value, println_name_value_or}, display::{println_name_value, println_name_value_or},
}; };
use solana_cli_config::config::{Config, CONFIG_FILE};
use solana_sdk::signature::read_keypair_file; use solana_sdk::signature::read_keypair_file;
use std::error; use std::error;
@ -162,7 +162,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.takes_value(true) .takes_value(true)
.global(true) .global(true)
.help("Configuration file to use"); .help("Configuration file to use");
if let Some(ref config_file) = *config::CONFIG_FILE { if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(&config_file) arg.default_value(&config_file)
} else { } else {
arg arg

View File

@ -3,6 +3,7 @@ use crate::cli::{
log_instruction_custom_error, required_lamports_from, CliCommand, CliCommandInfo, CliConfig, log_instruction_custom_error, required_lamports_from, CliCommand, CliCommandInfo, CliConfig,
CliError, ProcessResult, SigningAuthority, CliError, ProcessResult, SigningAuthority,
}; };
use crate::offline::BLOCKHASH_ARG;
use clap::{App, Arg, ArgMatches, SubCommand}; use clap::{App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*, ArgConstant}; use solana_clap_utils::{input_parsers::*, input_validators::*, ArgConstant};
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
@ -55,7 +56,7 @@ pub fn nonce_arg<'a, 'b>() -> Arg<'a, 'b> {
.long(NONCE_ARG.long) .long(NONCE_ARG.long)
.takes_value(true) .takes_value(true)
.value_name("PUBKEY") .value_name("PUBKEY")
.requires("blockhash") .requires(BLOCKHASH_ARG.name)
.validator(is_pubkey) .validator(is_pubkey)
.help(NONCE_ARG.help) .help(NONCE_ARG.help)
} }
@ -233,15 +234,8 @@ impl NonceSubCommands for App<'_, '_> {
pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> { pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap(); let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let new_authority = pubkey_of(matches, "new_authority").unwrap(); let new_authority = pubkey_of(matches, "new_authority").unwrap();
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) { let nonce_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
&matches,
NONCE_AUTHORITY_ARG.name,
None,
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount { command: CliCommand::AuthorizeNonceAccount {
@ -281,15 +275,8 @@ pub fn parse_get_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliEr
pub fn parse_new_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> { pub fn parse_new_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap(); let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) { let nonce_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
&matches,
NONCE_AUTHORITY_ARG.name,
None,
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::NewNonce { command: CliCommand::NewNonce {
@ -319,15 +306,8 @@ pub fn parse_withdraw_from_nonce_account(
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap(); let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap(); let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?; let lamports = required_lamports_from(matches, "amount", "unit")?;
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) { let nonce_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
&matches,
NONCE_AUTHORITY_ARG.name,
None,
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::WithdrawFromNonceAccount { command: CliCommand::WithdrawFromNonceAccount {

252
cli/src/offline.rs Normal file
View File

@ -0,0 +1,252 @@
use clap::{App, Arg, ArgMatches};
use solana_clap_utils::{
input_parsers::value_of,
input_validators::{is_hash, is_pubkey_sig},
ArgConstant,
};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash};
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
name: "blockhash",
long: "blockhash",
help: "Use the supplied blockhash",
};
pub const SIGN_ONLY_ARG: ArgConstant<'static> = ArgConstant {
name: "sign_only",
long: "sign-only",
help: "Sign the transaction offline",
};
pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
name: "signer",
long: "signer",
help: "Provid a public-key/signature pair for the transaction",
};
#[derive(Clone, Debug, PartialEq)]
pub enum BlockhashQuery {
None(Hash, FeeCalculator),
FeeCalculator(Hash),
All,
}
impl BlockhashQuery {
pub fn new(blockhash: Option<Hash>, sign_only: bool) -> Self {
match blockhash {
Some(hash) if sign_only => Self::None(hash, FeeCalculator::default()),
Some(hash) if !sign_only => Self::FeeCalculator(hash),
None if !sign_only => Self::All,
_ => panic!("Cannot resolve blockhash"),
}
}
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
BlockhashQuery::new(blockhash, sign_only)
}
pub fn get_blockhash_fee_calculator(
&self,
rpc_client: &RpcClient,
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
let (hash, fee_calc) = match self {
BlockhashQuery::None(hash, fee_calc) => (Some(hash), Some(fee_calc)),
BlockhashQuery::FeeCalculator(hash) => (Some(hash), None),
BlockhashQuery::All => (None, None),
};
if None == fee_calc {
let (cluster_hash, fee_calc) = rpc_client.get_recent_blockhash()?;
Ok((*hash.unwrap_or(&cluster_hash), fee_calc))
} else {
Ok((*hash.unwrap(), fee_calc.unwrap().clone()))
}
}
}
impl Default for BlockhashQuery {
fn default() -> Self {
BlockhashQuery::All
}
}
fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help(BLOCKHASH_ARG.help)
}
fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGN_ONLY_ARG.name)
.long(SIGN_ONLY_ARG.long)
.takes_value(false)
.requires(BLOCKHASH_ARG.name)
.help(SIGN_ONLY_ARG.help)
}
fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGNER_ARG.name)
.long(SIGNER_ARG.long)
.takes_value(true)
.value_name("BASE58_PUBKEY=BASE58_SIG")
.validator(is_pubkey_sig)
.requires(BLOCKHASH_ARG.name)
.multiple(true)
.help(SIGNER_ARG.help)
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args(self) -> Self {
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}
#[cfg(test)]
mod tests {
use super::*;
use clap::App;
use serde_json::{self, json, Value};
use solana_client::{
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext},
};
use solana_sdk::{fee_calculator::FeeCalculator, hash::hash};
use std::collections::HashMap;
#[test]
fn test_blockhashspec_new_ok() {
let blockhash = hash(&[1u8]);
assert_eq!(
BlockhashQuery::new(Some(blockhash), true),
BlockhashQuery::None(blockhash, FeeCalculator::default()),
);
assert_eq!(
BlockhashQuery::new(Some(blockhash), false),
BlockhashQuery::FeeCalculator(blockhash),
);
assert_eq!(BlockhashQuery::new(None, false), BlockhashQuery::All,);
}
#[test]
#[should_panic]
fn test_blockhashspec_new_fail() {
BlockhashQuery::new(None, true);
}
#[test]
fn test_blockhashspec_new_from_matches_ok() {
let test_commands = App::new("blockhashspec_test").offline_args();
let blockhash = hash(&[1u8]);
let blockhash_string = blockhash.to_string();
let matches = test_commands.clone().get_matches_from(vec![
"blockhashspec_test",
"--blockhash",
&blockhash_string,
"--sign-only",
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::None(blockhash, FeeCalculator::default()),
);
let matches = test_commands.clone().get_matches_from(vec![
"blockhashspec_test",
"--blockhash",
&blockhash_string,
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::FeeCalculator(blockhash),
);
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhashspec_test"]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::All,
);
}
#[test]
#[should_panic]
fn test_blockhashspec_new_from_matches_fail() {
let test_commands = App::new("blockhashspec_test")
.arg(blockhash_arg())
// We can really only hit this case unless the arg requirements
// are broken, so unset the requires() to recreate that condition
.arg(sign_only_arg().requires(""));
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhashspec_test", "--sign-only"]);
BlockhashQuery::new_from_matches(&matches);
}
#[test]
fn test_blockhashspec_get_blockhash_fee_calc() {
let test_blockhash = hash(&[0u8]);
let rpc_blockhash = hash(&[1u8]);
let rpc_fee_calc = FeeCalculator::new(42, 42);
let get_recent_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
value: json!((
Value::String(rpc_blockhash.to_string()),
serde_json::to_value(rpc_fee_calc.clone()).unwrap()
)),
});
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::All
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(rpc_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::FeeCalculator(test_blockhash)
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::None(test_blockhash, FeeCalculator::default())
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, FeeCalculator::default()),
);
let rpc_client = RpcClient::new_mock("fails".to_string());
assert!(BlockhashQuery::All
.get_blockhash_fee_calculator(&rpc_client)
.is_err());
}
}

View File

@ -1,11 +1,12 @@
use crate::{ use crate::{
cli::{ cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys, build_balance_message, check_account_for_fee, check_unique_pubkeys,
get_blockhash_fee_calculator, log_instruction_custom_error, nonce_authority_arg, log_instruction_custom_error, nonce_authority_arg, replace_signatures,
replace_signatures, required_lamports_from, return_signers, CliCommand, CliCommandInfo, required_lamports_from, return_signers, CliCommand, CliCommandInfo, CliConfig, CliError,
CliConfig, CliError, ProcessResult, SigningAuthority, ProcessResult, SigningAuthority,
}, },
nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG}, nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
offline::*,
}; };
use clap::{App, Arg, ArgMatches, SubCommand}; use clap::{App, Arg, ArgMatches, SubCommand};
use console::style; use console::style;
@ -14,7 +15,6 @@ use solana_client::rpc_client::RpcClient;
use solana_sdk::signature::{Keypair, Signature}; use solana_sdk::signature::{Keypair, Signature};
use solana_sdk::{ use solana_sdk::{
account_utils::StateMut, account_utils::StateMut,
hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
signature::KeypairUtil, signature::KeypairUtil,
system_instruction::{create_address_with_seed, SystemError}, system_instruction::{create_address_with_seed, SystemError},
@ -172,29 +172,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("The vote account to which the stake will be delegated") .help("The vote account to which the stake will be delegated")
) )
.arg(stake_authority_arg()) .arg(stake_authority_arg())
.arg( .offline_args()
Arg::with_name("sign_only")
.long("sign-only")
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(
Arg::with_name("signer")
.long("signer")
.value_name("PUBKEY=BASE58_SIG")
.takes_value(true)
.validator(is_pubkey_sig)
.multiple(true)
.help("Provide a public-key/signature pair for the transaction"),
)
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.value_name("BLOCKHASH")
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg())
) )
@ -220,29 +198,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("New authorized staker") .help("New authorized staker")
) )
.arg(stake_authority_arg()) .arg(stake_authority_arg())
.arg( .offline_args()
Arg::with_name("sign_only")
.long("sign-only")
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(
Arg::with_name("signer")
.long("signer")
.value_name("PUBKEY=BASE58_SIG")
.takes_value(true)
.validator(is_pubkey_sig)
.multiple(true)
.help("Provide a public-key/signature pair for the transaction"),
)
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.value_name("BLOCKHASH")
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg())
) )
@ -268,29 +224,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("New authorized withdrawer") .help("New authorized withdrawer")
) )
.arg(withdraw_authority_arg()) .arg(withdraw_authority_arg())
.arg( .offline_args()
Arg::with_name("sign_only")
.long("sign-only")
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(
Arg::with_name("signer")
.long("signer")
.value_name("PUBKEY=BASE58_SIG")
.takes_value(true)
.validator(is_pubkey_sig)
.multiple(true)
.help("Provide a public-key/signature pair for the transaction"),
)
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.value_name("BLOCKHASH")
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg())
) )
@ -306,29 +240,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("Stake account to be deactivated.") .help("Stake account to be deactivated.")
) )
.arg(stake_authority_arg()) .arg(stake_authority_arg())
.arg( .offline_args()
Arg::with_name("sign_only")
.long("sign-only")
.takes_value(false)
.help("Sign the transaction offline"),
)
.arg(
Arg::with_name("signer")
.long("signer")
.value_name("PUBKEY=BASE58_SIG")
.takes_value(true)
.validator(is_pubkey_sig)
.multiple(true)
.help("Provide a public-key/signature pair for the transaction"),
)
.arg(
Arg::with_name("blockhash")
.long("blockhash")
.value_name("BLOCKHASH")
.takes_value(true)
.validator(is_hash)
.help("Use the supplied blockhash"),
)
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg())
) )
@ -373,7 +285,7 @@ impl StakeSubCommands for App<'_, '_> {
.arg(withdraw_authority_arg()) .arg(withdraw_authority_arg())
) )
.subcommand( .subcommand(
SubCommand::with_name("show-stake-account") SubCommand::with_name("stake-account")
.about("Show the contents of a stake account") .about("Show the contents of a stake account")
.alias("show-stake-account") .alias("show-stake-account")
.arg( .arg(
@ -437,29 +349,15 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap(); let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap(); let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
let force = matches.is_present("force"); let force = matches.is_present("force");
let sign_only = matches.is_present("sign_only"); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, "signer"); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(matches, "blockhash"); let blockhash_query = BlockhashQuery::new_from_matches(matches);
let require_keypair = signers.is_none(); let require_keypair = signers.is_none();
let nonce_account = pubkey_of(&matches, NONCE_ARG.name); let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let stake_authority = if matches.is_present(STAKE_AUTHORITY_ARG.name) { let stake_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
&matches, let nonce_authority =
STAKE_AUTHORITY_ARG.name, SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
signers.as_deref(),
)?)
} else {
None
};
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
Some(SigningAuthority::new_from_matches(
&matches,
NONCE_AUTHORITY_ARG.name,
signers.as_deref(),
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::DelegateStake { command: CliCommand::DelegateStake {
@ -469,7 +367,7 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
force, force,
sign_only, sign_only,
signers, signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
nonce_authority, nonce_authority,
}, },
@ -487,28 +385,14 @@ pub fn parse_stake_authorize(
StakeAuthorize::Staker => STAKE_AUTHORITY_ARG.name, StakeAuthorize::Staker => STAKE_AUTHORITY_ARG.name,
StakeAuthorize::Withdrawer => WITHDRAW_AUTHORITY_ARG.name, StakeAuthorize::Withdrawer => WITHDRAW_AUTHORITY_ARG.name,
}; };
let sign_only = matches.is_present("sign_only"); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, "signer"); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let authority = if matches.is_present(authority_flag) { let authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, authority_flag, signers.as_deref())?;
&matches, let blockhash_query = BlockhashQuery::new_from_matches(matches);
authority_flag,
signers.as_deref(),
)?)
} else {
None
};
let blockhash = value_of(matches, "blockhash");
let nonce_account = pubkey_of(&matches, NONCE_ARG.name); let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) { let nonce_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
&matches,
NONCE_AUTHORITY_ARG.name,
signers.as_deref(),
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::StakeAuthorize { command: CliCommand::StakeAuthorize {
@ -518,7 +402,7 @@ pub fn parse_stake_authorize(
authority, authority,
sign_only, sign_only,
signers, signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
nonce_authority, nonce_authority,
}, },
@ -528,29 +412,15 @@ pub fn parse_stake_authorize(
pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> { pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap(); let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
let sign_only = matches.is_present("sign_only"); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, "signer"); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(matches, "blockhash"); let blockhash_query = BlockhashQuery::new_from_matches(matches);
let require_keypair = signers.is_none(); let require_keypair = signers.is_none();
let nonce_account = pubkey_of(&matches, NONCE_ARG.name); let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let stake_authority = if matches.is_present(STAKE_AUTHORITY_ARG.name) { let stake_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
&matches, let nonce_authority =
STAKE_AUTHORITY_ARG.name, SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
signers.as_deref(),
)?)
} else {
None
};
let nonce_authority = if matches.is_present(NONCE_AUTHORITY_ARG.name) {
Some(SigningAuthority::new_from_matches(
&matches,
NONCE_AUTHORITY_ARG.name,
signers.as_deref(),
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::DeactivateStake { command: CliCommand::DeactivateStake {
@ -558,7 +428,7 @@ pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliComma
stake_authority, stake_authority,
sign_only, sign_only,
signers, signers,
blockhash, blockhash_query,
nonce_account, nonce_account,
nonce_authority, nonce_authority,
}, },
@ -570,15 +440,8 @@ pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap(); let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap(); let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?; let lamports = required_lamports_from(matches, "amount", "unit")?;
let withdraw_authority = if matches.is_present(WITHDRAW_AUTHORITY_ARG.name) { let withdraw_authority =
Some(SigningAuthority::new_from_matches( SigningAuthority::new_from_matches(&matches, WITHDRAW_AUTHORITY_ARG.name, None)?;
&matches,
WITHDRAW_AUTHORITY_ARG.name,
None,
)?)
} else {
None
};
Ok(CliCommandInfo { Ok(CliCommandInfo {
command: CliCommand::WithdrawStake { command: CliCommand::WithdrawStake {
@ -713,7 +576,7 @@ pub fn process_stake_authorize(
authority: Option<&SigningAuthority>, authority: Option<&SigningAuthority>,
sign_only: bool, sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>, signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<&SigningAuthority>, nonce_authority: Option<&SigningAuthority>,
) -> ProcessResult { ) -> ProcessResult {
@ -723,7 +586,7 @@ pub fn process_stake_authorize(
)?; )?;
let authority = authority.map(|a| a.keypair()).unwrap_or(&config.keypair); let authority = authority.map(|a| a.keypair()).unwrap_or(&config.keypair);
let (recent_blockhash, fee_calculator) = let (recent_blockhash, fee_calculator) =
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?; blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
let ixs = vec![stake_instruction::authorize( let ixs = vec![stake_instruction::authorize(
stake_account_pubkey, // stake account to update stake_account_pubkey, // stake account to update
&authority.pubkey(), // currently authorized &authority.pubkey(), // currently authorized
@ -779,12 +642,12 @@ pub fn process_deactivate_stake_account(
stake_authority: Option<&SigningAuthority>, stake_authority: Option<&SigningAuthority>,
sign_only: bool, sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>, signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<&SigningAuthority>, nonce_authority: Option<&SigningAuthority>,
) -> ProcessResult { ) -> ProcessResult {
let (recent_blockhash, fee_calculator) = let (recent_blockhash, fee_calculator) =
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?; blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
let stake_authority = stake_authority let stake_authority = stake_authority
.map(|a| a.keypair()) .map(|a| a.keypair())
.unwrap_or(&config.keypair); .unwrap_or(&config.keypair);
@ -872,7 +735,7 @@ pub fn process_withdraw_stake(
pub fn print_stake_state(stake_lamports: u64, stake_state: &StakeState, use_lamports_unit: bool) { pub fn print_stake_state(stake_lamports: u64, stake_state: &StakeState, use_lamports_unit: bool) {
fn show_authorized(authorized: &Authorized) { fn show_authorized(authorized: &Authorized) {
println!("authorized staker: {}", authorized.staker); println!("authorized staker: {}", authorized.staker);
println!("authorized withdrawer: {}", authorized.staker); println!("authorized withdrawer: {}", authorized.withdrawer);
} }
fn show_lockup(lockup: &Lockup) { fn show_lockup(lockup: &Lockup) {
println!("lockup epoch: {}", lockup.epoch); println!("lockup epoch: {}", lockup.epoch);
@ -1000,7 +863,7 @@ pub fn process_delegate_stake(
force: bool, force: bool,
sign_only: bool, sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>, signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash: Option<Hash>, blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>, nonce_account: Option<Pubkey>,
nonce_authority: Option<&SigningAuthority>, nonce_authority: Option<&SigningAuthority>,
) -> ProcessResult { ) -> ProcessResult {
@ -1053,7 +916,7 @@ pub fn process_delegate_stake(
} }
let (recent_blockhash, fee_calculator) = let (recent_blockhash, fee_calculator) =
get_blockhash_fee_calculator(rpc_client, sign_only, blockhash)?; blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
let ixs = vec![stake_instruction::delegate_stake( let ixs = vec![stake_instruction::delegate_stake(
stake_account_pubkey, stake_account_pubkey,
@ -1105,7 +968,11 @@ pub fn process_delegate_stake(
mod tests { mod tests {
use super::*; use super::*;
use crate::cli::{app, parse_command}; use crate::cli::{app, parse_command};
use solana_sdk::signature::{read_keypair_file, write_keypair}; use solana_sdk::{
fee_calculator::FeeCalculator,
hash::Hash,
signature::{read_keypair_file, write_keypair},
};
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) { fn make_tmp_file() -> (String, NamedTempFile) {
@ -1143,7 +1010,7 @@ mod tests {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1169,7 +1036,7 @@ mod tests {
authority: Some(read_keypair_file(&authority_keypair_file).unwrap().into()), authority: Some(read_keypair_file(&authority_keypair_file).unwrap().into()),
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1177,11 +1044,15 @@ mod tests {
} }
); );
// Test Authorize Subcommand w/ sign-only // Test Authorize Subcommand w/ sign-only
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let test_authorize = test_commands.clone().get_matches_from(vec![ let test_authorize = test_commands.clone().get_matches_from(vec![
"test", "test",
&subcommand, &subcommand,
&stake_account_string, &stake_account_string,
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--sign-only", "--sign-only",
]); ]);
assert_eq!( assert_eq!(
@ -1194,7 +1065,7 @@ mod tests {
authority: None, authority: None,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1210,6 +1081,8 @@ mod tests {
&subcommand, &subcommand,
&stake_account_string, &stake_account_string,
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer, &signer,
]); ]);
@ -1223,7 +1096,7 @@ mod tests {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: Some(vec![(keypair.pubkey(), sig)]), signers: Some(vec![(keypair.pubkey(), sig)]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1239,6 +1112,8 @@ mod tests {
&subcommand, &subcommand,
&stake_account_string, &stake_account_string,
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer, &signer,
"--signer", "--signer",
@ -1254,7 +1129,7 @@ mod tests {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: Some(vec![(keypair.pubkey(), sig), (keypair2.pubkey(), sig2),]), signers: Some(vec![(keypair.pubkey(), sig), (keypair2.pubkey(), sig2),]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1262,8 +1137,6 @@ mod tests {
} }
); );
// Test Authorize Subcommand w/ blockhash // Test Authorize Subcommand w/ blockhash
let blockhash = Hash::default();
let blockhash_string = format!("{}", blockhash);
let test_authorize = test_commands.clone().get_matches_from(vec![ let test_authorize = test_commands.clone().get_matches_from(vec![
"test", "test",
&subcommand, &subcommand,
@ -1282,7 +1155,7 @@ mod tests {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1317,7 +1190,7 @@ mod tests {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(nonce_account_pubkey), nonce_account: Some(nonce_account_pubkey),
nonce_authority: Some(nonce_authority_keypair.into()), nonce_authority: Some(nonce_authority_keypair.into()),
}, },
@ -1437,7 +1310,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1470,7 +1343,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1496,7 +1369,7 @@ mod tests {
force: true, force: true,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1525,7 +1398,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1538,6 +1411,8 @@ mod tests {
"delegate-stake", "delegate-stake",
&stake_account_string, &stake_account_string,
&vote_account_string, &vote_account_string,
"--blockhash",
&blockhash_string,
"--sign-only", "--sign-only",
]); ]);
assert_eq!( assert_eq!(
@ -1550,7 +1425,7 @@ mod tests {
force: false, force: false,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1567,6 +1442,8 @@ mod tests {
"delegate-stake", "delegate-stake",
&stake_account_string, &stake_account_string,
&vote_account_string, &vote_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
]); ]);
@ -1580,7 +1457,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: Some(vec![(key1, sig1)]), signers: Some(vec![(key1, sig1)]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1597,6 +1474,8 @@ mod tests {
"delegate-stake", "delegate-stake",
&stake_account_string, &stake_account_string,
&vote_account_string, &vote_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
"--signer", "--signer",
@ -1612,7 +1491,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: Some(vec![(key1, sig1), (key2, sig2)]), signers: Some(vec![(key1, sig1), (key2, sig2)]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1686,7 +1565,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1714,7 +1593,7 @@ mod tests {
), ),
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1740,7 +1619,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1752,6 +1631,8 @@ mod tests {
"test", "test",
"deactivate-stake", "deactivate-stake",
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--sign-only", "--sign-only",
]); ]);
assert_eq!( assert_eq!(
@ -1762,7 +1643,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1778,6 +1659,8 @@ mod tests {
"test", "test",
"deactivate-stake", "deactivate-stake",
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
]); ]);
@ -1789,7 +1672,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: Some(vec![(key1, sig1)]), signers: Some(vec![(key1, sig1)]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1805,6 +1688,8 @@ mod tests {
"test", "test",
"deactivate-stake", "deactivate-stake",
&stake_account_string, &stake_account_string,
"--blockhash",
&blockhash_string,
"--signer", "--signer",
&signer1, &signer1,
"--signer", "--signer",
@ -1818,7 +1703,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: Some(vec![(key1, sig1), (key2, sig2)]), signers: Some(vec![(key1, sig1), (key2, sig2)]),
blockhash: None, blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },

View File

@ -1,12 +1,14 @@
use chrono::prelude::*; use chrono::prelude::*;
use serde_json::Value; use serde_json::Value;
use solana_cli::cli::{ use solana_cli::{
process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand, cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
offline::BlockhashQuery,
}; };
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_faucet::faucet::run_local_faucet; use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{ use solana_sdk::{
account_utils::StateMut, account_utils::StateMut,
fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
nonce_state::NonceState, nonce_state::NonceState,
pubkey::Pubkey, pubkey::Pubkey,
@ -289,9 +291,11 @@ fn test_offline_pay_tx() {
check_balance(50, &rpc_client, &config_offline.keypair.pubkey()); check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
check_balance(50, &rpc_client, &config_online.keypair.pubkey()); check_balance(50, &rpc_client, &config_online.keypair.pubkey());
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::Pay(PayCommand { config_offline.command = CliCommand::Pay(PayCommand {
lamports: 10, lamports: 10,
to: bob_pubkey, to: bob_pubkey,
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
sign_only: true, sign_only: true,
..PayCommand::default() ..PayCommand::default()
}); });
@ -318,7 +322,7 @@ fn test_offline_pay_tx() {
lamports: 10, lamports: 10,
to: bob_pubkey, to: bob_pubkey,
signers: Some(signers), signers: Some(signers),
blockhash: Some(blockhash_str.parse::<Hash>().unwrap()), blockhash_query: BlockhashQuery::FeeCalculator(blockhash_str.parse::<Hash>().unwrap()),
..PayCommand::default() ..PayCommand::default()
}); });
process_command(&config_online).unwrap(); process_command(&config_online).unwrap();
@ -389,7 +393,7 @@ fn test_nonced_pay_tx() {
config.command = CliCommand::Pay(PayCommand { config.command = CliCommand::Pay(PayCommand {
lamports: 10, lamports: 10,
to: bob_pubkey, to: bob_pubkey,
blockhash: Some(nonce_hash), blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
nonce_account: Some(nonce_account.pubkey()), nonce_account: Some(nonce_account.pubkey()),
..PayCommand::default() ..PayCommand::default()
}); });

View File

@ -1,9 +1,13 @@
use serde_json::Value; use serde_json::Value;
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}; use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
offline::BlockhashQuery,
};
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_faucet::faucet::run_local_faucet; use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{ use solana_sdk::{
account_utils::StateMut, account_utils::StateMut,
fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
nonce_state::NonceState, nonce_state::NonceState,
pubkey::Pubkey, pubkey::Pubkey,
@ -132,7 +136,7 @@ fn test_seed_stake_delegation_and_deactivation() {
force: true, force: true,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -144,7 +148,7 @@ fn test_seed_stake_delegation_and_deactivation() {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -220,7 +224,7 @@ fn test_stake_delegation_and_deactivation() {
force: true, force: true,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -232,7 +236,7 @@ fn test_stake_delegation_and_deactivation() {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -305,6 +309,7 @@ fn test_offline_stake_delegation_and_deactivation() {
process_command(&config_validator).unwrap(); process_command(&config_validator).unwrap();
// Delegate stake offline // Delegate stake offline
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_validator.command = CliCommand::DelegateStake { config_validator.command = CliCommand::DelegateStake {
stake_account_pubkey: config_stake.keypair.pubkey(), stake_account_pubkey: config_stake.keypair.pubkey(),
vote_account_pubkey: config_vote.keypair.pubkey(), vote_account_pubkey: config_vote.keypair.pubkey(),
@ -312,7 +317,7 @@ fn test_offline_stake_delegation_and_deactivation() {
force: true, force: true,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -327,19 +332,20 @@ fn test_offline_stake_delegation_and_deactivation() {
force: true, force: true,
sign_only: false, sign_only: false,
signers: Some(signers), signers: Some(signers),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
process_command(&config_payer).unwrap(); process_command(&config_payer).unwrap();
// Deactivate stake offline // Deactivate stake offline
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_validator.command = CliCommand::DeactivateStake { config_validator.command = CliCommand::DeactivateStake {
stake_account_pubkey: config_stake.keypair.pubkey(), stake_account_pubkey: config_stake.keypair.pubkey(),
stake_authority: None, stake_authority: None,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -352,7 +358,7 @@ fn test_offline_stake_delegation_and_deactivation() {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: Some(signers), signers: Some(signers),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -439,7 +445,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
force: true, force: true,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(nonce_hash), blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
nonce_account: Some(nonce_account.pubkey()), nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None, nonce_authority: None,
}; };
@ -460,7 +466,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
stake_authority: None, stake_authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: Some(nonce_hash), blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
nonce_account: Some(nonce_account.pubkey()), nonce_account: Some(nonce_account.pubkey()),
nonce_authority: Some(config_keypair.into()), nonce_authority: Some(config_keypair.into()),
}; };
@ -514,7 +520,7 @@ fn test_stake_authorize() {
authority: None, authority: None,
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -539,7 +545,7 @@ fn test_stake_authorize() {
authority: Some(read_keypair_file(&online_authority_file).unwrap().into()), authority: Some(read_keypair_file(&online_authority_file).unwrap().into()),
sign_only: false, sign_only: false,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::default(),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -557,6 +563,7 @@ fn test_stake_authorize() {
let nonced_authority_pubkey = nonced_authority.pubkey(); let nonced_authority_pubkey = nonced_authority.pubkey();
let (nonced_authority_file, mut tmp_file) = make_tmp_file(); let (nonced_authority_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonced_authority, tmp_file.as_file_mut()).unwrap(); write_keypair(&nonced_authority, tmp_file.as_file_mut()).unwrap();
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config.command = CliCommand::StakeAuthorize { config.command = CliCommand::StakeAuthorize {
stake_account_pubkey, stake_account_pubkey,
new_authorized_pubkey: nonced_authority_pubkey, new_authorized_pubkey: nonced_authority_pubkey,
@ -564,7 +571,7 @@ fn test_stake_authorize() {
authority: Some(read_keypair_file(&offline_authority_file).unwrap().into()), authority: Some(read_keypair_file(&offline_authority_file).unwrap().into()),
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: None, blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -577,7 +584,7 @@ fn test_stake_authorize() {
authority: Some(offline_authority_pubkey.into()), authority: Some(offline_authority_pubkey.into()),
sign_only: false, sign_only: false,
signers: Some(signers), signers: Some(signers),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}; };
@ -625,7 +632,7 @@ fn test_stake_authorize() {
authority: Some(read_keypair_file(&nonced_authority_file).unwrap().into()), authority: Some(read_keypair_file(&nonced_authority_file).unwrap().into()),
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: Some(nonce_hash), blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
nonce_account: Some(nonce_account.pubkey()), nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None, nonce_authority: None,
}; };
@ -639,7 +646,7 @@ fn test_stake_authorize() {
authority: Some(nonced_authority_pubkey.into()), authority: Some(nonced_authority_pubkey.into()),
sign_only: false, sign_only: false,
signers: Some(signers), signers: Some(signers),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(nonce_account.pubkey()), nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None, nonce_authority: None,
}; };

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-client" name = "solana-client"
version = "0.23.0" version = "0.23.1"
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,11 +19,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_json = "1.0.44" serde_json = "1.0.44"
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
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.5" jsonrpc-http-server = "14.0.5"
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }

View File

@ -177,7 +177,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetVoteAccounts parse failure: {}", err), format!("GetVoteAccounts parse failure: {:?}", err),
) )
}) })
} }
@ -196,7 +196,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetClusterNodes parse failure: {}", err), format!("GetClusterNodes parse failure: {:?}", err),
) )
}) })
} }
@ -215,7 +215,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetConfirmedBlock parse failure: {}", err), format!("GetConfirmedBlock parse failure: {:?}", err),
) )
}) })
} }
@ -242,7 +242,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetConfirmedBlocks parse failure: {}", err), format!("GetConfirmedBlocks parse failure: {:?}", err),
) )
}) })
} }
@ -293,7 +293,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetEpochInfo parse failure: {}", err), format!("GetEpochInfo parse failure: {:?}", err),
) )
}) })
} }
@ -324,7 +324,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetLeaderSchedule failure: {}", err), format!("GetLeaderSchedule failure: {:?}", err),
) )
}) })
} }
@ -343,7 +343,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetEpochSchedule parse failure: {}", err), format!("GetEpochSchedule parse failure: {:?}", err),
) )
}) })
} }
@ -381,7 +381,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetVersion parse failure: {}", err), format!("GetVersion parse failure: {:?}", err),
) )
}) })
} }
@ -400,7 +400,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("MinimumLedgerSlot parse failure: {}", err), format!("MinimumLedgerSlot parse failure: {:?}", err),
) )
}) })
} }
@ -612,7 +612,7 @@ impl RpcClient {
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}: {}", pubkey, err), format!("AccountNotFound: pubkey={}: {:?}", pubkey, err),
) )
})? })?
} }
@ -698,7 +698,7 @@ impl RpcClient {
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("AccountNotFound: pubkey={}: {}", pubkey, err), format!("AccountNotFound: pubkey={}: {:?}", pubkey, err),
) )
})?; })?;
@ -749,7 +749,7 @@ impl RpcClient {
serde_json::from_value(response).map_err(|err| { serde_json::from_value(response).map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("GetTransactionCount parse failure: {}", err), format!("GetTransactionCount parse failure: {:?}", err),
) )
}) })
} }

View File

@ -15,10 +15,7 @@ pub struct RpcClientRequest {
impl RpcClientRequest { impl RpcClientRequest {
pub fn new(url: String) -> Self { pub fn new(url: String) -> Self {
Self { Self::new_with_timeout(url, Duration::from_secs(20))
client: reqwest::blocking::Client::new(),
url,
}
} }
pub fn new_with_timeout(url: String, timeout: Duration) -> Self { pub fn new_with_timeout(url: String, timeout: Duration) -> Self {

View File

@ -1,7 +1,7 @@
[package] [package]
name = "solana-core" name = "solana-core"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
documentation = "https://docs.rs/solana" documentation = "https://docs.rs/solana"
homepage = "https://solana.com/" homepage = "https://solana.com/"
readme = "../README.md" readme = "../README.md"
@ -40,26 +40,26 @@ rayon = "1.2.0"
serde = "1.0.104" serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.1" }
ed25519-dalek = "=1.0.0-pre.1" ed25519-dalek = "=1.0.0-pre.1"
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" } solana-merkle-tree = { path = "../merkle-tree", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.0" } solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.1" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" } solana-vote-signer = { path = "../vote-signer", version = "0.23.1" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.0" } solana-sys-tuner = { path = "../sys-tuner", version = "0.23.1" }
symlink = "0.1.0" symlink = "0.1.0"
sys-info = "0.5.8" sys-info = "0.5.8"
tempfile = "3.1.0" tempfile = "3.1.0"
@ -69,7 +69,7 @@ tokio-codec = "0.1"
tokio-fs = "0.1" tokio-fs = "0.1"
tokio-io = "0.1" tokio-io = "0.1"
untrusted = "0.7.0" untrusted = "0.7.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.1" }
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] } reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
[dev-dependencies] [dev-dependencies]

View File

@ -58,31 +58,35 @@ impl BlockstreamService {
let timeout = Duration::new(1, 0); let timeout = Duration::new(1, 0);
let (slot, slot_leader) = slot_full_receiver.recv_timeout(timeout)?; let (slot, slot_leader) = slot_full_receiver.recv_timeout(timeout)?;
let entries = blockstore.get_slot_entries(slot, 0, None).unwrap(); // Slot might not exist due to LedgerCleanupService, check first
let blockstore_meta = blockstore.meta(slot).unwrap().unwrap(); let blockstore_meta = blockstore.meta(slot).unwrap();
let _parent_slot = if slot == 0 { if let Some(blockstore_meta) = blockstore_meta {
None // Return error to main loop. Thread won't exit, will just log the error
} else { let entries = blockstore.get_slot_entries(slot, 0, None)?;
Some(blockstore_meta.parent_slot) let _parent_slot = if slot == 0 {
}; None
let ticks_per_slot = entries.iter().filter(|entry| entry.is_tick()).count() as u64; } else {
let mut tick_height = ticks_per_slot * slot; Some(blockstore_meta.parent_slot)
};
let ticks_per_slot = entries.iter().filter(|entry| entry.is_tick()).count() as u64;
let mut tick_height = ticks_per_slot * slot;
for (i, entry) in entries.iter().enumerate() { for (i, entry) in entries.iter().enumerate() {
if entry.is_tick() { if entry.is_tick() {
tick_height += 1; tick_height += 1;
} }
blockstream
.emit_entry_event(slot, tick_height, &slot_leader, &entry)
.unwrap_or_else(|e| {
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
});
if i == entries.len() - 1 {
blockstream blockstream
.emit_block_event(slot, tick_height, &slot_leader, entry.hash) .emit_entry_event(slot, tick_height, &slot_leader, &entry)
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output); debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
}); });
if i == entries.len() - 1 {
blockstream
.emit_block_event(slot, tick_height, &slot_leader, entry.hash)
.unwrap_or_else(|e| {
debug!("Blockstream error: {:?}, {:?}", e, blockstream.output);
});
}
} }
} }
Ok(()) Ok(())

View File

@ -272,7 +272,7 @@ impl ClusterInfo {
let ip_addr = node.gossip.ip(); let ip_addr = node.gossip.ip();
format!( format!(
"{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5} | {:5}| {:5} | {:5}| {:5} | {:5}| {:5}| v{}\n", "{:15} {:2}| {:5} | {:44} | {:5}| {:5}| {:5} | {:5}| {:5} | {:5}| {:5} | {:5}| {:5}| {}\n",
if ContactInfo::is_valid_address(&node.gossip) { if ContactInfo::is_valid_address(&node.gossip) {
ip_addr.to_string() ip_addr.to_string()
} else { } else {
@ -405,7 +405,8 @@ impl ClusterInfo {
.map(|x| x.value.contact_info().unwrap()) .map(|x| x.value.contact_info().unwrap())
} }
pub fn rpc_peers(&self) -> Vec<ContactInfo> { /// all validators that have a valid rpc port regardless of `shred_version`.
pub fn all_rpc_peers(&self) -> Vec<ContactInfo> {
let me = self.my_data(); let me = self.my_data();
self.gossip self.gossip
.crds .crds
@ -440,13 +441,15 @@ impl ClusterInfo {
.values() .values()
.filter_map(|x| x.value.contact_info()) .filter_map(|x| x.value.contact_info())
.filter(|x| x.id != me) .filter(|x| x.id != me)
/* shred_version not considered for gossip peers (ie, spy nodes do not set
shred_version) */
.filter(|x| ContactInfo::is_valid_address(&x.gossip)) .filter(|x| ContactInfo::is_valid_address(&x.gossip))
.cloned() .cloned()
.collect() .collect()
} }
/// all validators that have a valid tvu port. /// all validators that have a valid tvu port regardless of `shred_version`.
pub fn tvu_peers(&self) -> Vec<ContactInfo> { pub fn all_tvu_peers(&self) -> Vec<ContactInfo> {
let me = self.my_data(); let me = self.my_data();
self.gossip self.gossip
.crds .crds
@ -460,7 +463,37 @@ impl ClusterInfo {
.collect() .collect()
} }
/// all peers that have a valid storage addr /// all validators that have a valid tvu port and are on the same `shred_version`.
pub fn tvu_peers(&self) -> Vec<ContactInfo> {
let me = self.my_data();
self.gossip
.crds
.table
.values()
.filter_map(|x| x.value.contact_info())
.filter(|x| ContactInfo::is_valid_address(&x.tvu))
.filter(|x| !ClusterInfo::is_archiver(x))
.filter(|x| x.id != me.id)
.filter(|x| x.shred_version == me.shred_version)
.cloned()
.collect()
}
/// all peers that have a valid storage addr regardless of `shred_version`.
pub fn all_storage_peers(&self) -> Vec<ContactInfo> {
let me = self.my_data();
self.gossip
.crds
.table
.values()
.filter_map(|x| x.value.contact_info())
.filter(|x| ContactInfo::is_valid_address(&x.storage_addr))
.filter(|x| x.id != me.id)
.cloned()
.collect()
}
/// all peers that have a valid storage addr and are on the same `shred_version`.
pub fn storage_peers(&self) -> Vec<ContactInfo> { pub fn storage_peers(&self) -> Vec<ContactInfo> {
let me = self.my_data(); let me = self.my_data();
self.gossip self.gossip
@ -470,6 +503,7 @@ impl ClusterInfo {
.filter_map(|x| x.value.contact_info()) .filter_map(|x| x.value.contact_info())
.filter(|x| ContactInfo::is_valid_address(&x.storage_addr)) .filter(|x| ContactInfo::is_valid_address(&x.storage_addr))
.filter(|x| x.id != me.id) .filter(|x| x.id != me.id)
.filter(|x| x.shred_version == me.shred_version)
.cloned() .cloned()
.collect() .collect()
} }
@ -483,6 +517,7 @@ impl ClusterInfo {
.values() .values()
.filter_map(|x| x.value.contact_info()) .filter_map(|x| x.value.contact_info())
.filter(|x| x.id != me.id) .filter(|x| x.id != me.id)
.filter(|x| x.shred_version == me.shred_version)
.filter(|x| ContactInfo::is_valid_address(&x.tvu)) .filter(|x| ContactInfo::is_valid_address(&x.tvu))
.filter(|x| ContactInfo::is_valid_address(&x.tvu_forwards)) .filter(|x| ContactInfo::is_valid_address(&x.tvu_forwards))
.cloned() .cloned()
@ -495,6 +530,7 @@ impl ClusterInfo {
ClusterInfo::tvu_peers(self) ClusterInfo::tvu_peers(self)
.into_iter() .into_iter()
.filter(|x| x.id != me.id) .filter(|x| x.id != me.id)
.filter(|x| x.shred_version == me.shred_version)
.filter(|x| ContactInfo::is_valid_address(&x.gossip)) .filter(|x| ContactInfo::is_valid_address(&x.gossip))
.filter(|x| { .filter(|x| {
self.get_epoch_state_for_node(&x.id, None) self.get_epoch_state_for_node(&x.id, None)
@ -1057,6 +1093,7 @@ impl ClusterInfo {
.spawn(move || { .spawn(move || {
let mut last_push = timestamp(); let mut last_push = timestamp();
let mut last_contact_info_trace = timestamp(); let mut last_contact_info_trace = timestamp();
let mut adopt_shred_version = obj.read().unwrap().my_data().shred_version == 0;
let recycler = PacketsRecycler::default(); let recycler = PacketsRecycler::default();
loop { loop {
let start = timestamp(); let start = timestamp();
@ -1094,9 +1131,32 @@ impl ClusterInfo {
let table_size = obj.read().unwrap().gossip.crds.table.len(); let table_size = obj.read().unwrap().gossip.crds.table.len();
datapoint_debug!( datapoint_debug!(
"cluster_info-purge", "cluster_info-purge",
("tabel_size", table_size as i64, i64), ("table_size", table_size as i64, i64),
("purge_stake_timeout", timeout as i64, i64) ("purge_stake_timeout", timeout as i64, i64)
); );
// Adopt the entrypoint's `shred_version` if ours is unset
if adopt_shred_version {
// If gossip was given an entrypoint, lookup its id
let entrypoint_id = obj.read().unwrap().entrypoint.as_ref().map(|e| e.id);
if let Some(entrypoint_id) = entrypoint_id {
// If a pull from the entrypoint was successful, it should exist in the crds table
let entrypoint = obj.read().unwrap().lookup(&entrypoint_id).cloned();
if let Some(entrypoint) = entrypoint {
let mut self_info = obj.read().unwrap().my_data();
if entrypoint.shred_version == 0 {
info!("Unable to adopt entrypoint's shred version");
} else {
info!(
"Setting shred version to {:?} from entrypoint {:?}",
entrypoint.shred_version, entrypoint.id
);
self_info.shred_version = entrypoint.shred_version;
obj.write().unwrap().insert_self(self_info);
adopt_shred_version = false;
}
}
}
}
//TODO: possibly tune this parameter //TODO: possibly tune this parameter
//we saw a deadlock passing an obj.read().unwrap().timeout into sleep //we saw a deadlock passing an obj.read().unwrap().timeout into sleep
if start - last_push > CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 2 { if start - last_push > CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS / 2 {
@ -2663,6 +2723,14 @@ mod tests {
cluster_info.insert_info(contact_info); cluster_info.insert_info(contact_info);
stakes.insert(id3, 10); stakes.insert(id3, 10);
// normal but with different shred version
let id4 = Pubkey::new(&[4u8; 32]);
let mut contact_info = ContactInfo::new_localhost(&id4, timestamp());
contact_info.shred_version = 1;
assert_ne!(contact_info.shred_version, d.shred_version);
cluster_info.insert_info(contact_info.clone());
stakes.insert(id4, 10);
let stakes = Arc::new(stakes); let stakes = Arc::new(stakes);
let (peers, peers_and_stakes) = cluster_info.sorted_tvu_peers_and_stakes(Some(stakes)); let (peers, peers_and_stakes) = cluster_info.sorted_tvu_peers_and_stakes(Some(stakes));
assert_eq!(peers.len(), 2); assert_eq!(peers.len(), 2);

View File

@ -135,7 +135,7 @@ impl ClusterInfoRepairListener {
} }
let lowest_slot = blockstore.lowest_slot(); let lowest_slot = blockstore.lowest_slot();
let peers = cluster_info.read().unwrap().gossip_peers(); let peers = cluster_info.read().unwrap().tvu_peers();
let mut peers_needing_repairs: HashMap<Pubkey, EpochSlots> = HashMap::new(); let mut peers_needing_repairs: HashMap<Pubkey, EpochSlots> = HashMap::new();
// Iterate through all the known nodes in the network, looking for ones that // Iterate through all the known nodes in the network, looking for ones that

View File

@ -321,13 +321,27 @@ impl Tower {
if let Some(fork_stake) = stake_lockouts.get(&vote.slot) { if let Some(fork_stake) = stake_lockouts.get(&vote.slot) {
let lockout = fork_stake.stake as f64 / total_staked as f64; let lockout = fork_stake.stake as f64 / total_staked as f64;
trace!( trace!(
"fork_stake {} {} {} {}", "fork_stake slot: {} lockout: {} fork_stake: {} total_stake: {}",
slot, slot,
lockout, lockout,
fork_stake.stake, fork_stake.stake,
total_staked total_staked
); );
lockout > self.threshold_size for (new_lockout, original_lockout) in
lockouts.votes.iter().zip(self.lockouts.votes.iter())
{
if new_lockout.slot == original_lockout.slot {
if new_lockout.confirmation_count <= self.threshold_depth as u32 {
break;
}
if new_lockout.confirmation_count != original_lockout.confirmation_count {
return lockout > self.threshold_size;
}
} else {
break;
}
}
true
} else { } else {
false false
} }
@ -742,6 +756,34 @@ mod test {
assert!(!tower.check_vote_stake_threshold(1, &stakes, 2)); assert!(!tower.check_vote_stake_threshold(1, &stakes, 2));
} }
#[test]
fn test_check_vote_threshold_lockouts_not_updated() {
solana_logger::setup();
let mut tower = Tower::new_for_tests(1, 0.67);
let stakes = vec![
(
0,
StakeLockout {
stake: 1,
lockout: 8,
},
),
(
1,
StakeLockout {
stake: 2,
lockout: 8,
},
),
]
.into_iter()
.collect();
tower.record_vote(0, Hash::default());
tower.record_vote(1, Hash::default());
tower.record_vote(2, Hash::default());
assert!(tower.check_vote_stake_threshold(6, &stakes, 2));
}
#[test] #[test]
fn test_lockout_is_updated_for_entire_branch() { fn test_lockout_is_updated_for_entire_branch() {
let mut stake_lockouts = HashMap::new(); let mut stake_lockouts = HashMap::new();

View File

@ -299,8 +299,8 @@ mod tests {
assert_eq!(ci.gossip.port(), 11); assert_eq!(ci.gossip.port(), 11);
assert_eq!(ci.tvu.port(), 12); assert_eq!(ci.tvu.port(), 12);
assert_eq!(ci.tpu_forwards.port(), 13); assert_eq!(ci.tpu_forwards.port(), 13);
assert_eq!(ci.rpc.port(), 8899); assert_eq!(ci.rpc.port(), rpc_port::DEFAULT_RPC_PORT);
assert_eq!(ci.rpc_pubsub.port(), 8900); assert_eq!(ci.rpc_pubsub.port(), rpc_port::DEFAULT_RPC_PUBSUB_PORT);
assert!(ci.storage_addr.ip().is_unspecified()); assert!(ci.storage_addr.ip().is_unspecified());
} }
#[test] #[test]
@ -315,8 +315,14 @@ mod tests {
assert_eq!(d1.tvu, socketaddr!("127.0.0.1:1236")); assert_eq!(d1.tvu, socketaddr!("127.0.0.1:1236"));
assert_eq!(d1.tpu_forwards, socketaddr!("127.0.0.1:1237")); assert_eq!(d1.tpu_forwards, socketaddr!("127.0.0.1:1237"));
assert_eq!(d1.tpu, socketaddr!("127.0.0.1:1234")); assert_eq!(d1.tpu, socketaddr!("127.0.0.1:1234"));
assert_eq!(d1.rpc, socketaddr!("127.0.0.1:8899")); assert_eq!(
assert_eq!(d1.rpc_pubsub, socketaddr!("127.0.0.1:8900")); d1.rpc,
socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PORT))
);
assert_eq!(
d1.rpc_pubsub,
socketaddr!(format!("127.0.0.1:{}", rpc_port::DEFAULT_RPC_PUBSUB_PORT))
);
} }
#[test] #[test]

View File

@ -197,10 +197,10 @@ fn spy(
tvu_peers = spy_ref tvu_peers = spy_ref
.read() .read()
.unwrap() .unwrap()
.tvu_peers() .all_tvu_peers()
.into_iter() .into_iter()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
archivers = spy_ref.read().unwrap().storage_peers(); archivers = spy_ref.read().unwrap().all_storage_peers();
if let Some(num) = num_nodes { if let Some(num) = num_nodes {
if tvu_peers.len() + archivers.len() >= num { if tvu_peers.len() + archivers.len() >= num {
if let Some(gossip_addr) = find_node_by_gossip_addr { if let Some(gossip_addr) = find_node_by_gossip_addr {

View File

@ -68,9 +68,13 @@ impl LedgerCleanupService {
let disk_utilization_pre = blockstore.storage_size(); let disk_utilization_pre = blockstore.storage_size();
let root = new_root_receiver.recv_timeout(Duration::from_secs(1))?; let root = new_root_receiver.recv_timeout(Duration::from_secs(1))?;
// Notify blockstore of impending purge
if root > *next_purge_batch { if root > *next_purge_batch {
//cleanup //cleanup
blockstore.purge_slots(0, Some(root - max_ledger_slots)); let lowest_slot = root - max_ledger_slots;
*blockstore.lowest_cleanup_slot.write().unwrap() = lowest_slot;
blockstore.purge_slots(0, Some(lowest_slot));
*next_purge_batch += DEFAULT_PURGE_BATCH_SIZE; *next_purge_batch += DEFAULT_PURGE_BATCH_SIZE;
} }

View File

@ -30,7 +30,6 @@ pub mod gossip_service;
pub mod ledger_cleanup_service; pub mod ledger_cleanup_service;
pub mod local_vote_signer_service; pub mod local_vote_signer_service;
pub mod packet; pub mod packet;
pub mod partition_cfg;
pub mod poh_recorder; pub mod poh_recorder;
pub mod poh_service; pub mod poh_service;
pub mod recvmmsg; pub mod recvmmsg;

View File

@ -1,92 +0,0 @@
use solana_ledger::leader_schedule_cache::LeaderScheduleCache;
use solana_ledger::shred::Shred;
use solana_runtime::bank::Bank;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing::timestamp;
use std::collections::HashSet;
use std::sync::Arc;
use std::sync::RwLock;
///Configure a partition in the retransmit stage
#[derive(Debug, Clone)]
pub struct Partition {
pub num_partitions: usize,
pub my_partition: usize,
pub start_ts: u64,
pub end_ts: u64,
leaders: Arc<RwLock<Vec<Pubkey>>>,
}
impl Default for Partition {
fn default() -> Self {
Self {
num_partitions: 0,
my_partition: 0,
start_ts: 0,
end_ts: 0,
leaders: Arc::new(RwLock::new(vec![])),
}
}
}
#[derive(Default, Debug, Clone)]
pub struct PartitionCfg {
partitions: Vec<Partition>,
}
impl PartitionCfg {
pub fn new(partitions: Vec<Partition>) -> Self {
Self { partitions }
}
pub fn is_connected(
&self,
bank: &Option<Arc<Bank>>,
leader_schedule_cache: &Arc<LeaderScheduleCache>,
shred: &Shred,
) -> bool {
if bank.is_none() {
return true;
}
let bank = bank.as_ref().unwrap().clone();
let slot_leader_pubkey = leader_schedule_cache.slot_leader_at(shred.slot(), Some(&bank));
let slot_leader_pubkey = slot_leader_pubkey.unwrap_or_default();
let time = timestamp();
for p in &self.partitions {
let is_time = (p.start_ts <= time) && (time < p.end_ts);
if !is_time {
continue;
}
trace!("PARTITION_TEST partition time! {}", p.my_partition);
if p.num_partitions == 0 {
continue;
}
if p.leaders.read().unwrap().is_empty() {
let mut leader_vec = p.leaders.write().unwrap();
let mut leaders: Vec<Pubkey> = bank.vote_accounts().keys().cloned().collect();
leaders.sort();
*leader_vec = leaders;
warn!("PARTITION_TEST partition enabled {}", p.my_partition);
}
let is_connected: bool = {
let leaders = p.leaders.read().unwrap();
let start = p.my_partition * leaders.len() / p.num_partitions;
let partition_size = leaders.len() / p.num_partitions;
let end = start + partition_size;
let end = if leaders.len() - end < partition_size {
leaders.len()
} else {
end
};
let my_leaders: HashSet<_> = leaders[start..end].iter().collect();
my_leaders.contains(&slot_leader_pubkey)
};
if is_connected {
trace!("PARTITION_TEST connected {}", p.my_partition);
continue;
}
trace!("PARTITION_TEST not connected {}", p.my_partition);
return false;
}
trace!("PARTITION_TEST connected");
true
}
}

View File

@ -527,6 +527,9 @@ impl ReplayStage {
let tx_count = tx_count_after - tx_count_before; let tx_count = tx_count_after - tx_count_before;
confirm_result.map_err(|err| { confirm_result.map_err(|err| {
// LedgerCleanupService should not be cleaning up anything
// that comes after the root, so we should not see any
// errors related to the slot being purged
let slot = bank.slot(); let slot = bank.slot();
warn!("Fatal replay error in slot: {}, err: {:?}", slot, err); warn!("Fatal replay error in slot: {}, err: {:?}", slot, err);
datapoint_error!( datapoint_error!(

View File

@ -3,7 +3,6 @@
use crate::{ use crate::{
cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT}, cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT},
packet::Packets, packet::Packets,
partition_cfg::PartitionCfg,
repair_service::RepairStrategy, repair_service::RepairStrategy,
result::{Error, Result}, result::{Error, Result},
streamer::PacketReceiver, streamer::PacketReceiver,
@ -22,7 +21,7 @@ use solana_sdk::epoch_schedule::EpochSchedule;
use std::{ use std::{
cmp, cmp,
net::UdpSocket, net::UdpSocket,
sync::atomic::AtomicBool, sync::atomic::{AtomicBool, Ordering},
sync::mpsc::channel, sync::mpsc::channel,
sync::mpsc::RecvTimeoutError, sync::mpsc::RecvTimeoutError,
sync::Mutex, sync::Mutex,
@ -213,7 +212,7 @@ impl RetransmitStage {
exit: &Arc<AtomicBool>, exit: &Arc<AtomicBool>,
completed_slots_receiver: CompletedSlotsReceiver, completed_slots_receiver: CompletedSlotsReceiver,
epoch_schedule: EpochSchedule, epoch_schedule: EpochSchedule,
cfg: Option<PartitionCfg>, cfg: Option<Arc<AtomicBool>>,
shred_version: u16, shred_version: u16,
) -> Self { ) -> Self {
let (retransmit_sender, retransmit_receiver) = channel(); let (retransmit_sender, retransmit_receiver) = channel();
@ -245,7 +244,7 @@ impl RetransmitStage {
move |id, shred, working_bank, last_root| { move |id, shred, working_bank, last_root| {
let is_connected = cfg let is_connected = cfg
.as_ref() .as_ref()
.map(|x| x.is_connected(&working_bank, &leader_schedule_cache, shred)) .map(|x| x.load(Ordering::Relaxed))
.unwrap_or(true); .unwrap_or(true);
let rv = should_retransmit_and_persist( let rv = should_retransmit_and_persist(
shred, shred,

View File

@ -45,21 +45,12 @@ fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
Ok(Response { context, value }) Ok(Response { context, value })
} }
#[derive(Debug, Clone)] #[derive(Debug, Default, Clone)]
pub struct JsonRpcConfig { pub struct JsonRpcConfig {
pub enable_validator_exit: bool, // Enable the 'validatorExit' command pub enable_validator_exit: bool, // Enable the 'validatorExit' command
pub faucet_addr: Option<SocketAddr>, pub faucet_addr: Option<SocketAddr>,
} }
impl Default for JsonRpcConfig {
fn default() -> Self {
Self {
enable_validator_exit: false,
faucet_addr: None,
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct JsonRpcRequestProcessor { pub struct JsonRpcRequestProcessor {
bank_forks: Arc<RwLock<BankForks>>, bank_forks: Arc<RwLock<BankForks>>,
@ -383,7 +374,11 @@ impl JsonRpcRequestProcessor {
let stakes = HashMap::new(); let stakes = HashMap::new();
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes); let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);
Ok(self.blockstore.get_block_time(slot, slot_duration, stakes)) Ok(self
.blockstore
.get_block_time(slot, slot_duration, stakes)
.ok()
.unwrap_or(None))
} }
} }
@ -724,11 +719,14 @@ impl RpcSol for RpcSolImpl {
None None
} }
} }
let shred_version = cluster_info.my_data().shred_version;
Ok(cluster_info Ok(cluster_info
.all_peers() .all_peers()
.iter() .iter()
.filter_map(|(contact_info, _)| { .filter_map(|(contact_info, _)| {
if ContactInfo::is_valid_address(&contact_info.gossip) { if shred_version == contact_info.shred_version
&& ContactInfo::is_valid_address(&contact_info.gossip)
{
Some(RpcContactInfo { Some(RpcContactInfo {
pubkey: contact_info.id.to_string(), pubkey: contact_info.id.to_string(),
gossip: Some(contact_info.gossip), gossip: Some(contact_info.gossip),
@ -1117,6 +1115,7 @@ pub mod tests {
fee_calculator::DEFAULT_BURN_PERCENT, fee_calculator::DEFAULT_BURN_PERCENT,
hash::{hash, Hash}, hash::{hash, Hash},
instruction::InstructionError, instruction::InstructionError,
rpc_port,
signature::{Keypair, KeypairUtil}, signature::{Keypair, KeypairUtil},
system_transaction, system_transaction,
transaction::TransactionError, transaction::TransactionError,
@ -1355,8 +1354,9 @@ pub mod tests {
.expect("actual response deserialization"); .expect("actual response deserialization");
let expected = format!( let expected = format!(
r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:8899"}}],"id":1}}"#, r#"{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:{}"}}],"id":1}}"#,
leader_pubkey, leader_pubkey,
rpc_port::DEFAULT_RPC_PORT
); );
let expected: Response = let expected: Response =

View File

@ -131,6 +131,7 @@ impl JsonRpcService {
.cors(DomainsValidation::AllowOnly(vec![ .cors(DomainsValidation::AllowOnly(vec![
AccessControlAllowOrigin::Any, AccessControlAllowOrigin::Any,
])) ]))
.cors_max_age(86400)
.request_middleware(RpcRequestMiddleware::new(ledger_path)) .request_middleware(RpcRequestMiddleware::new(ledger_path))
.start_http(&rpc_addr); .start_http(&rpc_addr);
if let Err(e) = server { if let Err(e) = server {

View File

@ -6,7 +6,6 @@ use crate::{
cluster_info::ClusterInfo, cluster_info::ClusterInfo,
commitment::BlockCommitmentCache, commitment::BlockCommitmentCache,
ledger_cleanup_service::LedgerCleanupService, ledger_cleanup_service::LedgerCleanupService,
partition_cfg::PartitionCfg,
poh_recorder::PohRecorder, poh_recorder::PohRecorder,
replay_stage::{ReplayStage, ReplayStageConfig}, replay_stage::{ReplayStage, ReplayStageConfig},
retransmit_stage::RetransmitStage, retransmit_stage::RetransmitStage,
@ -84,7 +83,7 @@ impl Tvu {
completed_slots_receiver: CompletedSlotsReceiver, completed_slots_receiver: CompletedSlotsReceiver,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>, block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
sigverify_disabled: bool, sigverify_disabled: bool,
cfg: Option<PartitionCfg>, cfg: Option<Arc<AtomicBool>>,
shred_version: u16, shred_version: u16,
transaction_status_sender: Option<TransactionStatusSender>, transaction_status_sender: Option<TransactionStatusSender>,
) -> Self { ) -> Self {

View File

@ -6,7 +6,6 @@ use crate::{
commitment::BlockCommitmentCache, commitment::BlockCommitmentCache,
contact_info::ContactInfo, contact_info::ContactInfo,
gossip_service::{discover_cluster, GossipService}, gossip_service::{discover_cluster, GossipService},
partition_cfg::PartitionCfg,
poh_recorder::PohRecorder, poh_recorder::PohRecorder,
poh_service::PohService, poh_service::PohService,
rpc::JsonRpcConfig, rpc::JsonRpcConfig,
@ -57,16 +56,18 @@ pub struct ValidatorConfig {
pub dev_sigverify_disabled: bool, pub dev_sigverify_disabled: bool,
pub dev_halt_at_slot: Option<Slot>, pub dev_halt_at_slot: Option<Slot>,
pub expected_genesis_hash: Option<Hash>, pub expected_genesis_hash: Option<Hash>,
pub expected_shred_version: Option<u16>,
pub voting_disabled: bool, pub voting_disabled: bool,
pub transaction_status_service_disabled: bool, pub transaction_status_service_disabled: bool,
pub blockstream_unix_socket: Option<PathBuf>, pub blockstream_unix_socket: Option<PathBuf>,
pub storage_slots_per_turn: u64, pub storage_slots_per_turn: u64,
pub account_paths: Vec<PathBuf>, pub account_paths: Vec<PathBuf>,
pub rpc_config: JsonRpcConfig, pub rpc_config: JsonRpcConfig,
pub rpc_ports: Option<(u16, u16)>, // (API, PubSub)
pub snapshot_config: Option<SnapshotConfig>, pub snapshot_config: Option<SnapshotConfig>,
pub max_ledger_slots: Option<u64>, pub max_ledger_slots: Option<u64>,
pub broadcast_stage_type: BroadcastStageType, pub broadcast_stage_type: BroadcastStageType,
pub partition_cfg: Option<PartitionCfg>, pub enable_partition: Option<Arc<AtomicBool>>,
pub fixed_leader_schedule: Option<FixedSchedule>, pub fixed_leader_schedule: Option<FixedSchedule>,
pub wait_for_supermajority: bool, pub wait_for_supermajority: bool,
pub new_hard_forks: Option<Vec<Slot>>, pub new_hard_forks: Option<Vec<Slot>>,
@ -78,6 +79,7 @@ impl Default for ValidatorConfig {
dev_sigverify_disabled: false, dev_sigverify_disabled: false,
dev_halt_at_slot: None, dev_halt_at_slot: None,
expected_genesis_hash: None, expected_genesis_hash: None,
expected_shred_version: None,
voting_disabled: false, voting_disabled: false,
transaction_status_service_disabled: false, transaction_status_service_disabled: false,
blockstream_unix_socket: None, blockstream_unix_socket: None,
@ -85,9 +87,10 @@ impl Default for ValidatorConfig {
max_ledger_slots: None, max_ledger_slots: None,
account_paths: Vec::new(), account_paths: Vec::new(),
rpc_config: JsonRpcConfig::default(), rpc_config: JsonRpcConfig::default(),
rpc_ports: None,
snapshot_config: None, snapshot_config: None,
broadcast_stage_type: BroadcastStageType::Standard, broadcast_stage_type: BroadcastStageType::Standard,
partition_cfg: None, enable_partition: None,
fixed_leader_schedule: None, fixed_leader_schedule: None,
wait_for_supermajority: false, wait_for_supermajority: false,
new_hard_forks: None, new_hard_forks: None,
@ -115,8 +118,7 @@ impl ValidatorExit {
pub struct Validator { pub struct Validator {
pub id: Pubkey, pub id: Pubkey,
validator_exit: Arc<RwLock<Option<ValidatorExit>>>, validator_exit: Arc<RwLock<Option<ValidatorExit>>>,
rpc_service: Option<JsonRpcService>, rpc_service: Option<(JsonRpcService, PubSubService)>,
rpc_pubsub_service: Option<PubSubService>,
transaction_status_service: Option<TransactionStatusService>, transaction_status_service: Option<TransactionStatusService>,
gossip_service: GossipService, gossip_service: GossipService,
poh_recorder: Arc<Mutex<PohRecorder>>, poh_recorder: Arc<Mutex<PohRecorder>>,
@ -172,6 +174,15 @@ impl Validator {
let exit = Arc::new(AtomicBool::new(false)); let exit = Arc::new(AtomicBool::new(false));
let bank_info = &bank_forks_info[0]; let bank_info = &bank_forks_info[0];
let bank = bank_forks[bank_info.bank_slot].clone(); let bank = bank_forks[bank_info.bank_slot].clone();
info!("Starting validator from slot {}", bank.slot());
{
let hard_forks: Vec<_> = bank.hard_forks().read().unwrap().iter().copied().collect();
if !hard_forks.is_empty() {
info!("Hard forks: {:?}", hard_forks);
}
}
let bank_forks = Arc::new(RwLock::new(bank_forks)); let bank_forks = Arc::new(RwLock::new(bank_forks));
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default())); let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
@ -185,6 +196,16 @@ impl Validator {
compute_shred_version(&genesis_hash, &bank.hard_forks().read().unwrap()); compute_shred_version(&genesis_hash, &bank.hard_forks().read().unwrap());
Self::print_node_info(&node); Self::print_node_info(&node);
if let Some(expected_shred_version) = config.expected_shred_version {
if expected_shred_version != node.info.shred_version {
error!(
"shred version mismatch: expected {}",
expected_shred_version
);
process::exit(1);
}
}
let cluster_info = Arc::new(RwLock::new(ClusterInfo::new( let cluster_info = Arc::new(RwLock::new(ClusterInfo::new(
node.info.clone(), node.info.clone(),
keypair.clone(), keypair.clone(),
@ -198,36 +219,36 @@ impl Validator {
let blockstore = Arc::new(blockstore); let blockstore = Arc::new(blockstore);
let rpc_service = if node.info.rpc.port() == 0 {
None
} else {
Some(JsonRpcService::new(
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), node.info.rpc.port()),
config.rpc_config.clone(),
bank_forks.clone(),
block_commitment_cache.clone(),
blockstore.clone(),
cluster_info.clone(),
genesis_hash,
ledger_path,
storage_state.clone(),
validator_exit.clone(),
))
};
let subscriptions = Arc::new(RpcSubscriptions::new(&exit)); let subscriptions = Arc::new(RpcSubscriptions::new(&exit));
let rpc_pubsub_service = if node.info.rpc_pubsub.port() == 0 {
None let rpc_service = config.rpc_ports.map(|(rpc_port, rpc_pubsub_port)| {
} else { if ContactInfo::is_valid_address(&node.info.rpc) {
Some(PubSubService::new( assert!(ContactInfo::is_valid_address(&node.info.rpc_pubsub));
&subscriptions, assert_eq!(rpc_port, node.info.rpc.port());
SocketAddr::new( assert_eq!(rpc_pubsub_port, node.info.rpc_pubsub.port());
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), } else {
node.info.rpc_pubsub.port(), assert!(!ContactInfo::is_valid_address(&node.info.rpc_pubsub));
}
(
JsonRpcService::new(
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rpc_port),
config.rpc_config.clone(),
bank_forks.clone(),
block_commitment_cache.clone(),
blockstore.clone(),
cluster_info.clone(),
genesis_hash,
ledger_path,
storage_state.clone(),
validator_exit.clone(),
), ),
&exit, PubSubService::new(
)) &subscriptions,
}; SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rpc_pubsub_port),
&exit,
),
)
});
let (transaction_status_sender, transaction_status_service) = let (transaction_status_sender, transaction_status_service) =
if rpc_service.is_some() && !config.transaction_status_service_disabled { if rpc_service.is_some() && !config.transaction_status_service_disabled {
@ -296,47 +317,7 @@ impl Validator {
.set_entrypoint(entrypoint_info.clone()); .set_entrypoint(entrypoint_info.clone());
} }
if config.wait_for_supermajority { wait_for_supermajority(config, &bank, &cluster_info);
info!(
"Waiting for more than 75% of activated stake at slot {} to be in gossip...",
bank.slot()
);
loop {
let gossip_stake_percent = get_stake_percent_in_gossip(&bank, &cluster_info);
info!("{}% of activated stake in gossip", gossip_stake_percent,);
if gossip_stake_percent > 75 {
break;
}
sleep(Duration::new(1, 0));
}
}
let sockets = Sockets {
repair: node
.sockets
.repair
.try_clone()
.expect("Failed to clone repair socket"),
retransmit: node
.sockets
.retransmit_sockets
.iter()
.map(|s| s.try_clone().expect("Failed to clone retransmit socket"))
.collect(),
fetch: node
.sockets
.tvu
.iter()
.map(|s| s.try_clone().expect("Failed to clone TVU Sockets"))
.collect(),
forwards: node
.sockets
.tvu_forwards
.iter()
.map(|s| s.try_clone().expect("Failed to clone TVU forwards Sockets"))
.collect(),
};
let voting_keypair = if config.voting_disabled { let voting_keypair = if config.voting_disabled {
None None
@ -357,7 +338,31 @@ impl Validator {
storage_keypair, storage_keypair,
&bank_forks, &bank_forks,
&cluster_info, &cluster_info,
sockets, Sockets {
repair: node
.sockets
.repair
.try_clone()
.expect("Failed to clone repair socket"),
retransmit: node
.sockets
.retransmit_sockets
.iter()
.map(|s| s.try_clone().expect("Failed to clone retransmit socket"))
.collect(),
fetch: node
.sockets
.tvu
.iter()
.map(|s| s.try_clone().expect("Failed to clone TVU Sockets"))
.collect(),
forwards: node
.sockets
.tvu_forwards
.iter()
.map(|s| s.try_clone().expect("Failed to clone TVU forwards Sockets"))
.collect(),
},
blockstore.clone(), blockstore.clone(),
&storage_state, &storage_state,
config.blockstream_unix_socket.as_ref(), config.blockstream_unix_socket.as_ref(),
@ -370,7 +375,7 @@ impl Validator {
completed_slots_receiver, completed_slots_receiver,
block_commitment_cache, block_commitment_cache,
config.dev_sigverify_disabled, config.dev_sigverify_disabled,
config.partition_cfg.clone(), config.enable_partition.clone(),
node.info.shred_version, node.info.shred_version,
transaction_status_sender.clone(), transaction_status_sender.clone(),
); );
@ -399,7 +404,6 @@ impl Validator {
id, id,
gossip_service, gossip_service,
rpc_service, rpc_service,
rpc_pubsub_service,
transaction_status_service, transaction_status_service,
tpu, tpu,
tvu, tvu,
@ -450,10 +454,8 @@ impl Validator {
pub fn join(self) -> Result<()> { pub fn join(self) -> Result<()> {
self.poh_service.join()?; self.poh_service.join()?;
drop(self.poh_recorder); drop(self.poh_recorder);
if let Some(rpc_service) = self.rpc_service { if let Some((rpc_service, rpc_pubsub_service)) = self.rpc_service {
rpc_service.join()?; rpc_service.join()?;
}
if let Some(rpc_pubsub_service) = self.rpc_pubsub_service {
rpc_pubsub_service.join()?; rpc_pubsub_service.join()?;
} }
if let Some(transaction_status_service) = self.transaction_status_service { if let Some(transaction_status_service) = self.transaction_status_service {
@ -475,7 +477,7 @@ fn compute_shred_version(genesis_hash: &Hash, hard_forks: &HardForks) -> u16 {
let mut hash = *genesis_hash; let mut hash = *genesis_hash;
for (slot, count) in hard_forks.iter() { for (slot, count) in hard_forks.iter() {
let mut buf = [0u8; 16]; let mut buf = [0u8; 16];
LittleEndian::write_u64(&mut buf[..7], *slot); LittleEndian::write_u64(&mut buf[..8], *slot);
LittleEndian::write_u64(&mut buf[8..], *count as u64); LittleEndian::write_u64(&mut buf[8..], *count as u64);
hash = extend_and_hash(&hash, &buf); hash = extend_and_hash(&hash, &buf);
} }
@ -554,6 +556,30 @@ fn new_banks_from_blockstore(
) )
} }
fn wait_for_supermajority(
config: &ValidatorConfig,
bank: &Arc<Bank>,
cluster_info: &Arc<RwLock<ClusterInfo>>,
) {
if !config.wait_for_supermajority {
return;
}
info!(
"Waiting for more than 75% of activated stake at slot {} to be in gossip...",
bank.slot()
);
loop {
let gossip_stake_percent = get_stake_percent_in_gossip(&bank, &cluster_info);
info!("{}% of activated stake in gossip", gossip_stake_percent,);
if gossip_stake_percent > 75 {
break;
}
sleep(Duration::new(1, 0));
}
}
pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) { pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
use crate::genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo}; use crate::genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo};
@ -577,8 +603,11 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
let leader_voting_keypair = Arc::new(voting_keypair); let leader_voting_keypair = Arc::new(voting_keypair);
let storage_keypair = Arc::new(Keypair::new()); let storage_keypair = Arc::new(Keypair::new());
let mut config = ValidatorConfig::default(); let config = ValidatorConfig {
config.transaction_status_service_disabled = true; transaction_status_service_disabled: true,
rpc_ports: Some((node.info.rpc.port(), node.info.rpc_pubsub.port())),
..ValidatorConfig::default()
};
let node = Validator::new( let node = Validator::new(
node, node,
&node_keypair, &node_keypair,
@ -654,6 +683,16 @@ mod tests {
use crate::genesis_utils::create_genesis_config_with_leader; use crate::genesis_utils::create_genesis_config_with_leader;
use std::fs::remove_dir_all; use std::fs::remove_dir_all;
#[test]
fn test_compute_shred_version() {
let mut hard_forks = HardForks::default();
assert_eq!(compute_shred_version(&Hash::default(), &hard_forks), 1);
hard_forks.register(1);
assert_eq!(compute_shred_version(&Hash::default(), &hard_forks), 55551);
hard_forks.register(1);
assert_eq!(compute_shred_version(&Hash::default(), &hard_forks), 46353);
}
#[test] #[test]
fn validator_exit() { fn validator_exit() {
solana_logger::setup(); solana_logger::setup();
@ -669,8 +708,14 @@ mod tests {
let voting_keypair = Arc::new(Keypair::new()); let voting_keypair = Arc::new(Keypair::new());
let storage_keypair = Arc::new(Keypair::new()); let storage_keypair = Arc::new(Keypair::new());
let mut config = ValidatorConfig::default(); let config = ValidatorConfig {
config.transaction_status_service_disabled = true; transaction_status_service_disabled: true,
rpc_ports: Some((
validator_node.info.rpc.port(),
validator_node.info.rpc_pubsub.port(),
)),
..ValidatorConfig::default()
};
let validator = Validator::new( let validator = Validator::new(
validator_node, validator_node,
&Arc::new(validator_keypair), &Arc::new(validator_keypair),
@ -703,8 +748,14 @@ mod tests {
ledger_paths.push(validator_ledger_path.clone()); ledger_paths.push(validator_ledger_path.clone());
let voting_keypair = Arc::new(Keypair::new()); let voting_keypair = Arc::new(Keypair::new());
let storage_keypair = Arc::new(Keypair::new()); let storage_keypair = Arc::new(Keypair::new());
let mut config = ValidatorConfig::default(); let config = ValidatorConfig {
config.transaction_status_service_disabled = true; transaction_status_service_disabled: true,
rpc_ports: Some((
validator_node.info.rpc.port(),
validator_node.info.rpc_pubsub.port(),
)),
..ValidatorConfig::default()
};
Validator::new( Validator::new(
validator_node, validator_node,
&Arc::new(validator_keypair), &Arc::new(validator_keypair),

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-faucet" name = "solana-faucet"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
tokio = "0.1" tokio = "0.1"
tokio-codec = "0.1" tokio-codec = "0.1"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-genesis-programs" name = "solana-genesis-programs"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.23.1" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.1" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" } solana-exchange-program = { path = "../programs/exchange", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.1" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.1" }
solana-vest-program = { path = "../programs/vest", version = "0.23.0" } solana-vest-program = { path = "../programs/vest", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
[lib] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-genesis" name = "solana-genesis"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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/"
@ -17,13 +17,13 @@ serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" } solana-genesis-programs = { path = "../genesis-programs", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.1" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
tempfile = "3.1.0" tempfile = "3.1.0"
[[bin]] [[bin]]

View File

@ -55,7 +55,7 @@ pub const BATCH_FOUR_STAKER_INFOS: &[StakerInfo] = &[
}, },
StakerInfo { StakerInfo {
name: "unbecoming silver", name: "unbecoming silver",
staker: "42yapY7Vrs5jqht9TCKZsPoyb4vDFYcPfRkqAP85NSAQ", staker: "4AcoZa1P8fF5XK21RJsiuMRZPEScbbWNc75oakRFHiBz",
lamports: 28_800 * LAMPORTS_PER_SOL, lamports: 28_800 * LAMPORTS_PER_SOL,
}, },
StakerInfo { StakerInfo {
@ -220,7 +220,6 @@ pub const VALIDATOR_PUBKEYS: &[&str] = &[
"7v5DXDvYzkgTdFYXYB12ZLKD6z8QfzR53N9hg6XgEQJE", // Cryptium Labs GmbH "7v5DXDvYzkgTdFYXYB12ZLKD6z8QfzR53N9hg6XgEQJE", // Cryptium Labs GmbH
"8LSwP5qYbmuUfKLGwi8XaKJnai9HyZAJTnBovyWebRfd", // "8LSwP5qYbmuUfKLGwi8XaKJnai9HyZAJTnBovyWebRfd", //
"8UPb8LMWyoJJC9Aeq9QmTzKZKV2ssov739bTJ14M4ws1", // "8UPb8LMWyoJJC9Aeq9QmTzKZKV2ssov739bTJ14M4ws1", //
"8oRw7qpj6XgLGXYCDuNoTMCqoJnDd6A8LTpNyqApSfkA", //
"8wFK4fCAuDoAH1fsgou9yKZPqDMFtJUVoDdkZAAMuhyA", // LunaNova Technologies Ltd "8wFK4fCAuDoAH1fsgou9yKZPqDMFtJUVoDdkZAAMuhyA", // LunaNova Technologies Ltd
"94eWgQm2k8BXKEWbJP2eScHZeKopXpqkuoVrCofQWBhW", // Node A-Team "94eWgQm2k8BXKEWbJP2eScHZeKopXpqkuoVrCofQWBhW", // Node A-Team
"9J8WcnXxo3ArgEwktfk9tsrf4Rp8h5uPUgnQbQHLvtkd", // moonli.me "9J8WcnXxo3ArgEwktfk9tsrf4Rp8h5uPUgnQbQHLvtkd", // moonli.me

View File

@ -3,19 +3,19 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-gossip" name = "solana-gossip"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-install" name = "solana-install"
description = "The solana cluster software installer" description = "The solana cluster software installer"
version = "0.23.0" version = "0.23.1"
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,11 +26,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 = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
tar = "0.4.26" tar = "0.4.26"
tempdir = "0.3.7" tempdir = "0.3.7"
url = "2.1.1" url = "2.1.1"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-keygen" name = "solana-keygen"
version = "0.23.0" version = "0.23.1"
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"
@ -14,8 +14,9 @@ clap = "2.33"
dirs = "2.0.2" dirs = "2.0.2"
num_cpus = "1.12.0" num_cpus = "1.12.0"
rpassword = "4.0" rpassword = "4.0"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-cli-config = { path = "../cli-config", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.1" }
tiny-bip39 = "0.7.0" tiny-bip39 = "0.7.0"
[[bin]] [[bin]]

View File

@ -8,6 +8,7 @@ use num_cpus;
use solana_clap_utils::keypair::{ use solana_clap_utils::keypair::{
keypair_from_seed_phrase, prompt_passphrase, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG, keypair_from_seed_phrase, prompt_passphrase, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
}; };
use solana_cli_config::config::{Config, CONFIG_FILE};
use solana_sdk::{ use solana_sdk::{
pubkey::write_pubkey_file, pubkey::write_pubkey_file,
signature::{ signature::{
@ -21,7 +22,7 @@ use std::{
path::Path, path::Path,
process::exit, process::exit,
sync::{ sync::{
atomic::{AtomicU64, Ordering}, atomic::{AtomicBool, AtomicU64, Ordering},
Arc, Arc,
}, },
thread, thread,
@ -30,6 +31,12 @@ use std::{
const NO_PASSPHRASE: &str = ""; const NO_PASSPHRASE: &str = "";
struct GrindMatch {
starts: String,
ends: String,
count: AtomicU64,
}
fn check_for_overwrite(outfile: &str, matches: &ArgMatches) { fn check_for_overwrite(outfile: &str, matches: &ArgMatches) {
let force = matches.is_present("force"); let force = matches.is_present("force");
if !force && Path::new(outfile).exists() { if !force && Path::new(outfile).exists() {
@ -38,23 +45,28 @@ fn check_for_overwrite(outfile: &str, matches: &ArgMatches) {
} }
} }
fn get_keypair_from_matches(matches: &ArgMatches) -> Result<Keypair, Box<dyn error::Error>> { fn get_keypair_from_matches(
matches: &ArgMatches,
config: Config,
) -> Result<Keypair, Box<dyn error::Error>> {
let mut path = dirs::home_dir().expect("home directory"); let mut path = dirs::home_dir().expect("home directory");
let infile = if matches.is_present("infile") { let keypair = if matches.is_present("keypair") {
matches.value_of("infile").unwrap() matches.value_of("keypair").unwrap()
} else if config.keypair_path != "" {
&config.keypair_path
} else { } else {
path.extend(&[".config", "solana", "id.json"]); path.extend(&[".config", "solana", "id.json"]);
path.to_str().unwrap() path.to_str().unwrap()
}; };
if infile == "-" { if keypair == "-" {
let mut stdin = std::io::stdin(); let mut stdin = std::io::stdin();
read_keypair(&mut stdin) read_keypair(&mut stdin)
} else if infile == ASK_KEYWORD { } else if keypair == ASK_KEYWORD {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name); let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
keypair_from_seed_phrase("pubkey recovery", skip_validation, false) keypair_from_seed_phrase("pubkey recovery", skip_validation, false)
} else { } else {
read_keypair_file(infile) read_keypair_file(keypair)
} }
} }
@ -73,28 +85,152 @@ fn output_keypair(
Ok(()) Ok(())
} }
fn grind_validator_starts_with(v: String) -> Result<(), String> {
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from("Expected : between PREFIX and COUNT"));
}
let args: Vec<&str> = v.split(':').collect();
bs58::decode(&args[0])
.into_vec()
.map_err(|err| format!("{}: {:?}", args[0], err))?;
let count = args[1].parse::<u64>();
if count.is_err() || count.unwrap() == 0 {
return Err(String::from("Expected COUNT to be of type u64"));
}
Ok(())
}
fn grind_validator_ends_with(v: String) -> Result<(), String> {
if v.matches(':').count() != 1 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from("Expected : between SUFFIX and COUNT"));
}
let args: Vec<&str> = v.split(':').collect();
bs58::decode(&args[0])
.into_vec()
.map_err(|err| format!("{}: {:?}", args[0], err))?;
let count = args[1].parse::<u64>();
if count.is_err() || count.unwrap() == 0 {
return Err(String::from("Expected COUNT to be of type u64"));
}
Ok(())
}
fn grind_validator_starts_and_ends_with(v: String) -> Result<(), String> {
if v.matches(':').count() != 2 || (v.starts_with(':') || v.ends_with(':')) {
return Err(String::from(
"Expected : between PREFIX and SUFFIX and COUNT",
));
}
let args: Vec<&str> = v.split(':').collect();
bs58::decode(&args[0])
.into_vec()
.map_err(|err| format!("{}: {:?}", args[0], err))?;
bs58::decode(&args[1])
.into_vec()
.map_err(|err| format!("{}: {:?}", args[1], err))?;
let count = args[2].parse::<u64>();
if count.is_err() || count.unwrap() == 0 {
return Err(String::from("Expected COUNT to be a u64"));
}
Ok(())
}
fn grind_print_info(grind_matches: &[GrindMatch]) {
println!("Searching with {} threads for:", num_cpus::get());
for gm in grind_matches {
let mut msg = Vec::<String>::new();
if gm.count.load(Ordering::Relaxed) > 1 {
msg.push("pubkeys".to_string());
msg.push("start".to_string());
msg.push("end".to_string());
} else {
msg.push("pubkey".to_string());
msg.push("starts".to_string());
msg.push("ends".to_string());
}
println!(
"\t{} {} that {} with '{}' and {} with '{}'",
gm.count.load(Ordering::Relaxed),
msg[0],
msg[1],
gm.starts,
msg[2],
gm.ends
);
}
}
fn grind_parse_args(
starts_with_args: HashSet<String>,
ends_with_args: HashSet<String>,
starts_and_ends_with_args: HashSet<String>,
) -> Vec<GrindMatch> {
let mut grind_matches = Vec::<GrindMatch>::new();
for sw in starts_with_args {
let args: Vec<&str> = sw.split(':').collect();
grind_matches.push(GrindMatch {
starts: args[0].to_lowercase(),
ends: "".to_string(),
count: AtomicU64::new(args[1].parse::<u64>().unwrap()),
});
}
for ew in ends_with_args {
let args: Vec<&str> = ew.split(':').collect();
grind_matches.push(GrindMatch {
starts: "".to_string(),
ends: args[0].to_lowercase(),
count: AtomicU64::new(args[1].parse::<u64>().unwrap()),
});
}
for swew in starts_and_ends_with_args {
let args: Vec<&str> = swew.split(':').collect();
grind_matches.push(GrindMatch {
starts: args[0].to_lowercase(),
ends: args[1].to_lowercase(),
count: AtomicU64::new(args[2].parse::<u64>().unwrap()),
});
}
grind_print_info(&grind_matches);
grind_matches
}
fn main() -> Result<(), Box<dyn error::Error>> { fn main() -> Result<(), Box<dyn error::Error>> {
let matches = App::new(crate_name!()) let matches = App::new(crate_name!())
.about(crate_description!()) .about(crate_description!())
.version(solana_clap_utils::version!()) .version(solana_clap_utils::version!())
.setting(AppSettings::SubcommandRequiredElseHelp) .setting(AppSettings::SubcommandRequiredElseHelp)
.arg({
let arg = Arg::with_name("config_file")
.short("C")
.long("config")
.value_name("PATH")
.takes_value(true)
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(&config_file)
} else {
arg
}
})
.subcommand( .subcommand(
SubCommand::with_name("verify") SubCommand::with_name("verify")
.about("Verify a keypair can sign and verify a message.") .about("Verify a keypair can sign and verify a message.")
.arg( .arg(
Arg::with_name("infile") Arg::with_name("pubkey")
.index(1) .index(1)
.value_name("BASE58_PUBKEY")
.takes_value(true)
.required(true)
.help("Public key"),
)
.arg(
Arg::with_name("keypair")
.index(2)
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
.help("Path to keypair file"), .help("Path to keypair file"),
) )
.arg(
Arg::with_name("pubkey")
.index(2)
.value_name("BASE58_PUBKEY")
.takes_value(true)
.help("Public key"),
)
) )
.subcommand( .subcommand(
SubCommand::with_name("new") SubCommand::with_name("new")
@ -148,33 +284,37 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.arg( .arg(
Arg::with_name("ignore_case") Arg::with_name("ignore_case")
.long("ignore-case") .long("ignore-case")
.help("Perform case insensitive matches"), .help("Performs case insensitive matches"),
)
.arg(
Arg::with_name("includes")
.long("includes")
.value_name("BASE58")
.takes_value(true)
.multiple(true)
.validator(|value| {
bs58::decode(&value).into_vec()
.map(|_| ())
.map_err(|err| format!("{}: {:?}", value, err))
})
.help("Save keypair if its public key includes this string\n(may be specified multiple times)"),
) )
.arg( .arg(
Arg::with_name("starts_with") Arg::with_name("starts_with")
.long("starts-with") .long("starts-with")
.value_name("BASE58 PREFIX") .value_name("PREFIX:COUNT")
.number_of_values(1)
.takes_value(true) .takes_value(true)
.multiple(true) .multiple(true)
.validator(|value| { .validator(grind_validator_starts_with)
bs58::decode(&value).into_vec() .help("Saves specified number of keypairs whos public key starts with the indicated prefix\nExample: --starts-with sol:4\nPREFIX type is Base58\nCOUNT type is u64"),
.map(|_| ()) )
.map_err(|err| format!("{}: {:?}", value, err)) .arg(
}) Arg::with_name("ends_with")
.help("Save keypair if its public key starts with this prefix\n(may be specified multiple times)"), .long("ends-with")
.value_name("SUFFIX:COUNT")
.number_of_values(1)
.takes_value(true)
.multiple(true)
.validator(grind_validator_ends_with)
.help("Saves specified number of keypairs whos public key ends with the indicated suffix\nExample: --ends-with ana:4\nSUFFIX type is Base58\nCOUNT type is u64"),
)
.arg(
Arg::with_name("starts_and_ends_with")
.long("starts-and-ends-with")
.value_name("PREFIX:SUFFIX:COUNT")
.number_of_values(1)
.takes_value(true)
.multiple(true)
.validator(grind_validator_starts_and_ends_with)
.help("Saves specified number of keypairs whos public key starts and ends with the indicated perfix and suffix\nExample: --starts-and-ends-with sol:ana:4\nPREFIX and SUFFIX type is Base58\nCOUNT type is u64"),
), ),
) )
.subcommand( .subcommand(
@ -182,7 +322,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.about("Display the pubkey from a keypair file") .about("Display the pubkey from a keypair file")
.setting(AppSettings::DisableVersion) .setting(AppSettings::DisableVersion)
.arg( .arg(
Arg::with_name("infile") Arg::with_name("keypair")
.index(1) .index(1)
.value_name("PATH") .value_name("PATH")
.takes_value(true) .takes_value(true)
@ -234,10 +374,15 @@ fn main() -> Result<(), Box<dyn error::Error>> {
) )
.get_matches(); .get_matches();
let config = if let Some(config_file) = matches.value_of("config_file") {
Config::load(config_file).unwrap_or_default()
} else {
Config::default()
};
match matches.subcommand() { match matches.subcommand() {
("pubkey", Some(matches)) => { ("pubkey", Some(matches)) => {
let keypair = get_keypair_from_matches(matches)?; let keypair = get_keypair_from_matches(matches, config)?;
if matches.is_present("outfile") { if matches.is_present("outfile") {
let outfile = matches.value_of("outfile").unwrap(); let outfile = matches.value_of("outfile").unwrap();
@ -311,16 +456,8 @@ fn main() -> Result<(), Box<dyn error::Error>> {
} }
("grind", Some(matches)) => { ("grind", Some(matches)) => {
let ignore_case = matches.is_present("ignore_case"); let ignore_case = matches.is_present("ignore_case");
let includes = if matches.is_present("includes") {
values_t_or_exit!(matches, "includes", String)
.into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect()
} else {
HashSet::new()
};
let starts_with = if matches.is_present("starts_with") { let starts_with_args = if matches.is_present("starts_with") {
values_t_or_exit!(matches, "starts_with", String) values_t_or_exit!(matches, "starts_with", String)
.into_iter() .into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s }) .map(|s| if ignore_case { s.to_lowercase() } else { s })
@ -328,68 +465,101 @@ fn main() -> Result<(), Box<dyn error::Error>> {
} else { } else {
HashSet::new() HashSet::new()
}; };
let ends_with_args = if matches.is_present("ends_with") {
values_t_or_exit!(matches, "ends_with", String)
.into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect()
} else {
HashSet::new()
};
let starts_and_ends_with_args = if matches.is_present("starts_and_ends_with") {
values_t_or_exit!(matches, "starts_and_ends_with", String)
.into_iter()
.map(|s| if ignore_case { s.to_lowercase() } else { s })
.collect()
} else {
HashSet::new()
};
if includes.is_empty() && starts_with.is_empty() { if starts_with_args.is_empty()
&& ends_with_args.is_empty()
&& starts_and_ends_with_args.is_empty()
{
eprintln!( eprintln!(
"Error: No keypair search criteria provided (--includes or --starts-with)" "Error: No keypair search criteria provided (--starts-with or --ends-with or --starts-and-ends-with)"
); );
exit(1); exit(1);
} }
let grind_matches =
grind_parse_args(starts_with_args, ends_with_args, starts_and_ends_with_args);
let grind_matches_thread_safe = Arc::new(grind_matches);
let attempts = Arc::new(AtomicU64::new(1)); let attempts = Arc::new(AtomicU64::new(1));
let found = Arc::new(AtomicU64::new(0)); let found = Arc::new(AtomicU64::new(0));
let start = Instant::now(); let start = Instant::now();
let done = Arc::new(AtomicBool::new(false));
println!( for _ in 0..num_cpus::get() {
"Searching with {} threads for a pubkey containing {:?} or starting with {:?}", let done = done.clone();
num_cpus::get(), let attempts = attempts.clone();
includes, let found = found.clone();
starts_with let grind_matches_thread_safe = grind_matches_thread_safe.clone();
);
let _threads = (0..num_cpus::get()) let handle = thread::spawn(move || loop {
.map(|_| { if done.load(Ordering::Relaxed) {
let attempts = attempts.clone(); break;
let found = found.clone(); }
let includes = includes.clone(); let attempts = attempts.fetch_add(1, Ordering::Relaxed);
let starts_with = starts_with.clone(); if attempts % 1_000_000 == 0 {
println!(
thread::spawn(move || loop { "Searched {} keypairs in {}s. {} matches found.",
let attempts = attempts.fetch_add(1, Ordering::Relaxed); attempts,
if attempts % 5_000_000 == 0 { start.elapsed().as_secs(),
println!( found.load(Ordering::Relaxed),
"Searched {} keypairs in {}s. {} matches found", );
attempts, }
start.elapsed().as_secs(), let keypair = Keypair::new();
found.load(Ordering::Relaxed), let mut pubkey = bs58::encode(keypair.pubkey()).into_string();
); if ignore_case {
pubkey = pubkey.to_lowercase();
}
let mut total_matches_found = 0;
for i in 0..grind_matches_thread_safe.len() {
if grind_matches_thread_safe[i].count.load(Ordering::Relaxed) == 0 {
total_matches_found += 1;
continue;
} }
if (!grind_matches_thread_safe[i].starts.is_empty()
let keypair = Keypair::new(); && grind_matches_thread_safe[i].ends.is_empty()
let mut pubkey = bs58::encode(keypair.pubkey()).into_string(); && pubkey.starts_with(&grind_matches_thread_safe[i].starts))
|| (grind_matches_thread_safe[i].starts.is_empty()
if ignore_case { && !grind_matches_thread_safe[i].ends.is_empty()
pubkey = pubkey.to_lowercase(); && pubkey.ends_with(&grind_matches_thread_safe[i].ends))
} || (!grind_matches_thread_safe[i].starts.is_empty()
&& !grind_matches_thread_safe[i].ends.is_empty()
if starts_with.iter().any(|s| pubkey.starts_with(s)) && pubkey.starts_with(&grind_matches_thread_safe[i].starts)
|| includes.iter().any(|s| pubkey.contains(s)) && pubkey.ends_with(&grind_matches_thread_safe[i].ends))
{ {
let found = found.fetch_add(1, Ordering::Relaxed); let _found = found.fetch_add(1, Ordering::Relaxed);
output_keypair( grind_matches_thread_safe[i]
&keypair, .count
&format!("{}.json", keypair.pubkey()), .fetch_sub(1, Ordering::Relaxed);
&format!("{}", found), println!("Wrote keypair to {}", &format!("{}.json", keypair.pubkey()));
) write_keypair_file(&keypair, &format!("{}.json", keypair.pubkey()))
.unwrap(); .unwrap();
} }
}); }
}) if total_matches_found == grind_matches_thread_safe.len() {
.collect::<Vec<_>>(); done.store(true, Ordering::Relaxed);
thread::park(); }
});
handle.join().unwrap();
}
} }
("verify", Some(matches)) => { ("verify", Some(matches)) => {
let keypair = get_keypair_from_matches(matches)?; let keypair = get_keypair_from_matches(matches, config)?;
let test_data = b"test"; let test_data = b"test";
let signature = Signature::new(&keypair.sign(test_data).to_bytes()); let signature = Signature::new(&keypair.sign(test_data).to_bytes());
let pubkey_bs58 = matches.value_of("pubkey").unwrap(); let pubkey_bs58 = matches.value_of("pubkey").unwrap();

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-ledger-tool" name = "solana-ledger-tool"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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/"
@ -16,12 +16,12 @@ serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
serde_yaml = "0.8.11" serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
tempfile = "3.1.0" tempfile = "3.1.0"
[dev-dependencies] [dev-dependencies]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-ledger" name = "solana-ledger"
version = "0.23.0" version = "0.23.1"
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"
@ -29,19 +29,19 @@ reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0
serde = "1.0.104" serde = "1.0.104"
serde_bytes = "0.11.3" serde_bytes = "0.11.3"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.1" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" } solana-genesis-programs = { path = "../genesis-programs", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.1" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" } solana-merkle-tree = { path = "../merkle-tree", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.1" }
ed25519-dalek = "1.0.0-pre.1" ed25519-dalek = "1.0.0-pre.1"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.1" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.1" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.1" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.1" }
sys-info = "0.5.8" sys-info = "0.5.8"
symlink = "0.1.0" symlink = "0.1.0"
tar = "0.4.26" tar = "0.4.26"
@ -59,7 +59,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 = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
[lib] [lib]
crate-type = ["lib"] crate-type = ["lib"]

View File

@ -90,6 +90,7 @@ pub struct Blockstore {
insert_shreds_lock: Arc<Mutex<()>>, insert_shreds_lock: Arc<Mutex<()>>,
pub new_shreds_signals: Vec<SyncSender<bool>>, pub new_shreds_signals: Vec<SyncSender<bool>>,
pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>, pub completed_slots_senders: Vec<SyncSender<Vec<Slot>>>,
pub lowest_cleanup_slot: Arc<RwLock<u64>>,
} }
pub struct IndexMetaWorkingSetEntry { pub struct IndexMetaWorkingSetEntry {
@ -207,7 +208,7 @@ impl Blockstore {
measure.stop(); measure.stop();
info!("{:?} {}", blockstore_path, measure); info!("{:?} {}", blockstore_path, measure);
Ok(Blockstore { let blockstore = Blockstore {
db, db,
meta_cf, meta_cf,
dead_slots_cf, dead_slots_cf,
@ -222,7 +223,9 @@ impl Blockstore {
completed_slots_senders: vec![], completed_slots_senders: vec![],
insert_shreds_lock: Arc::new(Mutex::new(())), insert_shreds_lock: Arc::new(Mutex::new(())),
last_root, last_root,
}) lowest_cleanup_slot: Arc::new(RwLock::new(0)),
};
Ok(blockstore)
} }
pub fn open_with_signal( pub fn open_with_signal(
@ -1059,6 +1062,12 @@ impl Blockstore {
to_index: u64, to_index: u64,
buffer: &mut [u8], buffer: &mut [u8],
) -> Result<(u64, usize)> { ) -> Result<(u64, usize)> {
// lowest_cleanup_slot is the last slot that was not cleaned up by
// LedgerCleanupService
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
if *lowest_cleanup_slot > slot {
return Err(BlockstoreError::SlotCleanedUp);
}
let meta_cf = self.db.column::<cf::SlotMeta>(); let meta_cf = self.db.column::<cf::SlotMeta>();
let mut buffer_offset = 0; let mut buffer_offset = 0;
let mut last_index = 0; let mut last_index = 0;
@ -1288,14 +1297,26 @@ impl Blockstore {
slot: Slot, slot: Slot,
slot_duration: Duration, slot_duration: Duration,
stakes: &HashMap<Pubkey, (u64, Account)>, stakes: &HashMap<Pubkey, (u64, Account)>,
) -> Option<UnixTimestamp> { ) -> Result<Option<UnixTimestamp>> {
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
// lowest_cleanup_slot is the last slot that was not cleaned up by
// LedgerCleanupService
if *lowest_cleanup_slot > slot {
return Err(BlockstoreError::SlotCleanedUp);
}
let unique_timestamps: HashMap<Pubkey, (Slot, UnixTimestamp)> = self let unique_timestamps: HashMap<Pubkey, (Slot, UnixTimestamp)> = self
.get_timestamp_slots(slot, TIMESTAMP_SLOT_INTERVAL, TIMESTAMP_SLOT_RANGE) .get_timestamp_slots(slot, TIMESTAMP_SLOT_INTERVAL, TIMESTAMP_SLOT_RANGE)
.into_iter() .into_iter()
.flat_map(|query_slot| self.get_block_timestamps(query_slot).unwrap_or_default()) .flat_map(|query_slot| self.get_block_timestamps(query_slot).unwrap_or_default())
.collect(); .collect();
calculate_stake_weighted_timestamp(unique_timestamps, stakes, slot, slot_duration) Ok(calculate_stake_weighted_timestamp(
unique_timestamps,
stakes,
slot,
slot_duration,
))
} }
fn get_timestamp_slots( fn get_timestamp_slots(
@ -1346,6 +1367,12 @@ impl Blockstore {
slot: Slot, slot: Slot,
encoding: Option<RpcTransactionEncoding>, encoding: Option<RpcTransactionEncoding>,
) -> Result<RpcConfirmedBlock> { ) -> Result<RpcConfirmedBlock> {
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
// lowest_cleanup_slot is the last slot that was not cleaned up by
// LedgerCleanupService
if *lowest_cleanup_slot > slot {
return Err(BlockstoreError::SlotCleanedUp);
}
let encoding = encoding.unwrap_or(RpcTransactionEncoding::Json); let encoding = encoding.unwrap_or(RpcTransactionEncoding::Json);
if self.is_root(slot) { if self.is_root(slot) {
let slot_meta_cf = self.db.column::<cf::SlotMeta>(); let slot_meta_cf = self.db.column::<cf::SlotMeta>();
@ -1466,6 +1493,14 @@ impl Blockstore {
if self.is_dead(slot) { if self.is_dead(slot) {
return Err(BlockstoreError::DeadSlot); return Err(BlockstoreError::DeadSlot);
} }
// lowest_cleanup_slot is the last slot that was not cleaned up by
// LedgerCleanupService
let lowest_cleanup_slot = self.lowest_cleanup_slot.read().unwrap();
if *lowest_cleanup_slot > slot {
return Err(BlockstoreError::SlotCleanedUp);
}
let slot_meta_cf = self.db.column::<cf::SlotMeta>(); let slot_meta_cf = self.db.column::<cf::SlotMeta>();
let slot_meta = slot_meta_cf.get(slot)?; let slot_meta = slot_meta_cf.get(slot)?;
if slot_meta.is_none() { if slot_meta.is_none() {
@ -4886,10 +4921,11 @@ pub mod tests {
}) })
.sum(); .sum();
expected_time /= total_stake; expected_time /= total_stake;
assert_eq!(block_time_slot_3.unwrap() as u64, expected_time); assert_eq!(block_time_slot_3.unwrap().unwrap() as u64, expected_time);
assert_eq!( assert_eq!(
blockstore blockstore
.get_block_time(8, slot_duration.clone(), &stakes) .get_block_time(8, slot_duration.clone(), &stakes)
.unwrap()
.unwrap() as u64, .unwrap() as u64,
expected_time + 2 // At 400ms block duration, 5 slots == 2sec expected_time + 2 // At 400ms block duration, 5 slots == 2sec
); );

View File

@ -49,6 +49,7 @@ pub enum BlockstoreError {
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
Serialize(#[from] Box<bincode::ErrorKind>), Serialize(#[from] Box<bincode::ErrorKind>),
FsExtraError(#[from] fs_extra::error::Error), FsExtraError(#[from] fs_extra::error::Error),
SlotCleanedUp,
} }
pub(crate) type Result<T> = std::result::Result<T, BlockstoreError>; pub(crate) type Result<T> = std::result::Result<T, BlockstoreError>;

View File

@ -396,11 +396,11 @@ mod tests {
); );
assert_eq!( assert_eq!(
cache.next_leader_slot(&pubkey, 0, &bank, None), cache.next_leader_slot(&pubkey, 0, &bank, None),
Some((1, 6047999)) Some((1, 863999))
); );
assert_eq!( assert_eq!(
cache.next_leader_slot(&pubkey, 1, &bank, None), cache.next_leader_slot(&pubkey, 1, &bank, None),
Some((2, 6047999)) Some((2, 863999))
); );
assert_eq!( assert_eq!(
cache.next_leader_slot( cache.next_leader_slot(

View File

@ -448,7 +448,7 @@ pub fn bank_from_archive<P: AsRef<Path>>(
} else { } else {
// Once v0.23.x is deployed, this default can be removed and snapshots without a version // Once v0.23.x is deployed, this default can be removed and snapshots without a version
// file can be rejected // file can be rejected
String::from("v0.22.3") String::from("0.22.3")
}; };
let bank = rebuild_bank_from_snapshots( let bank = rebuild_bank_from_snapshots(
@ -525,11 +525,6 @@ where
|stream| { |stream| {
let mut bank: Bank = match snapshot_version { let mut bank: Bank = match snapshot_version {
env!("CARGO_PKG_VERSION") => deserialize_from_snapshot(stream.by_ref())?, env!("CARGO_PKG_VERSION") => deserialize_from_snapshot(stream.by_ref())?,
"v0.22.3" => {
let bank0223: solana_runtime::bank::LegacyBank0223 =
deserialize_from_snapshot(stream.by_ref())?;
bank0223.into()
}
_ => { _ => {
return Err(get_io_error(&format!( return Err(get_io_error(&format!(
"unsupported snapshot version: {}", "unsupported snapshot version: {}",

View File

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

View File

@ -38,6 +38,7 @@ impl ClusterValidatorInfo {
pub trait Cluster { pub trait Cluster {
fn get_node_pubkeys(&self) -> Vec<Pubkey>; fn get_node_pubkeys(&self) -> Vec<Pubkey>;
fn get_validator_client(&self, pubkey: &Pubkey) -> Option<ThinClient>; fn get_validator_client(&self, pubkey: &Pubkey) -> Option<ThinClient>;
fn get_contact_info(&self, pubkey: &Pubkey) -> Option<&ContactInfo>;
fn exit_node(&mut self, pubkey: &Pubkey) -> ClusterValidatorInfo; fn exit_node(&mut self, pubkey: &Pubkey) -> ClusterValidatorInfo;
fn restart_node(&mut self, pubkey: &Pubkey, cluster_validator_info: ClusterValidatorInfo); fn restart_node(&mut self, pubkey: &Pubkey, cluster_validator_info: ClusterValidatorInfo);
fn exit_restart_node(&mut self, pubkey: &Pubkey, config: ValidatorConfig); fn exit_restart_node(&mut self, pubkey: &Pubkey, config: ValidatorConfig);

View File

@ -207,6 +207,10 @@ impl LocalCluster {
let leader_storage_keypair = Arc::new(storage_keypair); let leader_storage_keypair = Arc::new(storage_keypair);
let leader_voting_keypair = Arc::new(voting_keypair); let leader_voting_keypair = Arc::new(voting_keypair);
let mut leader_config = config.validator_configs[0].clone(); let mut leader_config = config.validator_configs[0].clone();
leader_config.rpc_ports = Some((
leader_node.info.rpc.port(),
leader_node.info.rpc_pubsub.port(),
));
leader_config.transaction_status_service_disabled = true; leader_config.transaction_status_service_disabled = true;
let leader_server = Validator::new( let leader_server = Validator::new(
leader_node, leader_node,
@ -351,6 +355,10 @@ impl LocalCluster {
} }
let mut config = validator_config.clone(); let mut config = validator_config.clone();
config.rpc_ports = Some((
validator_node.info.rpc.port(),
validator_node.info.rpc_pubsub.port(),
));
config.transaction_status_service_disabled = true; config.transaction_status_service_disabled = true;
let voting_keypair = Arc::new(voting_keypair); let voting_keypair = Arc::new(voting_keypair);
let validator_server = Validator::new( let validator_server = Validator::new(
@ -658,6 +666,8 @@ impl Cluster for LocalCluster {
// Update the stored ContactInfo for this node // Update the stored ContactInfo for this node
let node = Node::new_localhost_with_pubkey(&pubkey); let node = Node::new_localhost_with_pubkey(&pubkey);
cluster_validator_info.info.contact_info = node.info.clone(); cluster_validator_info.info.contact_info = node.info.clone();
cluster_validator_info.config.rpc_ports =
Some((node.info.rpc.port(), node.info.rpc_pubsub.port()));
cluster_validator_info cluster_validator_info
.config .config
.transaction_status_service_disabled = true; .transaction_status_service_disabled = true;
@ -695,6 +705,10 @@ impl Cluster for LocalCluster {
cluster_validator_info.config = validator_config; cluster_validator_info.config = validator_config;
self.restart_node(pubkey, cluster_validator_info); self.restart_node(pubkey, cluster_validator_info);
} }
fn get_contact_info(&self, pubkey: &Pubkey) -> Option<&ContactInfo> {
self.validators.get(pubkey).map(|v| &v.info.contact_info)
}
} }
impl Drop for LocalCluster { impl Drop for LocalCluster {

View File

@ -73,12 +73,14 @@ fn run_archiver_startup_basic(num_nodes: usize, num_archivers: usize) {
} }
#[test] #[test]
#[ignore]
#[serial] #[serial]
fn test_archiver_startup_1_node() { fn test_archiver_startup_1_node() {
run_archiver_startup_basic(1, 1); run_archiver_startup_basic(1, 1);
} }
#[test] #[test]
#[ignore]
#[serial] #[serial]
fn test_archiver_startup_2_nodes() { fn test_archiver_startup_2_nodes() {
run_archiver_startup_basic(2, 1); run_archiver_startup_basic(2, 1);

View File

@ -1,13 +1,11 @@
use assert_matches::assert_matches; use assert_matches::assert_matches;
use log::*; use log::*;
use serial_test_derive::serial; use serial_test_derive::serial;
use solana_client::rpc_client::RpcClient;
use solana_client::thin_client::create_client; use solana_client::thin_client::create_client;
use solana_core::{ use solana_core::{
broadcast_stage::BroadcastStageType, broadcast_stage::BroadcastStageType, consensus::VOTE_THRESHOLD_DEPTH,
consensus::VOTE_THRESHOLD_DEPTH, gossip_service::discover_cluster, validator::ValidatorConfig,
gossip_service::discover_cluster,
partition_cfg::{Partition, PartitionCfg},
validator::ValidatorConfig,
}; };
use solana_ledger::{ use solana_ledger::{
bank_forks::SnapshotConfig, blockstore::Blockstore, leader_schedule::FixedSchedule, bank_forks::SnapshotConfig, blockstore::Blockstore, leader_schedule::FixedSchedule,
@ -18,7 +16,6 @@ use solana_local_cluster::{
cluster_tests, cluster_tests,
local_cluster::{ClusterConfig, LocalCluster}, local_cluster::{ClusterConfig, LocalCluster},
}; };
use solana_sdk::timing::timestamp;
use solana_sdk::{ use solana_sdk::{
client::SyncClient, client::SyncClient,
clock, clock,
@ -28,6 +25,7 @@ use solana_sdk::{
poh_config::PohConfig, poh_config::PohConfig,
signature::{Keypair, KeypairUtil}, signature::{Keypair, KeypairUtil},
}; };
use std::sync::atomic::{AtomicBool, Ordering};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fs, iter, fs, iter,
@ -248,7 +246,7 @@ fn run_cluster_partition(
}; };
let validator_pubkeys: Vec<_> = validator_keys.iter().map(|v| v.pubkey()).collect(); let validator_pubkeys: Vec<_> = validator_keys.iter().map(|v| v.pubkey()).collect();
let mut config = ClusterConfig { let config = ClusterConfig {
cluster_lamports, cluster_lamports,
node_stakes, node_stakes,
validator_configs: vec![validator_config.clone(); num_nodes], validator_configs: vec![validator_config.clone(); num_nodes],
@ -256,71 +254,65 @@ fn run_cluster_partition(
..ClusterConfig::default() ..ClusterConfig::default()
}; };
let now = timestamp(); let enable_partition = Some(Arc::new(AtomicBool::new(true)));
// Partition needs to start after the first few shorter warmup epochs, otherwise info!(
// no root will be set before the partition is resolved, the leader schedule will "PARTITION_TEST starting cluster with {:?} partitions slots_per_epoch: {}",
// not be computable, and the cluster wll halt. partitions, config.slots_per_epoch,
let partition_epoch_start_offset = cluster_tests::time_until_nth_epoch(
partition_start_epoch,
config.slots_per_epoch,
config.stakers_slot_offset,
); );
// Assume it takes <= 10 seconds for `LocalCluster::new` to boot up. let mut cluster = LocalCluster::new(&config);
let local_cluster_boot_time = 10_000;
let partition_start = now + partition_epoch_start_offset + local_cluster_boot_time; let (cluster_nodes, _) = discover_cluster(&cluster.entry_point_info.gossip, num_nodes).unwrap();
let partition_end = partition_start + leader_schedule_time as u64;
let mut validator_index = 0; info!("PARTITION_TEST sleeping until partition starting condition",);
for (i, partition) in partitions.iter().enumerate() { loop {
for _ in partition.iter() { let mut reached_epoch = true;
let mut p1 = Partition::default(); for node in &cluster_nodes {
p1.num_partitions = partitions.len(); let node_client = RpcClient::new_socket(node.rpc);
p1.my_partition = i; if let Ok(epoch_info) = node_client.get_epoch_info() {
p1.start_ts = partition_start; info!("slots_per_epoch: {:?}", epoch_info);
p1.end_ts = partition_end; if epoch_info.slots_in_epoch <= (1 << VOTE_THRESHOLD_DEPTH) {
config.validator_configs[validator_index].partition_cfg = reached_epoch = false;
Some(PartitionCfg::new(vec![p1])); break;
validator_index += 1; }
} else {
reached_epoch = false;
}
}
if reached_epoch {
info!("PARTITION_TEST start partition");
enable_partition
.clone()
.unwrap()
.store(false, Ordering::Relaxed);
break;
} else {
sleep(Duration::from_millis(100));
} }
} }
info!( sleep(Duration::from_millis(leader_schedule_time));
"PARTITION_TEST starting cluster with {:?} partitions",
partitions info!("PARTITION_TEST remove partition");
); enable_partition.unwrap().store(true, Ordering::Relaxed);
let now = Instant::now();
let mut cluster = LocalCluster::new(&config);
let elapsed = now.elapsed();
assert!(elapsed.as_millis() < local_cluster_boot_time as u128);
let now = timestamp();
let timeout = partition_start as u64 - now as u64;
info!(
"PARTITION_TEST sleeping until partition start timeout {}",
timeout
);
let mut dead_nodes = HashSet::new(); let mut dead_nodes = HashSet::new();
if timeout > 0 {
sleep(Duration::from_millis(timeout as u64));
}
info!("PARTITION_TEST done sleeping until partition start timeout");
let now = timestamp();
let timeout = partition_end as u64 - now as u64;
info!(
"PARTITION_TEST sleeping until partition end timeout {}",
timeout
);
let mut alive_node_contact_infos = vec![]; let mut alive_node_contact_infos = vec![];
let should_exits: Vec<_> = partitions let should_exits: Vec<_> = partitions
.iter() .iter()
.flat_map(|p| p.iter().map(|(_, should_exit)| should_exit)) .flat_map(|p| p.iter().map(|(_, should_exit)| should_exit))
.collect(); .collect();
assert_eq!(should_exits.len(), validator_pubkeys.len()); assert_eq!(should_exits.len(), validator_pubkeys.len());
let timeout = 10;
if timeout > 0 { if timeout > 0 {
// Give partitions time to propagate their blocks from durinig the partition // Give partitions time to propagate their blocks from during the partition
// after the partition resolves // after the partition resolves
let propagation_time = leader_schedule_time; let propagation_time = leader_schedule_time;
info!("PARTITION_TEST resolving partition"); info!("PARTITION_TEST resolving partition. sleeping {}ms", timeout);
sleep(Duration::from_millis(timeout)); sleep(Duration::from_millis(10_000));
info!("PARTITION_TEST waiting for blocks to propagate after partition"); info!(
"PARTITION_TEST waiting for blocks to propagate after partition {}ms",
propagation_time
);
sleep(Duration::from_millis(propagation_time)); sleep(Duration::from_millis(propagation_time));
info!("PARTITION_TEST resuming normal operation"); info!("PARTITION_TEST resuming normal operation");
for (pubkey, should_exit) in validator_pubkeys.iter().zip(should_exits) { for (pubkey, should_exit) in validator_pubkeys.iter().zip(should_exits) {
@ -353,6 +345,7 @@ fn run_cluster_partition(
info!("PARTITION_TEST looking for new roots on all nodes"); info!("PARTITION_TEST looking for new roots on all nodes");
let mut roots = vec![HashSet::new(); alive_node_contact_infos.len()]; let mut roots = vec![HashSet::new(); alive_node_contact_infos.len()];
let mut done = false; let mut done = false;
let mut last_print = Instant::now();
while !done { while !done {
for (i, ingress_node) in alive_node_contact_infos.iter().enumerate() { for (i, ingress_node) in alive_node_contact_infos.iter().enumerate() {
let client = create_client( let client = create_client(
@ -362,12 +355,15 @@ fn run_cluster_partition(
let slot = client.get_slot().unwrap_or(0); let slot = client.get_slot().unwrap_or(0);
roots[i].insert(slot); roots[i].insert(slot);
let min_node = roots.iter().map(|r| r.len()).min().unwrap_or(0); let min_node = roots.iter().map(|r| r.len()).min().unwrap_or(0);
info!("PARTITION_TEST min observed roots {}/16", min_node); if last_print.elapsed().as_secs() > 3 {
info!("PARTITION_TEST min observed roots {}/16", min_node);
last_print = Instant::now();
}
done = min_node >= 16; done = min_node >= 16;
} }
sleep(Duration::from_millis(clock::DEFAULT_MS_PER_SLOT / 2)); sleep(Duration::from_millis(clock::DEFAULT_MS_PER_SLOT / 2));
} }
info!("PARTITION_TEST done spending on all node"); info!("PARTITION_TEST done waiting for roots");
} }
#[allow(unused_attributes)] #[allow(unused_attributes)]
@ -424,6 +420,7 @@ fn test_kill_partition() {
leader_schedule.push(k.pubkey()) leader_schedule.push(k.pubkey())
} }
} }
info!("leader_schedule: {}", leader_schedule.len());
run_cluster_partition( run_cluster_partition(
&partitions, &partitions,
@ -665,8 +662,11 @@ fn test_snapshot_restart_tower() {
cluster.restart_node(&validator_id, validator_info); cluster.restart_node(&validator_id, validator_info);
// Test cluster can still make progress and get confirmations in tower // Test cluster can still make progress and get confirmations in tower
// Use the restarted node as the discovery point so that we get updated
// validator's ContactInfo
let restarted_node_info = cluster.get_contact_info(&validator_id).unwrap();
cluster_tests::spend_and_verify_all_nodes( cluster_tests::spend_and_verify_all_nodes(
&cluster.entry_point_info, &restarted_node_info,
&cluster.funding_keypair, &cluster.funding_keypair,
1, 1,
HashSet::new(), HashSet::new(),

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-log-analyzer" name = "solana-log-analyzer"
description = "The solana cluster network analysis tool" description = "The solana cluster network analysis tool"
version = "0.23.0" version = "0.23.1"
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/"
@ -17,8 +17,8 @@ semver = "0.9.0"
serde = "1.0.104" serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
[[bin]] [[bin]]
name = "solana-log-analyzer" name = "solana-log-analyzer"

View File

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

View File

@ -1,7 +1,7 @@
[package] [package]
name = "solana-measure" name = "solana-measure"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
[target."cfg(unix)".dependencies] [target."cfg(unix)".dependencies]
jemallocator = "0.3.2" jemallocator = "0.3.2"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-merkle-tree" name = "solana-merkle-tree"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
[dev-dependencies] [dev-dependencies]
hex = "0.4.0" hex = "0.4.0"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-metrics" name = "solana-metrics"
version = "0.23.0" version = "0.23.1"
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"
@ -13,7 +13,7 @@ env_logger = "0.7.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 = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
sys-info = "0.5.8" sys-info = "0.5.8"
[dev-dependencies] [dev-dependencies]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-net-shaper" name = "solana-net-shaper"
description = "The solana cluster network shaping tool" description = "The solana cluster network shaping tool"
version = "0.23.0" version = "0.23.1"
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/"
@ -16,8 +16,8 @@ semver = "0.9.0"
serde = "1.0.104" serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
serde_json = "1.0.44" serde_json = "1.0.44"
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
rand = "0.6.5" rand = "0.6.5"
[[bin]] [[bin]]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-net-utils" name = "solana-net-utils"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
tokio = "0.1" tokio = "0.1"
tokio-codec = "0.1" tokio-codec = "0.1"

View File

@ -868,6 +868,7 @@ EOF
;; ;;
config) config)
failOnValidatorBootupFailure=false
prepareInstancesAndWriteConfigFile prepareInstancesAndWriteConfigFile
;; ;;
info) info)

View File

@ -75,7 +75,7 @@ solana-bench-exchange)
" "
;; ;;
idle) idle)
# Add the mint keypair to idle clients for convenience # Add the faucet keypair to idle clients for convenience
net/scripts/rsync-retry.sh -vPrc \ net/scripts/rsync-retry.sh -vPrc \
"$entrypointIp":~/solana/config/faucet-keypair.json ~/solana/ "$entrypointIp":~/solana/config/faucet-keypair.json ~/solana/
exit 0 exit 0

View File

@ -221,8 +221,8 @@ EOF
# shellcheck disable=SC2206 # Do not want to quote $genesisOptions # shellcheck disable=SC2206 # Do not want to quote $genesisOptions
args+=($genesisOptions) args+=($genesisOptions)
if [[ -f net/keypairs/mint.json ]]; then if [[ -f net/keypairs/faucet.json ]]; then
export FAUCET_KEYPAIR=net/keypairs/mint.json export FAUCET_KEYPAIR=net/keypairs/faucet.json
fi fi
if [[ -f net/keypairs/bootstrap-validator-identity.json ]]; then if [[ -f net/keypairs/bootstrap-validator-identity.json ]]; then
export BOOTSTRAP_VALIDATOR_IDENTITY_KEYPAIR=net/keypairs/bootstrap-validator-identity.json export BOOTSTRAP_VALIDATOR_IDENTITY_KEYPAIR=net/keypairs/bootstrap-validator-identity.json
@ -303,11 +303,11 @@ EOF
fi fi
set -x set -x
# Add the mint keypair to validators for convenient access from tools # Add the faucet keypair to validators for convenient access from tools
# like bench-tps and add to blocktreamers to run a faucet # like bench-tps and add to blocktreamers to run a faucet
scp "$entrypointIp":~/solana/config/faucet-keypair.json config/ scp "$entrypointIp":~/solana/config/faucet-keypair.json config/
if [[ $nodeType = blockstreamer ]]; then if [[ $nodeType = blockstreamer ]]; then
# Run another faucet with the mint keypair on the blockstreamer node. # Run another faucet with the same keypair on the blockstreamer node.
# Typically the blockstreamer node has a static IP/DNS name for hosting # Typically the blockstreamer node has a static IP/DNS name for hosting
# the blockexplorer web app, and is a location that somebody would expect # the blockexplorer web app, and is a location that somebody would expect
# to be able to airdrop from # to be able to airdrop from

View File

@ -1,5 +1,3 @@
asteroids|216.24.140.155|10.1.1.26|16|64|NVME|2000|||0|Denver
pacman|216.24.140.154|10.1.1.25|16|64|NVME|2000|||0|Denver
dumoulin|216.24.140.149|10.1.1.20|16|64|SATA|2000|NVME,NVME,NVME|1000,1000,1000|4|Denver dumoulin|216.24.140.149|10.1.1.20|16|64|SATA|2000|NVME,NVME,NVME|1000,1000,1000|4|Denver
foosball|216.24.140.150|10.1.1.21|16|64|SATA|2000|NVME|1000|2|Denver foosball|216.24.140.150|10.1.1.21|16|64|SATA|2000|NVME|1000|2|Denver
pingpong|216.24.140.151|10.1.1.22|16|64|SATA|2000|NVME|1000|2|Denver pingpong|216.24.140.151|10.1.1.22|16|64|SATA|2000|NVME|1000|2|Denver

View File

@ -174,7 +174,7 @@ cloud_CreateInstances() {
# the stock Ubuntu 18.04 image and programmatically install CUDA after the # the stock Ubuntu 18.04 image and programmatically install CUDA after the
# instance boots # instance boots
# #
imageName="ubuntu-1804-bionic-v20181029-with-cuda-10-and-cuda-9-2" imageName="ubuntu-1804-bionic-v20181029-with-cuda-10-and-cuda-9-2 --image-project principal-lane-200702"
else else
# Upstream Ubuntu 18.04 LTS image # Upstream Ubuntu 18.04 LTS image
imageName="ubuntu-1804-bionic-v20190813a --image-project ubuntu-os-cloud" imageName="ubuntu-1804-bionic-v20190813a --image-project ubuntu-os-cloud"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-perf" name = "solana-perf"
version = "0.23.0" version = "0.23.1"
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"
@ -18,11 +18,11 @@ serde_derive = "1.0.103"
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 = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.1" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.1" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.1" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.1" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.1" }
[lib] [lib]
name = "solana_perf" name = "solana_perf"

View File

@ -1,7 +1,7 @@
[package] [package]
name = "solana-bpf-programs" name = "solana-bpf-programs"
description = "Blockchain, Rebuilt for Scale" description = "Blockchain, Rebuilt for Scale"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0" } solana-bpf-loader-program = { path = "../bpf_loader", version = "0.23.1" }
solana-logger = { path = "../../logger", version = "0.23.0" } solana-logger = { path = "../../logger", version = "0.23.1" }
solana-runtime = { path = "../../runtime", version = "0.23.0" } solana-runtime = { path = "../../runtime", version = "0.23.1" }
solana-sdk = { path = "../../sdk", version = "0.23.0" } solana-sdk = { path = "../../sdk", version = "0.23.1" }
solana_rbpf = "=0.1.19" solana_rbpf = "=0.1.19"
[[bench]] [[bench]]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-128bit" name = "solana-bpf-rust-128bit"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.23.0" } solana-bpf-rust-128bit-dep = { path = "../128bit_dep", version = "0.23.1" }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-128bit-dep" name = "solana-bpf-rust-128bit-dep"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-alloc" name = "solana-bpf-rust-alloc"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-dep-crate" name = "solana-bpf-rust-dep-crate"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-dup-accounts" name = "solana-bpf-rust-dup-accounts"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-external-spend" name = "solana-bpf-rust-external-spend"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-iter" name = "solana-bpf-rust-iter"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-many-args" name = "solana-bpf-rust-many-args"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.23.0" } solana-bpf-rust-many-args-dep = { path = "../many_args_dep", version = "0.23.1" }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-many-args-dep" name = "solana-bpf-rust-many-args-dep"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-noop" name = "solana-bpf-rust-noop"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-panic" name = "solana-bpf-rust-panic"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-param-passing" name = "solana-bpf-rust-param-passing"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.23.0" } solana-bpf-rust-param-passing-dep = { path = "../param_passing_dep", version = "0.23.1" }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

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

View File

@ -3,7 +3,7 @@
[package] [package]
name = "solana-bpf-rust-sysval" name = "solana-bpf-rust-sysval"
version = "0.23.0" version = "0.23.1"
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 = "0.23.0", default-features = false } solana-sdk = { path = "../../../../sdk/", version = "0.23.1", default-features = false }
[dev_dependencies] [dev_dependencies]
solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.0" } solana-sdk-bpf-test = { path = "../../../../sdk/bpf/rust/test", version = "0.23.1" }
[features] [features]
program = ["solana-sdk/program"] program = ["solana-sdk/program"]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-bpf-loader-program" name = "solana-bpf-loader-program"
version = "0.23.0" version = "0.23.1"
description = "Solana BPF loader" description = "Solana BPF loader"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@ -14,8 +14,8 @@ byteorder = "1.3.2"
libc = "0.2.66" libc = "0.2.66"
log = "0.4.8" log = "0.4.8"
serde = "1.0.104" serde = "1.0.104"
solana-logger = { path = "../../logger", version = "0.23.0" } solana-logger = { path = "../../logger", version = "0.23.1" }
solana-sdk = { path = "../../sdk", version = "0.23.0" } solana-sdk = { path = "../../sdk", version = "0.23.1" }
solana_rbpf = "=0.1.19" solana_rbpf = "=0.1.19"
[lib] [lib]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-btc-spv-program" name = "solana-btc-spv-program"
version = "0.23.0" version = "0.23.1"
description = "Solana Bitcoin spv parsing program" description = "Solana Bitcoin spv parsing program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@ -16,7 +16,7 @@ num-derive = "0.3"
num-traits = "0.2" num-traits = "0.2"
serde = "1.0.104" serde = "1.0.104"
serde_derive = "1.0.103" serde_derive = "1.0.103"
solana-sdk = { path = "../../sdk", version = "0.23.0"} solana-sdk = { path = "../../sdk", version = "0.23.1"}
hex = "0.3.2" hex = "0.3.2"
[lib] [lib]

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