Compare commits

...

55 Commits

Author SHA1 Message Date
235158d2bc CLI: Expose sign-only reply parsing helper (#8107) (#8110)
automerge
2020-02-03 19:55:45 -08:00
521238f7d7 Delete uptime command, report total credits in solana validators instead
(cherry picked from commit 4c0420b884)
2020-02-03 17:15:09 -07:00
384f52a607 Fix consensus threshold when new root is created (#8093)
When a new root is created, the oldest slot is popped off
but when the logic checks for identical slots, it assumes
that any difference means a slot was popped off the front.
2020-02-03 16:54:48 -07:00
49f2d912ab Add split-stake command (#8092)
automerge
2020-02-03 11:04:21 -08:00
8652fe30ce Update book release version 2020-02-03 11:36:19 -07:00
899a14ba51 Disable windows update as windows build artifacts are turned off 2020-02-01 22:25:47 -07:00
466c7dafb3 Bump version to v0.23.2 2020-02-01 21:46:34 -07:00
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
135 changed files with 2718 additions and 1893 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.2"
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.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
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.2" }
solana-chacha = { path = "../chacha", version = "0.23.0" } solana-chacha = { path = "../chacha", version = "0.23.2" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.23.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.0" } solana-archiver-utils = { path = "../archiver-utils", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
[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.2"
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.2" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.0" } solana-chacha-sys = { path = "../chacha-sys", version = "0.23.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
[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.2"
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.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-archiver-lib = { path = "../archiver-lib", version = "0.23.0" } solana-archiver-lib = { path = "../archiver-lib", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-banking-bench" name = "solana-banking-bench"
version = "0.23.0" version = "0.23.2"
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.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2"
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.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-genesis = { path = "../genesis", version = "0.23.0" } solana-genesis = { path = "../genesis", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" } solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2" }

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

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018" edition = "2018"
name = "solana-bench-tps" name = "solana-bench-tps"
version = "0.23.0" version = "0.23.2"
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.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-genesis = { path = "../genesis", version = "0.23.0" } solana-genesis = { path = "../genesis", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.2" }
solana-librapay = { path = "../programs/librapay", version = "0.23.0", optional = true } solana-librapay = { path = "../programs/librapay", version = "0.23.2", optional = true }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2", 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.2" }
[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.2"},"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.2 [channel=unknown commit=unknown]
Blockchain, Rebuilt for Scale Blockchain, Rebuilt for Scale
USAGE: USAGE:
@ -241,7 +241,6 @@ SUBCOMMANDS:
stakes Show stake account information stakes Show stake account information
storage-account Show the contents of a storage account storage-account Show the contents of a storage account
transaction-count Get current transaction count transaction-count Get current transaction count
uptime Show the uptime of a validator, based on epoch voting history
validator-info Publish/get Validator info on Solana validator-info Publish/get Validator info on Solana
validators Show summary information about the current validators validators Show summary information about the current validators
vote-account Show the contents of a vote account vote-account Show the contents of a vote account
@ -254,7 +253,7 @@ SUBCOMMANDS:
#### solana-account #### solana-account
```text ```text
solana-account solana-account
Show the contents of an account Show the contents of an account
USAGE: USAGE:
@ -283,7 +282,7 @@ ARGS:
#### solana-address #### solana-address
```text ```text
solana-address solana-address
Get your public key Get your public key
USAGE: USAGE:
@ -307,7 +306,7 @@ OPTIONS:
#### solana-airdrop #### solana-airdrop
```text ```text
solana-airdrop solana-airdrop
Request lamports Request lamports
USAGE: USAGE:
@ -337,7 +336,7 @@ ARGS:
#### solana-authorize-nonce-account #### solana-authorize-nonce-account
```text ```text
solana-authorize-nonce-account solana-authorize-nonce-account
Assign account authority to a new entity Assign account authority to a new entity
USAGE: USAGE:
@ -373,7 +372,7 @@ ARGS:
#### solana-balance #### solana-balance
```text ```text
solana-balance solana-balance
Get your balance Get your balance
USAGE: USAGE:
@ -401,7 +400,7 @@ ARGS:
#### solana-block-production #### solana-block-production
```text ```text
solana-block-production solana-block-production
Show information about block production Show information about block production
USAGE: USAGE:
@ -428,7 +427,7 @@ OPTIONS:
#### solana-block-time #### solana-block-time
```text ```text
solana-block-time solana-block-time
Get estimated production time of a block Get estimated production time of a block
USAGE: USAGE:
@ -455,7 +454,7 @@ ARGS:
#### solana-cancel #### solana-cancel
```text ```text
solana-cancel solana-cancel
Cancel a transfer Cancel a transfer
USAGE: USAGE:
@ -482,7 +481,7 @@ ARGS:
#### solana-catchup #### solana-catchup
```text ```text
solana-catchup solana-catchup
Wait for a validator to catch up to the cluster Wait for a validator to catch up to the cluster
USAGE: USAGE:
@ -509,7 +508,7 @@ ARGS:
#### solana-claim-storage-reward #### solana-claim-storage-reward
```text ```text
solana-claim-storage-reward solana-claim-storage-reward
Redeem storage reward credits Redeem storage reward credits
USAGE: USAGE:
@ -537,7 +536,7 @@ ARGS:
#### solana-cluster-version #### solana-cluster-version
```text ```text
solana-cluster-version solana-cluster-version
Get the version of the cluster entrypoint Get the version of the cluster entrypoint
USAGE: USAGE:
@ -561,7 +560,7 @@ OPTIONS:
#### solana-config #### solana-config
```text ```text
solana-config solana-config
Solana command-line tool configuration settings Solana command-line tool configuration settings
USAGE: USAGE:
@ -590,7 +589,7 @@ SUBCOMMANDS:
#### solana-confirm #### solana-confirm
```text ```text
solana-confirm solana-confirm
Confirm transaction by signature Confirm transaction by signature
USAGE: USAGE:
@ -617,7 +616,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 derived account address with a seed Generate a derived account address with a seed
USAGE: USAGE:
@ -641,13 +640,13 @@ OPTIONS:
ARGS: ARGS:
<SEED_STRING> The seed. Must not take more than 32 bytes to encode as utf-8 <SEED_STRING> The seed. Must not take more than 32 bytes to encode as utf-8
<PROGRAM_ID> The program_id that the address will ultimately be used for, <PROGRAM_ID> The program_id that the address will ultimately be used for,
or one of STAKE, VOTE, and STORAGE keywords or one of STAKE, VOTE, and STORAGE keywords
``` ```
#### solana-create-archiver-storage-account #### solana-create-archiver-storage-account
```text ```text
solana-create-archiver-storage-account solana-create-archiver-storage-account
Create an archiver storage account Create an archiver storage account
USAGE: USAGE:
@ -669,13 +668,13 @@ OPTIONS:
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
ARGS: ARGS:
<STORAGE ACCOUNT OWNER PUBKEY> <STORAGE ACCOUNT OWNER PUBKEY>
<STORAGE ACCOUNT> <STORAGE ACCOUNT>
``` ```
#### solana-create-nonce-account #### solana-create-nonce-account
```text ```text
solana-create-nonce-account solana-create-nonce-account
Create a nonce account Create a nonce account
USAGE: USAGE:
@ -705,7 +704,7 @@ ARGS:
#### solana-create-stake-account #### solana-create-stake-account
```text ```text
solana-create-stake-account solana-create-stake-account
Create a stake account Create a stake account
USAGE: USAGE:
@ -741,7 +740,7 @@ ARGS:
#### solana-create-validator-storage-account #### solana-create-validator-storage-account
```text ```text
solana-create-validator-storage-account solana-create-validator-storage-account
Create a validator storage account Create a validator storage account
USAGE: USAGE:
@ -763,13 +762,13 @@ OPTIONS:
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
ARGS: ARGS:
<STORAGE ACCOUNT OWNER PUBKEY> <STORAGE ACCOUNT OWNER PUBKEY>
<STORAGE ACCOUNT> <STORAGE ACCOUNT>
``` ```
#### solana-create-vote-account #### solana-create-vote-account
```text ```text
solana-create-vote-account solana-create-vote-account
Create a vote account Create a vote account
USAGE: USAGE:
@ -802,7 +801,7 @@ ARGS:
#### solana-deactivate-stake #### solana-deactivate-stake
```text ```text
solana-deactivate-stake solana-deactivate-stake
Deactivate the delegated stake from the stake account Deactivate the delegated stake from the stake account
USAGE: USAGE:
@ -827,9 +826,9 @@ OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster -u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> --nonce <PUBKEY>
Provide the nonce account to use when creating a nonced Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY> --nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction Provide the nonce authority keypair to use when signing a nonced transaction
@ -843,7 +842,7 @@ ARGS:
#### solana-delegate-stake #### solana-delegate-stake
```text ```text
solana-delegate-stake solana-delegate-stake
Delegate stake to a vote account Delegate stake to a vote account
USAGE: USAGE:
@ -868,9 +867,9 @@ OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster -u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> --nonce <PUBKEY>
Provide the nonce account to use when creating a nonced Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY> --nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction Provide the nonce authority keypair to use when signing a nonced transaction
@ -885,7 +884,7 @@ ARGS:
#### solana-deploy #### solana-deploy
```text ```text
solana-deploy solana-deploy
Deploy a program Deploy a program
USAGE: USAGE:
@ -912,7 +911,7 @@ ARGS:
#### solana-epoch-info #### solana-epoch-info
```text ```text
solana-epoch-info solana-epoch-info
Get information about the current epoch Get information about the current epoch
USAGE: USAGE:
@ -937,7 +936,7 @@ OPTIONS:
#### solana-fees #### solana-fees
```text ```text
solana-fees solana-fees
Display current cluster fees Display current cluster fees
USAGE: USAGE:
@ -961,7 +960,7 @@ OPTIONS:
#### solana-genesis-hash #### solana-genesis-hash
```text ```text
solana-genesis-hash solana-genesis-hash
Get the genesis hash Get the genesis hash
USAGE: USAGE:
@ -985,7 +984,7 @@ OPTIONS:
#### solana-gossip #### solana-gossip
```text ```text
solana-gossip solana-gossip
Show the current gossip network nodes Show the current gossip network nodes
USAGE: USAGE:
@ -1009,7 +1008,7 @@ OPTIONS:
#### solana-help #### solana-help
```text ```text
solana-help solana-help
Prints this message or the help of the given subcommand(s) Prints this message or the help of the given subcommand(s)
USAGE: USAGE:
@ -1021,7 +1020,7 @@ ARGS:
#### solana-new-nonce #### solana-new-nonce
```text ```text
solana-new-nonce solana-new-nonce
Generate a new nonce, rendering the existing nonce useless Generate a new nonce, rendering the existing nonce useless
USAGE: USAGE:
@ -1053,7 +1052,7 @@ ARGS:
#### solana-nonce #### solana-nonce
```text ```text
solana-nonce solana-nonce
Get the current nonce value Get the current nonce value
USAGE: USAGE:
@ -1080,7 +1079,7 @@ ARGS:
#### solana-nonce-account #### solana-nonce-account
```text ```text
solana-nonce-account solana-nonce-account
Show the contents of a nonce account Show the contents of a nonce account
USAGE: USAGE:
@ -1108,14 +1107,14 @@ ARGS:
#### solana-pay #### solana-pay
```text ```text
solana-pay solana-pay
Send a payment Send a payment
USAGE: USAGE:
solana pay [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT> [--] [UNIT] solana pay [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT> [--] [UNIT]
FLAGS: FLAGS:
--cancelable --cancelable
-h, --help Prints help information -h, --help Prints help information
--sign-only Sign the transaction offline --sign-only Sign the transaction offline
--skip-seed-phrase-validation Skip validation of seed phrases. Use this if your phrase does not use the BIP39 --skip-seed-phrase-validation Skip validation of seed phrases. Use this if your phrase does not use the BIP39
@ -1134,9 +1133,9 @@ OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster -u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> --nonce <PUBKEY>
Provide the nonce account to use when creating a nonced Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY> --nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction Provide the nonce authority keypair to use when signing a nonced transaction
@ -1154,7 +1153,7 @@ ARGS:
#### solana-ping #### solana-ping
```text ```text
solana-ping solana-ping
Submit transactions sequentially Submit transactions sequentially
USAGE: USAGE:
@ -1183,7 +1182,7 @@ OPTIONS:
#### solana-send-signature #### solana-send-signature
```text ```text
solana-send-signature solana-send-signature
Send a signature to authorize a transfer Send a signature to authorize a transfer
USAGE: USAGE:
@ -1211,7 +1210,7 @@ ARGS:
#### solana-send-timestamp #### solana-send-timestamp
```text ```text
solana-send-timestamp solana-send-timestamp
Send a timestamp to unlock a transfer Send a timestamp to unlock a transfer
USAGE: USAGE:
@ -1240,7 +1239,7 @@ ARGS:
#### solana-show-stake-account #### solana-show-stake-account
```text ```text
solana-show-stake-account solana-show-stake-account
Show the contents of a stake account Show the contents of a stake account
USAGE: USAGE:
@ -1268,7 +1267,7 @@ ARGS:
#### solana-slot #### solana-slot
```text ```text
solana-slot solana-slot
Get current slot Get current slot
USAGE: USAGE:
@ -1293,7 +1292,7 @@ OPTIONS:
#### solana-stake-authorize-staker #### solana-stake-authorize-staker
```text ```text
solana-stake-authorize-staker solana-stake-authorize-staker
Authorize a new stake signing keypair for the given stake account Authorize a new stake signing keypair for the given stake account
USAGE: USAGE:
@ -1318,9 +1317,9 @@ OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster -u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> --nonce <PUBKEY>
Provide the nonce account to use when creating a nonced Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY> --nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction Provide the nonce authority keypair to use when signing a nonced transaction
@ -1335,7 +1334,7 @@ ARGS:
#### solana-stake-authorize-withdrawer #### solana-stake-authorize-withdrawer
```text ```text
solana-stake-authorize-withdrawer solana-stake-authorize-withdrawer
Authorize a new withdraw signing keypair for the given stake account Authorize a new withdraw signing keypair for the given stake account
USAGE: USAGE:
@ -1360,9 +1359,9 @@ OPTIONS:
-u, --url <URL> JSON RPC URL for the solana cluster -u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
--nonce <PUBKEY> --nonce <PUBKEY>
Provide the nonce account to use when creating a nonced Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY> --nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction Provide the nonce authority keypair to use when signing a nonced transaction
@ -1377,7 +1376,7 @@ ARGS:
#### solana-stake-history #### solana-stake-history
```text ```text
solana-stake-history solana-stake-history
Show the stake history Show the stake history
USAGE: USAGE:
@ -1402,7 +1401,7 @@ OPTIONS:
#### solana-stakes #### solana-stakes
```text ```text
solana-stakes solana-stakes
Show stake account information Show stake account information
USAGE: USAGE:
@ -1430,7 +1429,7 @@ ARGS:
#### solana-storage-account #### solana-storage-account
```text ```text
solana-storage-account solana-storage-account
Show the contents of a storage account Show the contents of a storage account
USAGE: USAGE:
@ -1457,7 +1456,7 @@ ARGS:
#### solana-transaction-count #### solana-transaction-count
```text ```text
solana-transaction-count solana-transaction-count
Get current transaction count Get current transaction count
USAGE: USAGE:
@ -1480,38 +1479,9 @@ OPTIONS:
-k, --keypair <PATH> /path/to/id.json -k, --keypair <PATH> /path/to/id.json
``` ```
#### solana-uptime
```text
solana-uptime
Show the uptime of a validator, based on epoch voting history
USAGE:
solana uptime [FLAGS] [OPTIONS] <VOTE ACCOUNT PUBKEY>
FLAGS:
--aggregate Aggregate uptime data across span
-h, --help Prints help information
--skip-seed-phrase-validation Skip validation of seed phrases. Use this if your phrase does not use the BIP39
official English word list
-V, --version Prints version information
-v, --verbose Show extra information header
OPTIONS:
--ask-seed-phrase <KEYPAIR NAME> Recover a keypair using a seed phrase and optional passphrase [possible
values: keypair]
-C, --config <PATH> Configuration file to use [default:
~/.config/solana/cli/config.yml]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--span <NUM OF EPOCHS> Number of recent epochs to examine
ARGS:
<VOTE ACCOUNT PUBKEY> Vote account pubkey
```
#### solana-validator-info #### solana-validator-info
```text ```text
solana-validator-info solana-validator-info
Publish/get Validator info on Solana Publish/get Validator info on Solana
USAGE: USAGE:
@ -1540,7 +1510,7 @@ SUBCOMMANDS:
#### solana-validators #### solana-validators
```text ```text
solana-validators solana-validators
Show summary information about the current validators Show summary information about the current validators
USAGE: USAGE:
@ -1565,7 +1535,7 @@ OPTIONS:
#### solana-vote-account #### solana-vote-account
```text ```text
solana-vote-account solana-vote-account
Show the contents of a vote account Show the contents of a vote account
USAGE: USAGE:
@ -1593,7 +1563,7 @@ ARGS:
#### solana-vote-authorize-voter #### solana-vote-authorize-voter
```text ```text
solana-vote-authorize-voter solana-vote-authorize-voter
Authorize a new vote signing keypair for the given vote account Authorize a new vote signing keypair for the given vote account
USAGE: USAGE:
@ -1621,7 +1591,7 @@ ARGS:
#### solana-vote-authorize-withdrawer #### solana-vote-authorize-withdrawer
```text ```text
solana-vote-authorize-withdrawer solana-vote-authorize-withdrawer
Authorize a new withdraw signing keypair for the given vote account Authorize a new withdraw signing keypair for the given vote account
USAGE: USAGE:
@ -1649,7 +1619,7 @@ ARGS:
#### solana-vote-update-validator #### solana-vote-update-validator
```text ```text
solana-vote-update-validator solana-vote-update-validator
Update the vote account's validator identity Update the vote account's validator identity
USAGE: USAGE:
@ -1678,7 +1648,7 @@ ARGS:
#### solana-withdraw-from-nonce-account #### solana-withdraw-from-nonce-account
```text ```text
solana-withdraw-from-nonce-account solana-withdraw-from-nonce-account
Withdraw lamports from the nonce account Withdraw lamports from the nonce account
USAGE: USAGE:
@ -1713,7 +1683,7 @@ ARGS:
#### solana-withdraw-stake #### solana-withdraw-stake
```text ```text
solana-withdraw-stake solana-withdraw-stake
Withdraw the unstaked lamports from the stake account Withdraw the unstaked lamports from the stake account
USAGE: USAGE:

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

@ -2,7 +2,7 @@
Follow this guide to setup Solana's key generation tool called `solana-keygen` Follow this guide to setup Solana's key generation tool called `solana-keygen`
{% hint style="warn" %} {% hint style="warn" %}
After installation, ensure your version is `0.21.1` or higher by running `solana-keygen -V` After installation, ensure your version is `0.23.1` or higher by running `solana-keygen -V`
{% endhint %} {% endhint %}
## Download ## Download

View File

@ -1,14 +1,14 @@
# Installing the Validator Software # Installing the Validator Software
Install the Solana release Install the Solana release
[v0.21.0](https://github.com/solana-labs/solana/releases/tag/v0.21.0) on your [v0.23.1](https://github.com/solana-labs/solana/releases/tag/v0.23.1) on your
machine by running: machine by running:
```bash ```bash
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.21.0/install/solana-install-init.sh | sh -s - 0.21.0 curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.23.1/install/solana-install-init.sh | sh -s - 0.23.1
``` ```
If you are connecting to a different testnet, you can replace `0.21.0` with the If you are connecting to a different testnet, you can replace `0.23.1` with the
release tag matching the software version of your desired testnet, or replace it release tag matching the software version of your desired testnet, or replace it
with the named channel `stable`, `beta`, or `edge`. with the named channel `stable`, `beta`, or `edge`.
@ -16,11 +16,11 @@ The following output indicates a successful update:
```text ```text
looking for latest release looking for latest release
downloading v0.21.0 installer downloading v0.23.1 installer
Configuration: /home/solana/.config/solana/install/config.yml Configuration: /home/solana/.config/solana/install/config.yml
Active release directory: /home/solana/.local/share/solana/install/active_release Active release directory: /home/solana/.local/share/solana/install/active_release
* Release version: 0.21.0 * Release version: 0.23.1
* Release URL: https://github.com/solana-labs/solana/releases/download/v0.21.0/solana-release-x86_64-unknown-linux-gnu.tar.bz2 * Release URL: https://github.com/solana-labs/solana/releases/download/v0.23.1/solana-release-x86_64-unknown-linux-gnu.tar.bz2
Update successful Update successful
``` ```

View File

@ -83,7 +83,6 @@ To monitor your validator during its warmup period:
* View your vote account:`solana vote-account ~/validator-vote-keypair.json` This displays the current state of all the votes the validator has submitted to the network. * View your vote account:`solana vote-account ~/validator-vote-keypair.json` This displays the current state of all the votes the validator has submitted to the network.
* View your stake account, the delegation preference and details of your stake:`solana stake-account ~/validator-stake-keypair.json` * View your stake account, the delegation preference and details of your stake:`solana stake-account ~/validator-stake-keypair.json`
* `solana uptime ~/validator-vote-keypair.json` will display the voting history \(aka, uptime\) of your validator over recent Epochs
* `solana validators` displays the current active stake of all validators, including yours * `solana validators` displays the current active stake of all validators, including yours
* `solana stake-history ` shows the history of stake warming up and cooling down over recent epochs * `solana stake-history ` shows the history of stake warming up and cooling down over recent epochs
* Look for log messages on your validator indicating your next leader slot: `[2019-09-27T20:16:00.319721164Z INFO solana_core::replay_stage] <VALIDATOR_IDENTITY_PUBKEY> voted and reset PoH at tick height ####. My next leader slot is ####` * Look for log messages on your validator indicating your next leader slot: `[2019-09-27T20:16:00.319721164Z INFO solana_core::replay_stage] <VALIDATOR_IDENTITY_PUBKEY> voted and reset PoH at tick height ####. My next leader slot is ####`

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-chacha-cuda" name = "solana-chacha-cuda"
version = "0.23.0" version = "0.23.2"
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.2" }
solana-chacha = { path = "../chacha", version = "0.23.0" } solana-chacha = { path = "../chacha", version = "0.23.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
[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.2"
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.2"
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.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
[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} \
@ -389,7 +389,7 @@ deploy() {
( (
echo "--- net.sh update" echo "--- net.sh update"
set -x set -x
time net/net.sh update -t "$CHANNEL_OR_TAG" --platform linux --platform osx --platform windows time net/net.sh update -t "$CHANNEL_OR_TAG" --platform linux --platform osx #--platform windows
) )
;; ;;
testnet-perf) testnet-perf)
@ -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.2"
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.2" }
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.2"
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.2"
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.2" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-cli-config = { path = "../cli-config", version = "0.23.2" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.2" }
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.2" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
tempfile = "3.1.0" tempfile = "3.1.0"
[[bin]] [[bin]]

View File

@ -86,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 {
@ -161,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>,
} }
@ -193,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,
@ -255,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>,
}, },
@ -266,10 +272,22 @@ 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>,
}, },
SplitStake {
stake_account_pubkey: Pubkey,
stake_authority: Option<SigningAuthority>,
sign_only: bool,
signers: Option<Vec<(Pubkey, Signature)>>,
blockhash_query: BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: Option<SigningAuthority>,
split_stake_account: KeypairEq,
seed: Option<String>,
lamports: u64,
},
ShowStakeHistory { ShowStakeHistory {
use_lamports_unit: bool, use_lamports_unit: bool,
}, },
@ -284,7 +302,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>,
}, },
@ -325,11 +343,6 @@ pub enum CliCommand {
pubkey: Pubkey, pubkey: Pubkey,
use_lamports_unit: bool, use_lamports_unit: bool,
}, },
Uptime {
pubkey: Pubkey,
aggregate: bool,
span: Option<u64>,
},
VoteAuthorize { VoteAuthorize {
vote_account_pubkey: Pubkey, vote_account_pubkey: Pubkey,
new_authorized_pubkey: Pubkey, new_authorized_pubkey: Pubkey,
@ -456,6 +469,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 {
@ -483,6 +500,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches), ("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches),
("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches), ("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches),
("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches), ("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches),
("split-stake", Some(matches)) => parse_split_stake(matches),
("stake-authorize-staker", Some(matches)) => { ("stake-authorize-staker", Some(matches)) => {
parse_stake_authorize(matches, StakeAuthorize::Staker) parse_stake_authorize(matches, StakeAuthorize::Staker)
} }
@ -516,7 +534,6 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
parse_vote_authorize(matches, VoteAuthorize::Withdrawer) parse_vote_authorize(matches, VoteAuthorize::Withdrawer)
} }
("vote-account", Some(matches)) => parse_vote_get_account_command(matches), ("vote-account", Some(matches)) => parse_vote_get_account_command(matches),
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
// Wallet Commands // Wallet Commands
("address", Some(_matches)) => Ok(CliCommandInfo { ("address", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::Address, command: CliCommand::Address,
@ -602,17 +619,13 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
let cancelable = matches.is_present("cancelable"); let cancelable = matches.is_present("cancelable");
let sign_only = matches.is_present(SIGN_ONLY_ARG.name); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(&matches, BLOCKHASH_ARG.name); 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 {
@ -624,7 +637,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,
}), }),
@ -1003,7 +1016,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 {
@ -1012,8 +1025,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())
@ -1261,6 +1273,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,
@ -1376,13 +1389,12 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
lockup, lockup,
*lamports, *lamports,
), ),
// Deactivate stake account
CliCommand::DeactivateStake { CliCommand::DeactivateStake {
stake_account_pubkey, stake_account_pubkey,
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(
@ -1392,7 +1404,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(),
), ),
@ -1403,7 +1415,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(
@ -1415,10 +1427,35 @@ 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(),
), ),
CliCommand::SplitStake {
stake_account_pubkey,
ref stake_authority,
sign_only,
ref signers,
blockhash_query,
nonce_account,
ref nonce_authority,
split_stake_account,
seed,
lamports,
} => process_split_stake(
&rpc_client,
config,
&stake_account_pubkey,
stake_authority.as_ref(),
*sign_only,
signers,
blockhash_query,
*nonce_account,
nonce_authority.as_ref(),
split_stake_account,
seed,
*lamports,
),
CliCommand::ShowStakeAccount { CliCommand::ShowStakeAccount {
pubkey: stake_account_pubkey, pubkey: stake_account_pubkey,
use_lamports_unit, use_lamports_unit,
@ -1438,7 +1475,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(
@ -1450,7 +1487,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(),
), ),
@ -1566,11 +1603,6 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&new_identity_pubkey, &new_identity_pubkey,
authorized_voter, authorized_voter,
), ),
CliCommand::Uptime {
pubkey: vote_account_pubkey,
aggregate,
span,
} => process_uptime(&rpc_client, config, &vote_account_pubkey, *aggregate, *span),
// Wallet Commands // Wallet Commands
@ -1622,7 +1654,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(
@ -1636,7 +1668,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(),
), ),
@ -2380,7 +2412,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::None(blockhash, FeeCalculator::default()),
sign_only: true, sign_only: true,
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2409,7 +2441,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),
signers: Some(vec![(key1, sig1)]), signers: Some(vec![(key1, sig1)]),
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2440,7 +2472,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),
signers: Some(vec![(key1, sig1), (key2, sig2)]), signers: Some(vec![(key1, sig1), (key2, sig2)]),
..PayCommand::default() ..PayCommand::default()
}), }),
@ -2464,7 +2496,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
@ -2491,7 +2523,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()
}), }),
@ -2522,7 +2554,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()
@ -2558,7 +2590,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)]),
@ -2762,13 +2794,30 @@ 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,
}; };
let signature = process_command(&config); let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string()); assert_eq!(signature.unwrap(), SIGNATURE.to_string());
let stake_pubkey = Pubkey::new_rand();
let split_stake_account = Keypair::new();
config.command = CliCommand::SplitStake {
stake_account_pubkey: stake_pubkey,
stake_authority: None,
sign_only: false,
signers: None,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: None,
split_stake_account: split_stake_account.into(),
seed: None,
lamports: 1234,
};
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
config.command = CliCommand::GetSlot { config.command = CliCommand::GetSlot {
commitment_config: CommitmentConfig::default(), commitment_config: CommitmentConfig::default(),
}; };
@ -2848,7 +2897,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);
@ -2875,7 +2924,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

@ -14,7 +14,7 @@ use solana_sdk::{
account_utils::StateMut, account_utils::StateMut,
clock::{self, Slot}, clock::{self, Slot},
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
epoch_schedule::{Epoch, EpochSchedule}, epoch_schedule::Epoch,
hash::Hash, hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, KeypairUtil}, signature::{Keypair, KeypairUtil},
@ -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")
@ -320,20 +321,6 @@ fn new_spinner_progress_bar() -> ProgressBar {
progress_bar progress_bar
} }
/// Aggregate epoch credit stats and return (total credits, total slots, total epochs)
pub fn aggregate_epoch_credits(
epoch_credits: &[(Epoch, u64, u64)],
epoch_schedule: &EpochSchedule,
) -> (u64, u64, u64) {
epoch_credits
.iter()
.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
})
}
pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult { pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult {
let cluster_nodes = rpc_client.get_cluster_nodes()?; let cluster_nodes = rpc_client.get_cluster_nodes()?;
@ -406,6 +393,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())
@ -864,7 +886,7 @@ pub fn process_show_stakes(
} }
pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult { pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult {
let epoch_schedule = rpc_client.get_epoch_schedule()?; let epoch_info = rpc_client.get_epoch_info()?;
let vote_accounts = rpc_client.get_vote_accounts()?; let vote_accounts = rpc_client.get_vote_accounts()?;
let total_active_stake = vote_accounts let total_active_stake = vote_accounts
.current .current
@ -913,7 +935,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
"Commission", "Commission",
"Last Vote", "Last Vote",
"Root Block", "Root Block",
"Uptime", "Credits",
"Active Stake", "Active Stake",
)) ))
.bold() .bold()
@ -921,7 +943,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
fn print_vote_account( fn print_vote_account(
vote_account: RpcVoteAccountInfo, vote_account: RpcVoteAccountInfo,
epoch_schedule: &EpochSchedule, current_epoch: Epoch,
total_active_stake: f64, total_active_stake: f64,
use_lamports_unit: bool, use_lamports_unit: bool,
delinquent: bool, delinquent: bool,
@ -934,17 +956,6 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
} }
} }
fn uptime(epoch_credits: Vec<(Epoch, u64, u64)>, epoch_schedule: &EpochSchedule) -> String {
let (total_credits, total_slots, _) =
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
if total_slots > 0 {
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
format!("{:.2}%", total_uptime)
} else {
"-".into()
}
}
println!( println!(
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}", "{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}",
if delinquent { if delinquent {
@ -957,7 +968,15 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
vote_account.commission, vote_account.commission,
non_zero_or_dash(vote_account.last_vote), non_zero_or_dash(vote_account.last_vote),
non_zero_or_dash(vote_account.root_slot), non_zero_or_dash(vote_account.root_slot),
uptime(vote_account.epoch_credits, epoch_schedule), vote_account
.epoch_credits
.iter()
.find_map(|(epoch, credits, _)| if *epoch == current_epoch {
Some(*credits)
} else {
None
})
.unwrap_or(0),
if vote_account.activated_stake > 0 { if vote_account.activated_stake > 0 {
format!( format!(
"{} ({:.2}%)", "{} ({:.2}%)",
@ -973,7 +992,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
for vote_account in vote_accounts.current.into_iter() { for vote_account in vote_accounts.current.into_iter() {
print_vote_account( print_vote_account(
vote_account, vote_account,
&epoch_schedule, epoch_info.epoch,
total_active_stake, total_active_stake,
use_lamports_unit, use_lamports_unit,
false, false,
@ -982,7 +1001,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
for vote_account in vote_accounts.delinquent.into_iter() { for vote_account in vote_accounts.delinquent.into_iter() {
print_vote_account( print_vote_account(
vote_account, vote_account,
&epoch_schedule, epoch_info.epoch,
total_active_stake, total_active_stake,
use_lamports_unit, use_lamports_unit,
true, true,

View File

@ -1,9 +1,5 @@
#[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 offline;

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

@ -234,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 {
@ -282,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 {
@ -320,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 {

View File

@ -1,8 +1,13 @@
use clap::{App, Arg}; use clap::{App, Arg, ArgMatches};
use serde_json::Value;
use solana_clap_utils::{ use solana_clap_utils::{
input_parsers::value_of,
input_validators::{is_hash, is_pubkey_sig}, input_validators::{is_hash, is_pubkey_sig},
ArgConstant, ArgConstant,
}; };
use solana_client::rpc_client::RpcClient;
use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature};
use std::str::FromStr;
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant { pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
name: "blockhash", name: "blockhash",
@ -22,6 +27,53 @@ pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
help: "Provid a public-key/signature pair for the transaction", 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> { fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name) Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long) .long(BLOCKHASH_ARG.long)
@ -61,3 +113,159 @@ impl OfflineArgs for App<'_, '_> {
.arg(signer_arg()) .arg(signer_arg())
} }
} }
pub fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) {
let object: Value = serde_json::from_str(&reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
let signers = signer_strings
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
(blockhash, signers)
}
#[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,9 +1,9 @@
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::*, offline::*,
@ -15,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},
@ -245,6 +244,55 @@ impl StakeSubCommands for App<'_, '_> {
.arg(nonce_arg()) .arg(nonce_arg())
.arg(nonce_authority_arg()) .arg(nonce_authority_arg())
) )
.subcommand(
SubCommand::with_name("split-stake")
.about("Split a stake account")
.arg(
Arg::with_name("stake_account_pubkey")
.index(1)
.value_name("STAKE ACCOUNT")
.takes_value(true)
.required(true)
.help("Stake account to be split")
)
.arg(
Arg::with_name("split_stake_account")
.index(2)
.value_name("SPLIT STAKE ACCOUNT")
.takes_value(true)
.required(true)
.validator(is_keypair_or_ask_keyword)
.help("Keypair of the new stake account to split funds into")
)
.arg(
Arg::with_name("amount")
.index(3)
.value_name("AMOUNT")
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The amount to move into the new stake account (default unit SOL)")
)
.arg(
Arg::with_name("unit")
.index(4)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request")
)
.arg(
Arg::with_name("seed")
.long("seed")
.value_name("SEED STRING")
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT STAKE ACCOUNT pubkey")
)
.arg(stake_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
)
.subcommand( .subcommand(
SubCommand::with_name("withdraw-stake") SubCommand::with_name("withdraw-stake")
.about("Withdraw the unstaked lamports from the stake account") .about("Withdraw the unstaked lamports from the stake account")
@ -286,7 +334,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(
@ -352,27 +400,13 @@ pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand
let force = matches.is_present("force"); let force = matches.is_present("force");
let sign_only = matches.is_present(SIGN_ONLY_ARG.name); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(matches, BLOCKHASH_ARG.name); 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 {
@ -382,7 +416,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,
}, },
@ -402,26 +436,12 @@ pub fn parse_stake_authorize(
}; };
let sign_only = matches.is_present(SIGN_ONLY_ARG.name); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name); 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_ARG.name);
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 {
@ -431,7 +451,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,
}, },
@ -439,31 +459,50 @@ pub fn parse_stake_authorize(
}) })
} }
pub fn parse_split_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
let split_stake_account = keypair_of(matches, "split_stake_account").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?;
let seed = matches.value_of("seed").map(|s| s.to_string());
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let require_keypair = signers.is_none();
let nonce_account = pubkey_of(&matches, NONCE_ARG.name);
let stake_authority =
SigningAuthority::new_from_matches(&matches, STAKE_AUTHORITY_ARG.name, signers.as_deref())?;
let nonce_authority =
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, signers.as_deref())?;
Ok(CliCommandInfo {
command: CliCommand::SplitStake {
stake_account_pubkey,
stake_authority,
sign_only,
signers,
blockhash_query,
nonce_account,
nonce_authority,
split_stake_account: split_stake_account.into(),
seed,
lamports,
},
require_keypair,
})
}
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_ARG.name); let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name); let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
let blockhash = value_of(matches, BLOCKHASH_ARG.name); 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 {
@ -471,7 +510,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,
}, },
@ -483,15 +522,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 {
@ -562,7 +594,7 @@ pub fn process_create_stake_account(
if lamports < minimum_balance { if lamports < minimum_balance {
return Err(CliError::BadParameter(format!( return Err(CliError::BadParameter(format!(
"need atleast {} lamports for stake account to be rent exempt, provided lamports: {}", "need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
minimum_balance, lamports minimum_balance, lamports
)) ))
.into()); .into());
@ -626,7 +658,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 {
@ -636,7 +668,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
@ -692,12 +724,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);
@ -782,10 +814,152 @@ pub fn process_withdraw_stake(
log_instruction_custom_error::<StakeError>(result) log_instruction_custom_error::<StakeError>(result)
} }
#[allow(clippy::too_many_arguments)]
pub fn process_split_stake(
rpc_client: &RpcClient,
config: &CliConfig,
stake_account_pubkey: &Pubkey,
stake_authority: Option<&SigningAuthority>,
sign_only: bool,
signers: &Option<Vec<(Pubkey, Signature)>>,
blockhash_query: &BlockhashQuery,
nonce_account: Option<Pubkey>,
nonce_authority: Option<&SigningAuthority>,
split_stake_account: &Keypair,
split_stake_account_seed: &Option<String>,
lamports: u64,
) -> ProcessResult {
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
(
&split_stake_account.pubkey(),
"split_stake_account".to_string(),
),
)?;
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
(&stake_account_pubkey, "stake_account".to_string()),
)?;
check_unique_pubkeys(
(&stake_account_pubkey, "stake_account".to_string()),
(
&split_stake_account.pubkey(),
"split_stake_account".to_string(),
),
)?;
let stake_authority = stake_authority
.map(|a| a.keypair())
.unwrap_or(&config.keypair);
let split_stake_account_address = if let Some(seed) = split_stake_account_seed {
create_address_with_seed(
&split_stake_account.pubkey(),
&seed,
&solana_stake_program::id(),
)?
} else {
split_stake_account.pubkey()
};
if let Ok(stake_account) = rpc_client.get_account(&split_stake_account_address) {
let err_msg = if stake_account.owner == solana_stake_program::id() {
format!(
"Stake account {} already exists",
split_stake_account_address
)
} else {
format!(
"Account {} already exists and is not a stake account",
split_stake_account_address
)
};
return Err(CliError::BadParameter(err_msg).into());
}
let minimum_balance =
rpc_client.get_minimum_balance_for_rent_exemption(std::mem::size_of::<StakeState>())?;
if lamports < minimum_balance {
return Err(CliError::BadParameter(format!(
"need at least {} lamports for stake account to be rent exempt, provided lamports: {}",
minimum_balance, lamports
))
.into());
}
let (recent_blockhash, fee_calculator) =
blockhash_query.get_blockhash_fee_calculator(rpc_client)?;
let ixs = if let Some(seed) = split_stake_account_seed {
stake_instruction::split_with_seed(
&stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
&split_stake_account.pubkey(),
seed,
)
} else {
stake_instruction::split(
&stake_account_pubkey,
&stake_authority.pubkey(),
lamports,
&split_stake_account_address,
)
};
let (nonce_authority, nonce_authority_pubkey) = nonce_authority
.map(|a| (a.keypair(), a.pubkey()))
.unwrap_or((&config.keypair, config.keypair.pubkey()));
let mut tx = if let Some(nonce_account) = &nonce_account {
Transaction::new_signed_with_nonce(
ixs,
Some(&config.keypair.pubkey()),
&[
&config.keypair,
nonce_authority,
stake_authority,
split_stake_account,
],
nonce_account,
&nonce_authority.pubkey(),
recent_blockhash,
)
} else {
Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair, stake_authority, split_stake_account],
recent_blockhash,
)
};
if let Some(signers) = signers {
replace_signatures(&mut tx, &signers)?;
}
if sign_only {
return_signers(&tx)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_account = rpc_client.get_account(nonce_account)?;
check_nonce_account(&nonce_account, &nonce_authority_pubkey, &recent_blockhash)?;
}
check_account_for_fee(
rpc_client,
&tx.message.account_keys[0],
&fee_calculator,
&tx.message,
)?;
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
log_instruction_custom_error::<StakeError>(result)
}
}
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);
@ -913,7 +1087,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 {
@ -966,7 +1140,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,
@ -1018,7 +1192,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) {
@ -1056,7 +1234,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,
}, },
@ -1082,7 +1260,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,
}, },
@ -1111,7 +1289,7 @@ mod tests {
authority: None, authority: None,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1142,7 +1320,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: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1175,7 +1353,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: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1201,7 +1379,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,
}, },
@ -1236,7 +1414,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()),
}, },
@ -1356,7 +1534,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,
}, },
@ -1389,7 +1567,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,
}, },
@ -1415,7 +1593,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,
}, },
@ -1444,7 +1622,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,
}, },
@ -1471,7 +1649,7 @@ mod tests {
force: false, force: false,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1503,7 +1681,7 @@ mod tests {
force: false, force: false,
sign_only: false, sign_only: false,
signers: Some(vec![(key1, sig1)]), signers: Some(vec![(key1, sig1)]),
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1537,7 +1715,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: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1611,7 +1789,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,
}, },
@ -1639,7 +1817,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,
}, },
@ -1665,7 +1843,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,
}, },
@ -1689,7 +1867,7 @@ mod tests {
stake_authority: None, stake_authority: None,
sign_only: true, sign_only: true,
signers: None, signers: None,
blockhash: Some(blockhash), blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1718,7 +1896,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: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
@ -1749,12 +1927,47 @@ 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: Some(blockhash), blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: None, nonce_account: None,
nonce_authority: None, nonce_authority: None,
}, },
require_keypair: false require_keypair: false
} }
); );
// Test SplitStake SubCommand
let (keypair_file, mut tmp_file) = make_tmp_file();
let stake_account_keypair = Keypair::new();
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
let (split_stake_account_keypair_file, mut tmp_file) = make_tmp_file();
let split_stake_account_keypair = Keypair::new();
write_keypair(&split_stake_account_keypair, tmp_file.as_file_mut()).unwrap();
let test_split_stake_account = test_commands.clone().get_matches_from(vec![
"test",
"split-stake",
&keypair_file,
&split_stake_account_keypair_file,
"50",
"lamports",
]);
assert_eq!(
parse_command(&test_split_stake_account).unwrap(),
CliCommandInfo {
command: CliCommand::SplitStake {
stake_account_pubkey: stake_account_keypair.pubkey(),
stake_authority: None,
sign_only: false,
signers: None,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: None,
split_stake_account: split_stake_account_keypair.into(),
seed: None,
lamports: 50
},
require_keypair: true
}
);
} }
} }

View File

@ -1,10 +1,6 @@
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, log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
cluster_query::aggregate_epoch_credits,
}; };
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand}; use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*}; use solana_clap_utils::{input_parsers::*, input_validators::*};
@ -176,31 +172,6 @@ impl VoteSubCommands for App<'_, '_> {
.help("Display balance in lamports instead of SOL"), .help("Display balance in lamports instead of SOL"),
), ),
) )
.subcommand(
SubCommand::with_name("uptime")
.about("Show the uptime of a validator, based on epoch voting history")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account pubkey"),
)
.arg(
Arg::with_name("span")
.long("span")
.value_name("NUM OF EPOCHS")
.takes_value(true)
.help("Number of recent epochs to examine"),
)
.arg(
Arg::with_name("aggregate")
.long("aggregate")
.help("Aggregate uptime data across span"),
),
)
} }
} }
@ -271,24 +242,6 @@ pub fn parse_vote_get_account_command(
}) })
} }
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
let aggregate = matches.is_present("aggregate");
let span = if matches.is_present("span") {
Some(value_t_or_exit!(matches, "span", u64))
} else {
None
};
Ok(CliCommandInfo {
command: CliCommand::Uptime {
pubkey: vote_account_pubkey,
aggregate,
span,
},
require_keypair: false,
})
}
pub fn process_create_vote_account( pub fn process_create_vote_account(
rpc_client: &RpcClient, rpc_client: &RpcClient,
config: &CliConfig, config: &CliConfig,
@ -517,60 +470,6 @@ pub fn process_show_vote_account(
Ok("".to_string()) Ok("".to_string())
} }
pub fn process_uptime(
rpc_client: &RpcClient,
_config: &CliConfig,
vote_account_pubkey: &Pubkey,
aggregate: bool,
span: Option<u64>,
) -> ProcessResult {
let (_vote_account, vote_state) = get_vote_account(rpc_client, vote_account_pubkey)?;
let epoch_schedule = rpc_client.get_epoch_schedule()?;
println!("validator identity: {}", vote_state.node_pubkey);
println!("authorized voter: {}", vote_state.authorized_voter);
if !vote_state.votes.is_empty() {
println!("uptime:");
let epoch_credits: Vec<(u64, u64, u64)> = if let Some(x) = span {
vote_state
.epoch_credits()
.iter()
.rev()
.take(x as usize)
.cloned()
.collect()
} else {
vote_state.epoch_credits().iter().rev().cloned().collect()
};
if aggregate {
let (total_credits, total_slots, epochs) =
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
if total_slots > 0 {
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
println!("{:.2}% over {} epochs", total_uptime, epochs);
} else {
println!("Insufficient voting history available");
}
} else {
for (epoch, credits, prev_credits) in epoch_credits {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
let uptime = credits_earned as f64 / slots_in_epoch as f64;
println!("- epoch: {} {:.2}% uptime", epoch, uptime * 100_f64,);
}
}
if let Some(x) = span {
if x > vote_state.epoch_credits().len() as u64 {
println!("(span longer than available epochs)");
}
}
}
Ok("".to_string())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -741,27 +640,5 @@ mod tests {
require_keypair: true require_keypair: true
} }
); );
// Test Uptime Subcommand
let pubkey = Pubkey::new_rand();
let matches = test_commands.clone().get_matches_from(vec![
"test",
"uptime",
&pubkey.to_string(),
"--span",
"4",
"--aggregate",
]);
assert_eq!(
parse_command(&matches).unwrap(),
CliCommandInfo {
command: CliCommand::Uptime {
pubkey,
aggregate: true,
span: Some(4)
},
require_keypair: false
}
);
} }
} }

View File

@ -1,19 +1,19 @@
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::{parse_sign_only_reply_string, 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,
hash::Hash, fee_calculator::FeeCalculator,
nonce_state::NonceState, nonce_state::NonceState,
pubkey::Pubkey, pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature}, signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
}; };
use std::fs::remove_dir_all; use std::fs::remove_dir_all;
use std::str::FromStr;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
#[cfg(test)] #[cfg(test)]
@ -289,9 +289,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()
}); });
@ -301,24 +303,12 @@ fn test_offline_pay_tx() {
check_balance(50, &rpc_client, &config_online.keypair.pubkey()); check_balance(50, &rpc_client, &config_online.keypair.pubkey());
check_balance(0, &rpc_client, &bob_pubkey); check_balance(0, &rpc_client, &bob_pubkey);
let object: Value = serde_json::from_str(&sig_response).unwrap(); let (blockhash, signers) = parse_sign_only_reply_string(&sig_response);
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
let signers: Vec<_> = signer_strings
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
config_online.command = CliCommand::Pay(PayCommand { config_online.command = CliCommand::Pay(PayCommand {
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),
..PayCommand::default() ..PayCommand::default()
}); });
process_command(&config_online).unwrap(); process_command(&config_online).unwrap();
@ -389,7 +379,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,18 +1,19 @@
use serde_json::Value; use solana_cli::{
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig}; cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
offline::{parse_sign_only_reply_string, 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,
hash::Hash, fee_calculator::FeeCalculator,
nonce_state::NonceState, nonce_state::NonceState,
pubkey::Pubkey, pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil, Signature}, signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
system_instruction::create_address_with_seed, system_instruction::create_address_with_seed,
}; };
use solana_stake_program::stake_state::{Lockup, StakeAuthorize, StakeState}; use solana_stake_program::stake_state::{Lockup, StakeAuthorize, StakeState};
use std::fs::remove_dir_all; use std::fs::remove_dir_all;
use std::str::FromStr;
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
#[cfg(test)] #[cfg(test)]
@ -40,23 +41,6 @@ fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
}); });
} }
fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) {
let object: Value = serde_json::from_str(&reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let signer_strings = object.get("signers").unwrap().as_array().unwrap();
let signers = signer_strings
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
(blockhash, signers)
}
#[test] #[test]
fn test_seed_stake_delegation_and_deactivation() { fn test_seed_stake_delegation_and_deactivation() {
solana_logger::setup(); solana_logger::setup();
@ -132,7 +116,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 +128,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 +204,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 +216,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 +289,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 +297,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 +312,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 +338,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 +425,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 +446,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 +500,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 +525,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 +543,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 +551,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 +564,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 +612,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 +626,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.2"
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.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
[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.2" }

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.2"
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.2" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.0" } solana-clap-utils = { path = "../clap-utils", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.2" }
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.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" } solana-merkle-tree = { path = "../merkle-tree", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.0" } solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.0" } solana-vote-signer = { path = "../vote-signer", version = "0.23.2" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.0" } solana-sys-tuner = { path = "../sys-tuner", version = "0.23.2" }
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.2" }
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

@ -327,21 +327,16 @@ impl Tower {
fork_stake.stake, fork_stake.stake,
total_staked total_staked
); );
for (new_lockout, original_lockout) in if vote.confirmation_count as usize > self.threshold_depth {
lockouts.votes.iter().zip(self.lockouts.votes.iter()) for old_vote in &self.lockouts.votes {
{ if old_vote.slot == vote.slot
if new_lockout.slot == original_lockout.slot { && old_vote.confirmation_count == vote.confirmation_count
if new_lockout.confirmation_count <= self.threshold_depth as u32 { {
break; return true;
} }
if new_lockout.confirmation_count != original_lockout.confirmation_count {
return lockout > self.threshold_size;
}
} else {
break;
} }
} }
true lockout > self.threshold_size
} else { } else {
false false
} }
@ -556,6 +551,24 @@ mod test {
assert!(tower.check_vote_stake_threshold(0, &stakes, 2)); assert!(tower.check_vote_stake_threshold(0, &stakes, 2));
} }
#[test]
fn test_check_vote_threshold_no_skip_lockout_with_new_root() {
solana_logger::setup();
let mut tower = Tower::new_for_tests(4, 0.67);
let mut stakes = HashMap::new();
for i in 0..(MAX_LOCKOUT_HISTORY as u64 + 1) {
stakes.insert(
i,
StakeLockout {
stake: 1,
lockout: 8,
},
);
tower.record_vote(i, Hash::default());
}
assert!(!tower.check_vote_stake_threshold(MAX_LOCKOUT_HISTORY as u64 + 1, &stakes, 2));
}
#[test] #[test]
fn test_is_slot_confirmed_not_enough_stake_failure() { fn test_is_slot_confirmed_not_enough_stake_failure() {
let tower = Tower::new_for_tests(1, 0.67); let tower = Tower::new_for_tests(1, 0.67);

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

@ -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

@ -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

@ -56,12 +56,14 @@ 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,
@ -77,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,
@ -84,6 +87,7 @@ 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,
enable_partition: None, enable_partition: None,
@ -114,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>>,
@ -126,7 +129,6 @@ pub struct Validator {
} }
impl Validator { impl Validator {
#[allow(clippy::cognitive_complexity)]
pub fn new( pub fn new(
mut node: Node, mut node: Node,
keypair: &Arc<Keypair>, keypair: &Arc<Keypair>,
@ -194,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(),
@ -207,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 {
@ -305,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
@ -366,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(),
@ -408,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,
@ -459,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 {
@ -563,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};
@ -586,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,
@ -688,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),
@ -722,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.2"
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.2"
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.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2"
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.2" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" } solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
solana-vest-program = { path = "../programs/vest", version = "0.23.0" } solana-vest-program = { path = "../programs/vest", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
[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.2"
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.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" } solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
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 {

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.2"
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.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-net-utils = { path = "../net-utils", version = "0.23.0" } solana-net-utils = { path = "../net-utils", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }

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.2"
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.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2"
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.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-cli-config = { path = "../cli-config", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.2" }
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.2"
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.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
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.2"
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.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" } solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-measure = { path = "../measure", version = "0.23.0" } solana-measure = { path = "../measure", version = "0.23.2" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.0" } solana-merkle-tree = { path = "../merkle-tree", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
solana-perf = { path = "../perf", version = "0.23.0" } solana-perf = { path = "../perf", version = "0.23.2" }
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.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
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.2" }
[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

@ -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())?,
"0.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.2"
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.2" }
solana-config-program = { path = "../programs/config", version = "0.23.0" } solana-config-program = { path = "../programs/config", version = "0.23.2" }
solana-core = { path = "../core", version = "0.23.0" } solana-core = { path = "../core", version = "0.23.2" }
solana-client = { path = "../client", version = "0.23.0" } solana-client = { path = "../client", version = "0.23.2" }
solana-faucet = { path = "../faucet", version = "0.23.0" } solana-faucet = { path = "../faucet", version = "0.23.2" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.0" } solana-exchange-program = { path = "../programs/exchange", version = "0.23.2" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.23.0" } solana-genesis-programs = { path = "../genesis-programs", version = "0.23.2" }
solana-ledger = { path = "../ledger", version = "0.23.0" } solana-ledger = { path = "../ledger", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-runtime = { path = "../runtime", version = "0.23.0" } solana-runtime = { path = "../runtime", version = "0.23.2" }
solana-sdk = { path = "../sdk", version = "0.23.0" } solana-sdk = { path = "../sdk", version = "0.23.2" }
solana-stake-program = { path = "../programs/stake", version = "0.23.0" } solana-stake-program = { path = "../programs/stake", version = "0.23.2" }
solana-storage-program = { path = "../programs/storage", version = "0.23.0" } solana-storage-program = { path = "../programs/storage", version = "0.23.2" }
solana-vest-program = { path = "../programs/vest", version = "0.23.0" } solana-vest-program = { path = "../programs/vest", version = "0.23.2" }
solana-vote-program = { path = "../programs/vote", version = "0.23.0" } solana-vote-program = { path = "../programs/vote", version = "0.23.2" }
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.2" }
[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

@ -662,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.2"
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.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
[[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.2"
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.2"
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.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
[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.2"
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.2" }
[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.2"
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.2" }
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.2"
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.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
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.2"
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.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
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

@ -1,6 +1,6 @@
[package] [package]
name = "solana-perf" name = "solana-perf"
version = "0.23.0" version = "0.23.2"
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.2" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.0" } solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.2" }
solana-budget-program = { path = "../programs/budget", version = "0.23.0" } solana-budget-program = { path = "../programs/budget", version = "0.23.2" }
solana-logger = { path = "../logger", version = "0.23.0" } solana-logger = { path = "../logger", version = "0.23.2" }
solana-metrics = { path = "../metrics", version = "0.23.0" } solana-metrics = { path = "../metrics", version = "0.23.2" }
[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.2"
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.2" }
solana-logger = { path = "../../logger", version = "0.23.0" } solana-logger = { path = "../../logger", version = "0.23.2" }
solana-runtime = { path = "../../runtime", version = "0.23.0" } solana-runtime = { path = "../../runtime", version = "0.23.2" }
solana-sdk = { path = "../../sdk", version = "0.23.0" } solana-sdk = { path = "../../sdk", version = "0.23.2" }
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.2"
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.2", 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.2" }
[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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2", 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.2" }
[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.2"
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.2" }
solana-sdk = { path = "../../sdk", version = "0.23.0" } solana-sdk = { path = "../../sdk", version = "0.23.2" }
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.2"
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.2"}
hex = "0.3.2" hex = "0.3.2"
[lib] [lib]

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "solana-budget-program" name = "solana-budget-program"
version = "0.23.0" version = "0.23.2"
description = "Solana Budget program" description = "Solana Budget program"
authors = ["Solana Maintainers <maintainers@solana.com>"] authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana" repository = "https://github.com/solana-labs/solana"
@ -16,11 +16,11 @@ num-derive = "0.3"
num-traits = "0.2" num-traits = "0.2"
serde = "1.0.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.2" }
thiserror = "1.0" thiserror = "1.0"
[dev-dependencies] [dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.23.0" } solana-runtime = { path = "../../runtime", version = "0.23.2" }
[lib] [lib]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]

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