Compare commits

...

33 Commits

Author SHA1 Message Date
45612bc988 \ 2020-02-21 18:10:11 -07:00
51ce98badd Add --enable-warmup-epochs flag
(cherry picked from commit ea5b00364f)
2020-02-21 17:03:35 -07:00
075e784bef Promote some datapoints to info to fix dashboard (#8381)
automerge

(cherry picked from commit aa80f69171)
2020-02-21 17:00:42 -07:00
c1b587c6e4 4x DEFAULT_MAX_LEDGER_SLOTS to give nodes 3 hours of slots to repair from (#8388)
automerge

(cherry picked from commit fb98df76b7)
2020-02-21 17:00:35 -07:00
94e2d0b5c2 Update unlocks (bp #8363) (#8382)
automerge
2020-02-21 11:40:27 -08:00
c2be9fdf0e Add handling for fallible signers (#8367) (#8374)
automerge
2020-02-21 01:45:13 -08:00
c2b17c7d3f Correct missing entry handling to avoid bad warns (bp #8339) (#8378)
automerge
2020-02-20 23:35:21 -08:00
31544f2a82 If the node was loaded from a snapshot, advertise it in gossip (#8364) (#8373)
automerge
2020-02-20 19:57:43 -08:00
3a88190e4e Enable BPF in TdS epoch 17 (#8370)
automerge
2020-02-20 18:11:58 -08:00
3f30354d1a Add non-bz2 snapshot for faster creation for dev. (#8350)
* Add non-bz2 snapshot for faster creation for dev.

* Fix tests..

* Revert and always just use snapshot.tar.bz2

(cherry picked from commit 5ef06a9d36)
2020-02-20 18:51:16 -07:00
11f15c0708 Flip Stable and Preview enum values
(cherry picked from commit 2d665da3e1)
2020-02-20 18:29:04 -07:00
a83bf85bb3 Search for the validator with the highest snapshot (#8368)
automerge
2020-02-20 17:24:23 -08:00
02877814fa Rename KeypairUtil to Signer (#8360) (#8366)
automerge
2020-02-20 16:30:43 -08:00
29cdfd6bc9 Book: Add instructions for verifying a paper wallet keypair (#8357) (#8365)
automerge
2020-02-20 14:33:18 -08:00
9dffc3abe4 Support transaction signing by heterogenous lists of keypairs (bp #8342) (#8362)
automerge
2020-02-20 14:02:14 -08:00
b4eb81546e Snapshot hash gossip changes (#8358) (#8359)
automerge
2020-02-20 12:52:04 -08:00
489fd3058f Do not compress small incomplete slot list (#8355) (#8356)
automerge
2020-02-20 10:48:47 -08:00
e5872ef1c1 Bitwise compress incomplete epoch slots (#8341) 2020-02-20 05:49:17 -08:00
cb9d18316a Update epoch slots to include all missing slots (#8276)
* Update epoch slots to include all missing slots

* new test for compress/decompress

* address review comments

* limit cache based on size, instead of comparing roots
2020-02-20 05:49:17 -08:00
c3ac85828b Process Gossip in parallel and add an upper limit (#8328) (#8345)
automerge
2020-02-19 21:54:52 -08:00
5fbddd5894 Add Preview operating mode, rename SoftLaunch operating mode to Stable (#8331) (#8340)
automerge
2020-02-19 18:13:41 -08:00
90af35737d Use correct static IP address 2020-02-19 18:15:54 -07:00
58cb21402b Remove validators from genesis (#8330) (#8333)
automerge
2020-02-19 15:42:25 -08:00
824b894977 More testnet->devnet 2020-02-19 16:15:58 -07:00
2295a5e512 Update README.md 2020-02-19 15:53:17 -07:00
83a322a211 rename testnet.solana.com to devnet.solana.com
(cherry picked from commit e3cebcf82d)

# Conflicts:
#	README.md
2020-02-19 15:53:17 -07:00
a008748d9d grooming: use cleanup, remove some dead code (bp #8324) (#8326)
automerge
2020-02-18 21:06:56 -08:00
72cb0b7c9e Add --fee-burn-percentage (#8323)
automerge
2020-02-18 19:03:41 -08:00
ede3781f91 Just define BnakSlotDelta type alias (bp #8186) (#8320)
automerge
2020-02-18 16:31:38 -08:00
e3ac6fac1e Factor out creating genesis with vote accounts into a utility function (bp #8315) (#8317)
automerge
2020-02-18 13:12:53 -08:00
e30561f8a0 CLI: Add optional airdrop recipient (#8291) (#8310)
automerge
2020-02-16 11:32:06 -08:00
8d59bef561 Cli: Remove units from various subcommands (#8301) (#8306)
automerge
2020-02-15 12:45:02 -08:00
897e1fc5d6 Bump version to 0.23.6 2020-02-14 22:38:14 -07:00
230 changed files with 3158 additions and 2200 deletions

682
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -126,10 +126,7 @@ Remote Testnets
---
We maintain several testnets:
* `testnet` - public stable testnet accessible via testnet.solana.com. Runs 24/7
* `testnet-beta` - public beta channel testnet accessible via beta.testnet.solana.com. Runs 24/7
* `testnet-edge` - public edge channel testnet accessible via edge.testnet.solana.com. Runs 24/7
* `testnet` - public stable testnet accessible via devnet.solana.com. Runs 24/7
## Deploy process

View File

@ -140,9 +140,9 @@ TODO: Documentation update procedure is WIP as we move to gitbook
Document the new recommended version by updating `book/src/running-archiver.md` and `book/src/validator-testnet.md` on the release (beta) branch to point at the `solana-install` for the upcoming release version.
### Update software on testnet.solana.com
### Update software on devnet.solana.com
The testnet running on testnet.solana.com is set to use a fixed release tag
The testnet running on devnet.solana.com is set to use a fixed release tag
which is set in the Buildkite testnet-management pipeline.
This tag needs to be updated and the testnet restarted after a new release
tag is created.
@ -182,4 +182,4 @@ TESTNET_OP=create-and-start
### Alert the community
Notify Discord users on #validator-support that a new release for
testnet.solana.com is available
devnet.solana.com is available

View File

@ -1,6 +1,6 @@
[package]
name = "solana-archiver-lib"
version = "0.23.5"
version = "0.23.6"
description = "Solana Archiver Library"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -15,22 +15,22 @@ ed25519-dalek = "=1.0.0-pre.1"
log = "0.4.8"
rand = "0.6.5"
rand_chacha = "0.1.1"
solana-client = { path = "../client", version = "0.23.5" }
solana-storage-program = { path = "../programs/storage", version = "0.23.5" }
solana-client = { path = "../client", version = "0.23.6" }
solana-storage-program = { path = "../programs/storage", version = "0.23.6" }
thiserror = "1.0"
serde = "1.0.104"
serde_json = "1.0.44"
serde_derive = "1.0.103"
solana-net-utils = { path = "../net-utils", version = "0.23.5" }
solana-chacha = { path = "../chacha", version = "0.23.5" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.5" }
solana-ledger = { path = "../ledger", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.5" }
solana-perf = { path = "../perf", version = "0.23.5" }
solana-sdk = { path = "../sdk", version = "0.23.5" }
solana-core = { path = "../core", version = "0.23.5" }
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.5" }
solana-metrics = { path = "../metrics", version = "0.23.5" }
solana-net-utils = { path = "../net-utils", version = "0.23.6" }
solana-chacha = { path = "../chacha", version = "0.23.6" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.23.6" }
solana-ledger = { path = "../ledger", version = "0.23.6" }
solana-logger = { path = "../logger", version = "0.23.6" }
solana-perf = { path = "../perf", version = "0.23.6" }
solana-sdk = { path = "../sdk", version = "0.23.6" }
solana-core = { path = "../core", version = "0.23.6" }
solana-archiver-utils = { path = "../archiver-utils", version = "0.23.6" }
solana-metrics = { path = "../metrics", version = "0.23.6" }
[dev-dependencies]
hex = "0.4.0"

View File

@ -36,7 +36,7 @@ use solana_sdk::{
commitment_config::CommitmentConfig,
hash::Hash,
message::Message,
signature::{Keypair, KeypairUtil, Signature},
signature::{Keypair, Signature, Signer},
timing::timestamp,
transaction::Transaction,
transport::TransportError,
@ -384,7 +384,7 @@ impl Archiver {
);
let message =
Message::new_with_payer(vec![ix], Some(&archiver_keypair.pubkey()));
if let Err(e) = client.send_message(&[&archiver_keypair], message) {
if let Err(e) = client.send_message(&[archiver_keypair.as_ref()], message) {
error!("unable to redeem reward, tx failed: {:?}", e);
} else {
info!(
@ -671,7 +671,7 @@ impl Archiver {
blockhash,
);
if let Err(err) = client.send_and_confirm_transaction(
&[&archiver_keypair, &storage_keypair],
&[archiver_keypair.as_ref(), storage_keypair.as_ref()],
&mut transaction,
10,
0,

View File

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

View File

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

View File

@ -12,7 +12,7 @@ use solana_core::{
cluster_info::{Node, VALIDATOR_PORT_RANGE},
contact_info::ContactInfo,
};
use solana_sdk::{commitment_config::CommitmentConfig, signature::KeypairUtil};
use solana_sdk::{commitment_config::CommitmentConfig, signature::Signer};
use std::{net::SocketAddr, path::PathBuf, process::exit, sync::Arc};
fn main() {

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "0.23.5"
version = "0.23.6"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -10,11 +10,11 @@ homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.2.0"
solana-core = { path = "../core", version = "0.23.5" }
solana-ledger = { path = "../ledger", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.5" }
solana-runtime = { path = "../runtime", version = "0.23.5" }
solana-measure = { path = "../measure", version = "0.23.5" }
solana-sdk = { path = "../sdk", version = "0.23.5" }
solana-core = { path = "../core", version = "0.23.6" }
solana-ledger = { path = "../ledger", version = "0.23.6" }
solana-logger = { path = "../logger", version = "0.23.6" }
solana-runtime = { path = "../runtime", version = "0.23.6" }
solana-measure = { path = "../measure", version = "0.23.6" }
solana-sdk = { path = "../sdk", version = "0.23.6" }
rand = "0.6.5"
crossbeam-channel = "0.3"

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "0.23.5"
version = "0.23.6"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -23,19 +23,19 @@ serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.23.5" }
solana-core = { path = "../core", version = "0.23.5" }
solana-genesis = { path = "../genesis", version = "0.23.5" }
solana-client = { path = "../client", version = "0.23.5" }
solana-faucet = { path = "../faucet", version = "0.23.5" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.5" }
solana-metrics = { path = "../metrics", version = "0.23.5" }
solana-net-utils = { path = "../net-utils", version = "0.23.5" }
solana-runtime = { path = "../runtime", version = "0.23.5" }
solana-sdk = { path = "../sdk", version = "0.23.5" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.6" }
solana-core = { path = "../core", version = "0.23.6" }
solana-genesis = { path = "../genesis", version = "0.23.6" }
solana-client = { path = "../client", version = "0.23.6" }
solana-faucet = { path = "../faucet", version = "0.23.6" }
solana-exchange-program = { path = "../programs/exchange", version = "0.23.6" }
solana-logger = { path = "../logger", version = "0.23.6" }
solana-metrics = { path = "../metrics", version = "0.23.6" }
solana-net-utils = { path = "../net-utils", version = "0.23.6" }
solana-runtime = { path = "../runtime", version = "0.23.6" }
solana-sdk = { path = "../sdk", version = "0.23.6" }
untrusted = "0.7.0"
ws = "0.9.1"
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "0.23.5" }
solana-local-cluster = { path = "../local-cluster", version = "0.23.6" }

View File

@ -15,7 +15,7 @@ use solana_sdk::{
client::{Client, SyncClient},
commitment_config::CommitmentConfig,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
timing::{duration_as_ms, duration_as_s},
transaction::Transaction,
{system_instruction, system_program},
@ -701,7 +701,7 @@ fn verify_funding_transfer<T: SyncClient + ?Sized>(
false
}
pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>], lamports: u64) {
pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>], lamports: u64) {
let total = lamports * (dests.len() as u64 + 1);
let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)];
let mut notfunded: Vec<&Arc<Keypair>> = dests.iter().collect();
@ -824,7 +824,11 @@ pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>],
}
}
pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], accounts: &[Keypair]) {
pub fn create_token_accounts<T: Client>(
client: &T,
signers: &[Arc<Keypair>],
accounts: &[Keypair],
) {
let mut notfunded: Vec<(&Arc<Keypair>, &Keypair)> = signers.iter().zip(accounts).collect();
while !notfunded.is_empty() {
@ -968,7 +972,12 @@ fn generate_keypairs(num: u64) -> Vec<Keypair> {
rnd.gen_n_keypairs(num)
}
pub fn airdrop_lamports(client: &dyn Client, faucet_addr: &SocketAddr, id: &Keypair, amount: u64) {
pub fn airdrop_lamports<T: Client>(
client: &T,
faucet_addr: &SocketAddr,
id: &Keypair,
amount: u64,
) {
let balance = client.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent());
let balance = balance.unwrap_or(0);
if balance >= amount {

View File

@ -5,7 +5,7 @@ pub mod order_book;
use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config};
use log::*;
use solana_core::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::signature::KeypairUtil;
use solana_sdk::signature::Signer;
fn main() {
solana_logger::setup();

View File

@ -10,7 +10,7 @@ use solana_local_cluster::local_cluster::{ClusterConfig, LocalCluster};
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::genesis_config::create_genesis_config;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::process::exit;
use std::sync::mpsc::channel;
use std::time::Duration;

View File

@ -2,14 +2,14 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "0.23.5"
version = "0.23.6"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "0.23.5" }
solana-core = { path = "../core", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.5" }
solana-net-utils = { path = "../net-utils", version = "0.23.5" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.6" }
solana-core = { path = "../core", version = "0.23.6" }
solana-logger = { path = "../logger", version = "0.23.6" }
solana-net-utils = { path = "../net-utils", version = "0.23.6" }

View File

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

View File

@ -7,7 +7,7 @@ use solana_faucet::faucet::request_airdrop_transaction;
#[cfg(feature = "move")]
use solana_librapay::{create_genesis, upload_mint_script, upload_payment_script};
use solana_measure::measure::Measure;
use solana_metrics::{self, datapoint_debug};
use solana_metrics::{self, datapoint_info};
use solana_sdk::{
client::Client,
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE},
@ -15,7 +15,7 @@ use solana_sdk::{
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_instruction, system_transaction,
timing::{duration_as_ms, duration_as_s, duration_as_us, timestamp},
transaction::Transaction,
@ -244,7 +244,7 @@ where
fn metrics_submit_lamport_balance(lamport_balance: u64) {
info!("Token balance: {}", lamport_balance);
datapoint_debug!(
datapoint_info!(
"bench-tps-lamport_balance",
("balance", lamport_balance, i64)
);
@ -375,7 +375,7 @@ fn generate_txs(
duration_as_ms(&duration),
blockhash,
);
datapoint_debug!(
datapoint_info!(
"bench-tps-generate_txs",
("duration", duration_as_us(&duration), i64)
);
@ -481,7 +481,7 @@ fn do_tx_transfers<T: Client>(
duration_as_ms(&transfer_start.elapsed()),
tx_len as f32 / duration_as_s(&transfer_start.elapsed()),
);
datapoint_debug!(
datapoint_info!(
"bench-tps-do_tx_transfers",
("duration", duration_as_us(&transfer_start.elapsed()), i64),
("count", tx_len, i64)

View File

@ -4,7 +4,7 @@ use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
use solana_genesis::Base64Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_program;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};

View File

@ -8,7 +8,7 @@ use solana_faucet::faucet::run_local_faucet;
use solana_local_cluster::local_cluster::{ClusterConfig, LocalCluster};
#[cfg(feature = "move")]
use solana_sdk::move_loader::solana_move_loader_program;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::sync::{mpsc::channel, Arc};
use std::time::Duration;

View File

@ -830,7 +830,7 @@ The result field will be a JSON object with the following fields:
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"solana-core": "0.23.5"},"id":1}
{"jsonrpc":"2.0","result":{"solana-core": "0.23.6"},"id":1}
```
### getVoteAccounts

View File

@ -154,7 +154,7 @@ The stream will output a series of JSON objects:
In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports `8000-10000`.
```bash
$ NDEBUG=1 ./multinode-demo/bench-tps.sh --entrypoint testnet.solana.com:8001 --faucet testnet.solana.com:9900 --duration 60 --tx_count 50
$ NDEBUG=1 ./multinode-demo/bench-tps.sh --entrypoint devnet.solana.com:8001 --faucet devnet.solana.com:9900 --duration 60 --tx_count 50
```
You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)

View File

@ -22,12 +22,6 @@ $ solana airdrop 2
// Return
"2.00000000 SOL"
// Command
$ solana airdrop 123 --lamports
// Return
"123 lamports"
```
### Get Balance

View File

@ -177,7 +177,7 @@ $ solana send-timestamp <PUBKEY> <PROCESS_ID> --date 2018-12-24T23:59:00
## Usage
### solana-cli
```text
solana-cli 0.23.5 [channel=unknown commit=unknown]
solana-cli 0.23.6 [channel=unknown commit=unknown]
Blockchain, Rebuilt for Scale
USAGE:
@ -191,12 +191,17 @@ FLAGS:
-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
--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]
--derivation-path <ACCOUNT or ACCOUNT/CHANGE>
Derivation path to use: m/44'/501'/ACCOUNT'/CHANGE'; default key is device base pubkey: m/44'/501'/0'
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
SUBCOMMANDS:
account Show the contents of an account
@ -226,6 +231,8 @@ SUBCOMMANDS:
genesis-hash Get the genesis hash
gossip Show the current gossip network nodes
help Prints this message or the help of the given subcommand(s)
leader-schedule Display leader schedule
live-slots Show information about the current slot progression
new-nonce Generate a new nonce, rendering the existing nonce useless
nonce Get the current nonce value
nonce-account Show the contents of a nonce account
@ -233,14 +240,17 @@ SUBCOMMANDS:
ping Submit transactions sequentially
send-signature Send a signature to authorize a transfer
send-timestamp Send a timestamp to unlock a transfer
show-stake-account Show the contents of a stake account
slot Get current slot
split-stake Split a stake account
stake-account Show the contents of a stake account
stake-authorize-staker Authorize a new stake signing keypair for the given stake account
stake-authorize-withdrawer Authorize a new withdraw signing keypair for the given stake account
stake-history Show the stake history
stake-set-lockup Set Lockup for the stake account
stakes Show stake account information
storage-account Show the contents of a storage account
transaction-count Get current transaction count
transfer Transfer funds between system accounts
validator-info Publish/get Validator info on Solana
validators Show summary information about the current validators
vote-account Show the contents of a vote account
@ -273,7 +283,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
-o, --output <FILE> Write the account data to this file
ARGS:
@ -301,7 +311,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-airdrop
@ -310,7 +320,7 @@ solana-airdrop
Request lamports
USAGE:
solana airdrop [FLAGS] [OPTIONS] <AMOUNT> [UNIT]
solana airdrop [FLAGS] [OPTIONS] <AMOUNT> [PUBKEY]
FLAGS:
-h, --help Prints help information
@ -327,11 +337,11 @@ OPTIONS:
--faucet-host <HOST> Faucet host to use [default: the --url host]
--faucet-port <PORT> Faucet port to use [default: 9900]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<AMOUNT> The airdrop amount to request (default unit SOL)
<UNIT> Specify unit to use for request and balance display [possible values: SOL, lamports]
<AMOUNT> The airdrop amount to request, in SOL
<PUBKEY> The pubkey of airdrop recipient
```
#### solana-authorize-nonce-account
@ -357,7 +367,7 @@ OPTIONS:
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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
@ -392,7 +402,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PUBKEY> The public key of the balance to check
@ -420,7 +430,7 @@ OPTIONS:
~/.config/solana/cli/config.yml]
--epoch <epoch> Epoch to show block production for [default: current epoch]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--slot-limit <slot_limit> Limit results to this many slots from the end of the epoch [default: full
epoch]
```
@ -446,7 +456,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<SLOT> Slot number of the block to query
@ -473,7 +483,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PROCESS ID> The process id of the transfer to cancel
@ -500,7 +510,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PUBKEY> Identity pubkey of the validator
@ -527,7 +537,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<NODE PUBKEY> The node account to credit the rewards to
@ -555,7 +565,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-config
@ -579,7 +589,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
SUBCOMMANDS:
get Get current config settings
@ -608,7 +618,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<SIGNATURE> The transaction signature to confirm
@ -636,7 +646,7 @@ OPTIONS:
~/.config/solana/cli/config.yml]
--from <PUBKEY> From (base) key, defaults to client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<SEED_STRING> The seed. Must not take more than 32 bytes to encode as utf-8
@ -665,7 +675,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<STORAGE ACCOUNT OWNER PUBKEY>
@ -678,7 +688,7 @@ solana-create-nonce-account
Create a nonce account
USAGE:
solana create-nonce-account [FLAGS] [OPTIONS] <NONCE ACCOUNT> <AMOUNT> [UNIT]
solana create-nonce-account [FLAGS] [OPTIONS] <NONCE ACCOUNT> <AMOUNT>
FLAGS:
-h, --help Prints help information
@ -693,13 +703,12 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce-authority <BASE58_PUBKEY> Assign noncing authority to another entity
ARGS:
<NONCE ACCOUNT> Keypair of the nonce account to fund
<AMOUNT> The amount to load the nonce account with (default unit SOL)
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
<AMOUNT> The amount to load the nonce account with, in SOL
```
#### solana-create-stake-account
@ -708,34 +717,56 @@ solana-create-stake-account
Create a stake account
USAGE:
solana create-stake-account [FLAGS] [OPTIONS] <STAKE ACCOUNT> <AMOUNT> [UNIT]
solana create-stake-account [FLAGS] [OPTIONS] <STAKE ACCOUNT> <AMOUNT>
FLAGS:
-h, --help Prints help information
--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
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]
--custodian <PUBKEY> Identity of the custodian (can withdraw before lockup expires)
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
--lockup-date <RFC3339 DATE TIME> The date and time at which this account will be available for withdrawal
--lockup-epoch <EPOCH> The epoch height at which this account will be available for withdrawal
--seed <SEED STRING> Seed for address generation; if specified, the resulting account will be at
a derived address of the STAKE ACCOUNT pubkey
--stake-authority <PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
--withdraw-authority <PUBKEY> Public key of authorized withdrawer (defaults to cli config pubkey)
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--custodian <KEYPAIR or PUBKEY> Identity of the custodian (can withdraw before lockup expires)
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
--from <KEYPAIR or PUBKEY> Source account of funds (if different from client local account)
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--lockup-date <RFC3339 DATE TIME>
The date and time at which this account will be available for withdrawal
--lockup-epoch <EPOCH>
The epoch height at which this account will be available for withdrawal
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--seed <SEED STRING>
Seed for address generation; if specified, the resulting account will be at a derived address of the STAKE
ACCOUNT pubkey
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
--withdraw-authority <PUBKEY> Public key of authorized withdrawer (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Keypair of the stake account to fund
<AMOUNT> The amount of send to the vote account (default unit SOL)
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
<STAKE ACCOUNT> Signing authority of the stake address to fund
<AMOUNT> The amount of send to the vote account, in SOL
```
#### solana-create-validator-storage-account
@ -759,7 +790,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<STORAGE ACCOUNT OWNER PUBKEY>
@ -790,7 +821,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--seed <SEED STRING> Seed for address generation; if specified, the resulting account will be at
a derived address of the VOTE ACCOUNT pubkey
@ -819,12 +850,16 @@ OPTIONS:
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
--blockhash <BLOCKHASH> Use the supplied blockhash
-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
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
@ -833,8 +868,8 @@ OPTIONS:
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR of PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR or PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Stake account to be deactivated.
@ -860,12 +895,16 @@ OPTIONS:
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
--blockhash <BLOCKHASH> Use the supplied blockhash
-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
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
@ -874,8 +913,8 @@ OPTIONS:
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR of PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR or PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Stake account to delegate
@ -903,7 +942,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PATH TO BPF PROGRAM> /path/to/program.o
@ -931,7 +970,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-fees
@ -955,7 +994,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-genesis-hash
@ -979,7 +1018,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-gossip
@ -1003,7 +1042,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-help
@ -1018,6 +1057,55 @@ ARGS:
<subcommand>... The subcommand whose help message to display
```
#### solana-leader-schedule
```text
solana-leader-schedule
Display leader schedule
USAGE:
solana leader-schedule [FLAGS] [OPTIONS]
FLAGS:
-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 or usb://remote/wallet/path
```
#### solana-live-slots
```text
solana-live-slots
Show information about the current slot progression
USAGE:
solana live-slots [FLAGS] [OPTIONS]
FLAGS:
-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 or usb://remote/wallet/path
-w, --ws <URL> WebSocket URL for PubSub RPC connection [default: ws://127.0.0.1:8900]
```
#### solana-new-nonce
```text
solana-new-nonce
@ -1041,7 +1129,7 @@ OPTIONS:
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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
@ -1071,7 +1159,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<NONCE ACCOUNT> Address of the nonce account to display
@ -1099,7 +1187,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<NONCE ACCOUNT> Address of the nonce account to display
@ -1111,7 +1199,7 @@ solana-pay
Send a payment
USAGE:
solana pay [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT> [--] [UNIT]
solana pay [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT>
FLAGS:
--cancelable
@ -1126,12 +1214,12 @@ OPTIONS:
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
--blockhash <BLOCKHASH> Use the supplied blockhash
-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
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
@ -1140,15 +1228,14 @@ OPTIONS:
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--after <DATETIME> A timestamp after which transaction will execute
--require-timestamp-from <PUBKEY> Require timestamp from this third party
--require-signature-from <PUBKEY>... Any third party signatures required to unlock the lamports
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--after <DATETIME> A timestamp after which transaction will execute
--require-timestamp-from <PUBKEY> Require timestamp from this third party
--require-signature-from <PUBKEY>... Any third party signatures required to unlock the lamports
ARGS:
<TO PUBKEY> The pubkey of recipient
<AMOUNT> The amount to send (default unit SOL)
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
<AMOUNT> The amount to send, in SOL
```
#### solana-ping
@ -1175,7 +1262,7 @@ OPTIONS:
-c, --count <NUMBER> Stop after submitting count transactions
-i, --interval <SECONDS> Wait interval seconds between submitting the next transaction [default: 2]
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--lamports <NUMBER> Number of lamports to transfer for each transaction [default: 1]
-t, --timeout <SECONDS> Wait up to timeout seconds for transaction confirmation [default: 15]
```
@ -1201,7 +1288,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PUBKEY> The pubkey of recipient
@ -1230,41 +1317,13 @@ OPTIONS:
~/.config/solana/cli/config.yml]
--date <DATETIME> Optional arbitrary timestamp to apply
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<PUBKEY> The pubkey of recipient
<PROCESS ID> The process id of the transfer to unlock
```
#### solana-show-stake-account
```text
solana-show-stake-account
Show the contents of a stake account
USAGE:
solana show-stake-account [FLAGS] [OPTIONS] <STAKE ACCOUNT>
FLAGS:
-h, --help Prints help information
--lamports Display balance in lamports instead of SOL
--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
ARGS:
<STAKE ACCOUNT> Address of the stake account to display
```
#### solana-slot
```text
solana-slot
@ -1287,7 +1346,85 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-split-stake
```text
solana-split-stake
Split a stake account
USAGE:
solana split-stake [FLAGS] [OPTIONS] <STAKE ACCOUNT> <SPLIT STAKE ACCOUNT> <AMOUNT>
FLAGS:
-h, --help Prints help information
--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
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]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--seed <SEED STRING>
Seed for address generation; if specified, the resulting account will be at a derived address of the SPLIT
STAKE ACCOUNT pubkey
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR or PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Stake account to be split
<SPLIT STAKE ACCOUNT> Keypair of the new stake account to split funds into
<AMOUNT> The amount to move into the new stake account, in unit SOL
```
#### solana-stake-account
```text
solana-stake-account
Show the contents of a stake account
USAGE:
solana stake-account [FLAGS] [OPTIONS] <STAKE ACCOUNT>
FLAGS:
-h, --help Prints help information
--lamports Display balance in lamports instead of SOL
--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 or usb://remote/wallet/path
ARGS:
<STAKE ACCOUNT> Address of the stake account to display
```
#### solana-stake-authorize-staker
@ -1310,12 +1447,16 @@ OPTIONS:
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
--blockhash <BLOCKHASH> Use the supplied blockhash
-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
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
@ -1324,8 +1465,8 @@ OPTIONS:
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR of PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--stake-authority <KEYPAIR or PUBKEY> Public key of authorized staker (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Stake account in which to set the authorized staker
@ -1356,8 +1497,12 @@ OPTIONS:
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
@ -1366,7 +1511,7 @@ OPTIONS:
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--withdraw-authority <KEYPAIR or PUBKEY> Public key of authorized withdrawer (defaults to cli config pubkey)
ARGS:
@ -1396,7 +1541,61 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-stake-set-lockup
```text
solana-stake-set-lockup
Set Lockup for the stake account
USAGE:
solana stake-set-lockup [FLAGS] [OPTIONS] <STAKE ACCOUNT>
FLAGS:
-h, --help Prints help information
--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
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]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--custodian <KEYPAIR or PUBKEY> Public key of signing custodian (defaults to cli config pubkey)
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--lockup-date <RFC3339 DATE TIME>
The date and time at which this account will be available for withdrawal
--lockup-epoch <EPOCH>
The epoch height at which this account will be available for withdrawal
--new-custodian <KEYPAIR or PUBKEY>
Identity of the new lockup custodian (can withdraw before lockup expires)
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
ARGS:
<STAKE ACCOUNT> Stake account for which to set Lockup
```
#### solana-stakes
@ -1421,7 +1620,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<VOTE ACCOUNT PUBKEYS>... Only show stake accounts delegated to the provided vote accounts
@ -1448,7 +1647,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<STORAGE ACCOUNT PUBKEY> Storage account pubkey
@ -1476,7 +1675,53 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-transfer
```text
solana-transfer
Transfer funds between system accounts
USAGE:
solana transfer [FLAGS] [OPTIONS] <TO PUBKEY> <AMOUNT>
FLAGS:
-h, --help Prints help information
--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
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]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
--from <KEYPAIR or PUBKEY> Source account of funds (if different from client local account)
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
ARGS:
<TO PUBKEY> The pubkey of recipient
<AMOUNT> The amount to send, in SOL
```
#### solana-validator-info
@ -1500,7 +1745,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
SUBCOMMANDS:
get Get and parse Solana Validator info
@ -1530,7 +1775,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
```
#### solana-vote-account
@ -1555,7 +1800,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<VOTE ACCOUNT PUBKEY> Vote account pubkey
@ -1582,7 +1827,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<VOTE ACCOUNT PUBKEY> Vote account in which to set the authorized voter
@ -1610,7 +1855,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<VOTE ACCOUNT PUBKEY> Vote account in which to set the authorized withdrawer
@ -1638,7 +1883,7 @@ OPTIONS:
-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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
ARGS:
<VOTE ACCOUNT PUBKEY> Vote account to update
@ -1652,7 +1897,7 @@ solana-withdraw-from-nonce-account
Withdraw lamports from the nonce account
USAGE:
solana withdraw-from-nonce-account [FLAGS] [OPTIONS] <NONCE ACCOUNT> <DESTINATION ACCOUNT> <AMOUNT> [UNIT]
solana withdraw-from-nonce-account [FLAGS] [OPTIONS] <NONCE ACCOUNT> <DESTINATION ACCOUNT> <AMOUNT>
FLAGS:
-h, --help Prints help information
@ -1669,7 +1914,7 @@ OPTIONS:
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
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
@ -1677,8 +1922,7 @@ OPTIONS:
ARGS:
<NONCE ACCOUNT> Nonce account from to withdraw from
<DESTINATION ACCOUNT> The account to which the lamports should be transferred
<AMOUNT> The amount to withdraw from the nonce account (default unit SOL)
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
<AMOUNT> The amount to withdraw from the nonce account, in SOL
```
#### solana-withdraw-stake
@ -1687,10 +1931,11 @@ solana-withdraw-stake
Withdraw the unstaked lamports from the stake account
USAGE:
solana withdraw-stake [FLAGS] [OPTIONS] <STAKE ACCOUNT> <DESTINATION ACCOUNT> <AMOUNT> [UNIT]
solana withdraw-stake [FLAGS] [OPTIONS] <STAKE ACCOUNT> <DESTINATION ACCOUNT> <AMOUNT>
FLAGS:
-h, --help Prints help information
--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
official English word list
-V, --version Prints version information
@ -1700,17 +1945,29 @@ OPTIONS:
--ask-seed-phrase <KEYPAIR NAME>
Recover a keypair using a seed phrase and optional passphrase [possible values: keypair]
--blockhash <BLOCKHASH> Use the supplied blockhash
-C, --config <PATH>
Configuration file to use [default: ~/.config/solana/cli/config.yml]
--fee-payer <KEYPAIR or PUBKEY>
Specify the fee-payer account. This may be a keypair file, the ASK keyword
or the pubkey of an offline signer, provided an appropriate --signer argument
is also passed. Defaults to the client keypair.
-u, --url <URL> JSON RPC URL for the solana cluster
-k, --keypair <PATH> /path/to/id.json
-k, --keypair <PATH> /path/to/id.json or usb://remote/wallet/path
--nonce <PUBKEY>
Provide the nonce account to use when creating a nonced
transaction. Nonced transactions are useful when a transaction
requires a lengthy signing process. Learn more about nonced
transactions at https://docs.solana.com/offline-signing/durable-nonce
--nonce-authority <KEYPAIR or PUBKEY>
Provide the nonce authority keypair to use when signing a nonced transaction
--signer <BASE58_PUBKEY=BASE58_SIG>... Provide a public-key/signature pair for the transaction
--withdraw-authority <KEYPAIR or PUBKEY> Public key of authorized withdrawer (defaults to cli config pubkey)
ARGS:
<STAKE ACCOUNT> Stake account from which to withdraw
<DESTINATION ACCOUNT> The account to which the lamports should be transferred
<AMOUNT> The amount to withdraw from the stake account (default unit SOL)
<UNIT> Specify unit to use for request [possible values: SOL, lamports]
<AMOUNT> The amount to withdraw from the stake account, in SOL
```

View File

@ -154,7 +154,7 @@ FLAGS:
OPTIONS:
-d, --data_dir <PATH> Directory to store install data [default: .../Library/Application Support/solana]
-u, --url <URL> JSON RPC URL for the solana cluster [default: http://testnet.solana.com:8899]
-u, --url <URL> JSON RPC URL for the solana cluster [default: http://devnet.solana.com:8899]
-p, --pubkey <PUBKEY> Public key of the update manifest [default: 9XX329sPuskWhH4DQh6k16c87dHKhXLBZTL3Gxmve8Gp]
```

View File

@ -22,7 +22,7 @@ At present, the following commands support offline signing:
To sign a transaction offline, pass the following arguments on the command line
1) `--sign-only`, prevents the client from submitting the signed transaction
to the network. Instead, the pubkey/signature pairs are printed to stdout.
to the network. Instead, the pubkey/signature pairs are printed to stdout.
2) `--blockhash BASE58_HASH`, allows the caller to specify the value used to
fill the transaction's `recent_blockhash` field. This serves a number of
purposes, namely:
@ -37,7 +37,7 @@ Command
```bash
solana@offline$ solana pay --sign-only --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \
recipient-keypair.json 1 SOL
recipient-keypair.json 1
```
Output
@ -67,7 +67,7 @@ Command
```bash
solana@online$ solana pay --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \
--signer FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN
recipient-keypair.json 1 SOL
recipient-keypair.json 1
```
Output

View File

@ -36,7 +36,7 @@ A nonce account is created by first generating a new keypair, then create the ac
```bash
solana-keygen new -o nonce-keypair.json
solana create-nonce-account nonce-keypair.json 1 SOL
solana create-nonce-account nonce-keypair.json 1
```
- Output
@ -64,7 +64,7 @@ presently stored nonce value with
- Command
```bash
solana nonce nonce-keypair.json
solana nonce nonce-keypair.json
```
- Output
@ -105,7 +105,7 @@ Inspect a nonce account in a more human friendly format with
- Command
```bash
solana nonce-account nonce-keypair.json
solana nonce-account nonce-keypair.json
```
- Output
@ -127,7 +127,7 @@ Withdraw funds from a nonce account with
- Command
```bash
solana withdraw-from-nonce-account nonce-keypair.json ~/.config/solana/id.json 0.5 SOL
solana withdraw-from-nonce-account nonce-keypair.json ~/.config/solana/id.json 0.5
```
- Output
@ -151,7 +151,7 @@ Reassign the authority of a nonce account after creation with
- Command
```bash
solana authorize-nonce-account nonce-keypair.json nonce-authority.json
solana authorize-nonce-account nonce-keypair.json nonce-authority.json
```
- Output
@ -197,7 +197,7 @@ Alice will need some funds to create a nonce account and send to Bob. Airdrop
her some SOL
```bash
$ solana airdrop -k alice.json 10 SOL
$ solana airdrop -k alice.json 10
10 SOL
```
@ -211,7 +211,7 @@ has full authority over the nonce account
{% endhint %}
```bash
$ solana create-nonce-account -k alice.json nonce.json 1 SOL
$ solana create-nonce-account -k alice.json nonce.json 1
3KPZr96BTsL3hqera9up82KAU462Gz31xjqJ6eHUAjF935Yf8i1kmfEbo6SVbNaACKE5z6gySrNjVRvmS8DcPuwV
```
@ -221,7 +221,7 @@ Alice attempts to pay Bob, but takes too long to sign. The specified blockhash
expires and the transaction fails
```bash
$ solana pay -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 bob.json 1 SOL
$ solana pay -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 bob.json 1
[2020-01-02T18:48:28.462911000Z ERROR solana_cli::cli] Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
Error: Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
```
@ -236,13 +236,13 @@ Remember, `alice.json` is the [nonce authority](#nonce-authority) in this exampl
{% endhint %}
```bash
$ solana nonce-account nonce.json
$ solana nonce-account nonce.json
balance: 1 SOL
minimum balance required: 0.00136416 SOL
nonce: F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7
```
```bash
$ solana pay -k alice.json --blockhash F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 1 SOL
$ solana pay -k alice.json --blockhash F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 1
HR1368UKHVZyenmH7yVz5sBAijV6XAPeWbEiXEGVYQorRMcoijeNAbzZqEZiH8cDB8tk65ckqeegFjK8dHwNFgQ
```
@ -256,7 +256,7 @@ $ solana balance -k bob.json
1 SOL
```
```bash
$ solana nonce-account nonce.json
$ solana nonce-account nonce.json
balance: 1 SOL
minimum balance required: 0.00136416 SOL
nonce: 6bjroqDcZgTv6Vavhqf81oBHTv3aMnX19UTB51YhAZnN

View File

@ -90,6 +90,91 @@ For full usage details run:
```bash
solana-keygen pubkey --help
```
## Verifying the Keypair
A keypair can be verified by following a variation on the
[offline signing](../offline-signing/README.md) procedure with a dummy transaction.
### Create and Sign a Dummy Transaction
Use offline signing to acquire the signature of a dummy transaction that can
be verified in the next step. A 0 Lamport [transfer](../cli/usage.md#solana-transfer)
is used to prevent inadvertent loss of funds. Additionally, an improbable _blockhash_
value is specified, as well as using the address of the _system program_ for the `TO`
argument, to ensure the transaction would be rejected by the _cluster_ should
it be submitted in error.
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only \
--ask-seed-phrase keypair --blockhash 11111111111111111111111111111111
```
Prompt for seed phrase
```text
[keypair] seed phrase:
[keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
Recovered pubkey `AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi`. Continue? (y/n): y
```
Output
```text
Blockhash: 11111111111111111111111111111111
Signers (Pubkey=Signature):
AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA
{"blockhash":"11111111111111111111111111111111","signers":["AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA"]}
```
### Verify the Signature
Using the _Signers_ output from the [previous step](#create-and-sign-a-dummy-transaction)
to reconstruct the transaction, this time specifying the _pubkey_ and _signature_
as in the submission step of [offline signing](../offline-signing/README.md). That is, the `--from` and
`--fee-payer` are explicitly set to the _pubkey_ rather than being taken from
the keypair (which is not queried this time).
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only --from AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi \
--signer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA \
--blockhash 11111111111111111111111111111111 --fee-payer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi
```
Output
```text
Blockhash: 11111111111111111111111111111111
Signers (Pubkey=Signature):
AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA
{"blockhash":"11111111111111111111111111111111","signers":["AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA"]}
```
### An Example of Failure
To simulate an error the [verification step](#verify-the-signature) is repeated,
but with a corrupted _signature_ (the last letter is changed from "A" to "B").
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only --from AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi \
--signer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWB \
--blockhash 11111111111111111111111111111111 --fee-payer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi
```
Output (Error)
```text
Error: BadParameter("Transaction construction failed, incorrect signature or public key provided")
```
## Checking Account Balance
All that is needed to check an account balance is the public key of an account.
@ -102,7 +187,7 @@ networked machine.
Next, configure the `solana` CLI tool to connect to a particular cluster:
```bash
solana config set --url <CLUSTER URL> # (i.e. http://testnet.solana.com:8899)
solana config set --url <CLUSTER URL> # (i.e. http://devnet.solana.com:8899)
```
Finally, to check the balance, run the following command:
@ -165,7 +250,7 @@ trigger a seed phrase input prompt for the stake account and use
`--ask-seed-phrase keypair` to securely input the funding keypair.
```bash
solana create-stake-account ASK 1 SOL --ask-seed-phrase keypair
solana create-stake-account ASK 1 --ask-seed-phrase keypair
[stake_account] seed phrase: 🔒
[stake_account] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:

View File

@ -22,7 +22,7 @@ Each CTF test starts with an opaque entry point and a funded keypair. The test s
```text
use crate::contact_info::ContactInfo;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
pub fn test_this_behavior(
entry_point_info: &ContactInfo,
funding_keypair: &Keypair,

View File

@ -8,9 +8,9 @@ Please note some of the information and instructions described here may change i
Archivers are specialized light clients. They download a part of the ledger \(a.k.a Segment\) and store it. They earn rewards for storing segments.
The testnet features a validator running at testnet.solana.com, which serves as the entrypoint to the cluster for your archiver node.
The testnet features a validator running at devnet.solana.com, which serves as the entrypoint to the cluster for your archiver node.
Additionally there is a blockexplorer available at [http://testnet.solana.com/](http://testnet.solana.com/).
Additionally there is a blockexplorer available at [http://devnet.solana.com/](http://devnet.solana.com/).
The testnet is configured to reset the ledger daily, or sooner should the hourly automated cluster sanity test fail.
@ -29,10 +29,10 @@ Before starting an archiver node, sanity check that the cluster is accessible to
Fetch the current transaction count over JSON RPC:
```bash
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://testnet.solana.com:8899
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://devnet.solana.com:8899
```
Inspect the blockexplorer at [http://testnet.solana.com/](http://testnet.solana.com/) for activity.
Inspect the blockexplorer at [http://devnet.solana.com/](http://devnet.solana.com/) for activity.
View the [metrics dashboard](https://metrics.solana.com:3000/d/testnet-beta/testnet-monitor-beta?var-testnet=testnet) for more detail on cluster activity.
@ -95,7 +95,7 @@ Download the binaries by navigating to [https://github.com/solana-labs/solana/re
Try running following command to join the gossip network and view all the other nodes in the cluster:
```bash
solana-gossip spy --entrypoint testnet.solana.com:8001
solana-gossip spy --entrypoint devnet.solana.com:8001
# Press ^C to exit
```
@ -129,7 +129,7 @@ Use solana-keygen to show the public keys for each of the keypairs, they will be
```text
Then set up the storage accounts for your archiver by running:
```bash
solana --keypair archiver-keypair.json airdrop 100000 lamports
solana --keypair archiver-keypair.json airdrop .0001
solana --keypair archiver-keypair.json create-archiver-storage-account $ARCHIVER_IDENTITY $STORAGE_IDENTITY
```
@ -138,7 +138,7 @@ Note: Every time the testnet restarts, run the steps to setup the archiver accou
To start the archiver:
```bash
solana-archiver --entrypoint testnet.solana.com:8001 --identity-keypair archiver-keypair.json --storage-keypair storage-keypair.json --ledger archiver-ledger
solana-archiver --entrypoint devnet.solana.com:8001 --identity-keypair archiver-keypair.json --storage-keypair storage-keypair.json --ledger archiver-ledger
```
## Verify Archiver Setup
@ -146,7 +146,7 @@ solana-archiver --entrypoint testnet.solana.com:8001 --identity-keypair archiver
From another console, confirm the IP address and **identity pubkey** of your archiver is visible in the gossip network by running:
```bash
solana-gossip spy --entrypoint testnet.solana.com:8001
solana-gossip spy --entrypoint devnet.solana.com:8001
```
Provide the **storage account pubkey** to the `solana storage-account` command to view the recent mining activity from your archiver:

View File

@ -13,9 +13,7 @@ serve as the entrypoint to the cluster for your validator.
Current testnet entrypoints:
* Stable, testnet.solana.com
* Beta, beta.testnet.solana.com
* Edge, edge.testnet.solana.com
* Developer testnet, devnet.solana.com
Solana may launch special testnets for validator participation; we will provide
you with a specific entrypoint URL to use.

View File

@ -6,7 +6,7 @@ Confirm the IP address and **identity pubkey** of your validator is visible in
the gossip network by running:
```bash
solana-gossip spy --entrypoint testnet.solana.com:8001
solana-gossip spy --entrypoint devnet.solana.com:8001
```
## Check Your Balance
@ -35,13 +35,13 @@ cluster, as well as the health of the cluster:
```bash
# Similar to solana-gossip, you should see your validator in the list of cluster nodes
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getClusterNodes"}' http://testnet.solana.com:8899
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getClusterNodes"}' http://devnet.solana.com:8899
# If your validator is properly voting, it should appear in the list of `current` vote accounts. If staked, `stake` should be > 0
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' http://testnet.solana.com:8899
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' http://devnet.solana.com:8899
# Returns the current leader schedule
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://testnet.solana.com:8899
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://devnet.solana.com:8899
# Returns info about the current epoch. slotIndex should progress on subsequent calls.
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://testnet.solana.com:8899
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://devnet.solana.com:8899
```

View File

@ -35,7 +35,7 @@ solana-keygen new -o ~/validator-stake-keypair.json
Now delegate 1 SOL to your validator by first creating your stake account:
```bash
solana create-stake-account ~/validator-stake-keypair.json 1 SOL
solana create-stake-account ~/validator-stake-keypair.json 1
```
and then delegating that stake to your validator:

View File

@ -6,11 +6,11 @@ The solana cli includes `get` and `set` configuration commands to automatically
set the `--url` argument for cli commands. For example:
```bash
solana config set --url http://testnet.solana.com:8899
solana config set --url http://devnet.solana.com:8899
```
\(You can always override the set configuration by explicitly passing the
`--url` argument with a command, eg: `solana --url http://beta.testnet.solana.com:8899 balance`\)
`--url` argument with a command, eg: `solana --url http://beta.devnet.solana.com:8899 balance`\)
## Confirm The Testnet Is Reachable
@ -33,7 +33,7 @@ Try running following command to join the gossip network and view all the other
nodes in the cluster:
```bash
solana-gossip spy --entrypoint testnet.solana.com:8001
solana-gossip spy --entrypoint devnet.solana.com:8001
# Press ^C to exit
```
@ -107,7 +107,7 @@ You should see the following output:
```text
Wallet Config Updated: /home/solana/.config/solana/wallet/config.yml
* url: http://testnet.solana.com:8899
* url: http://devnet.solana.com:8899
* keypair: /home/solana/validator-keypair.json
```
@ -155,7 +155,7 @@ Connect to a testnet cluster by running:
```bash
solana-validator --identity-keypair ~/validator-keypair.json --voting-keypair ~/validator-vote-keypair.json \
--ledger ~/validator-ledger --rpc-port 8899 --entrypoint testnet.solana.com:8001 \
--ledger ~/validator-ledger --rpc-port 8899 --entrypoint devnet.solana.com:8001 \
--limit-ledger-size
```
@ -166,7 +166,7 @@ Confirm your validator connected to the network by opening a new terminal and
running:
```bash
solana-gossip spy --entrypoint testnet.solana.com:8001
solana-gossip spy --entrypoint devnet.solana.com:8001
```
If your validator is connected, its public key and IP address will appear in the list.

View File

@ -5,8 +5,7 @@ that serves as an entrypoint to the cluster.
Current testnet entrypoints:
* Stable: testnet.solana.com
* Beta: beta.testnet.solana.com
* Stable: devnet.solana.com
Application developers should target the Stable testnet. Key differences
between the Stable testnet and what will be mainnet:
@ -28,13 +27,13 @@ You can submit a JSON-RPC request to see the specific software version of the
cluster. Use this to specify [the software version to install](validator-software.md).
```bash
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' testnet.solana.com:8899
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' devnet.solana.com:8899
```
Example result:
`{"jsonrpc":"2.0","result":{"solana-core":"0.21.0"},"id":1}`
## Using a Different Testnet
This guide is written in the context of testnet.solana.com, our most stable
This guide is written in the context of devnet.solana.com, our most stable
cluster. To participate in another testnet, modify the commands in the following
pages, replacing `testnet.solana.com` with your desired testnet.
pages, replacing `devnet.solana.com` with your desired testnet.

View File

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

View File

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

View File

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

View File

@ -81,7 +81,7 @@ mod tests {
use solana_ledger::get_tmp_ledger_path;
use solana_sdk::hash::{hash, Hash, Hasher};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_transaction;
use std::fs::remove_file;
use std::fs::File;

View File

@ -234,7 +234,7 @@ sanity() {
(
set -x
NO_INSTALL_CHECK=1 \
ci/testnet-sanity.sh edge-testnet-solana-com gce -P us-west1-b
ci/testnet-sanity.sh edge-devnet-solana-com gce -P us-west1-b
maybe_deploy_software
)
;;
@ -249,7 +249,7 @@ sanity() {
(
set -x
NO_INSTALL_CHECK=1 \
ci/testnet-sanity.sh beta-testnet-solana-com gce -P us-west1-b
ci/testnet-sanity.sh beta-devnet-solana-com gce -P us-west1-b
maybe_deploy_software --deploy-if-newer
)
;;
@ -263,7 +263,7 @@ sanity() {
testnet)
(
set -x
ci/testnet-sanity.sh testnet-solana-com gce -P us-west1-b
ci/testnet-sanity.sh devnet-solana-com gce -P us-west1-b
)
;;
testnet-perf)
@ -327,9 +327,9 @@ deploy() {
testnet-edge)
(
set -x
ci/testnet-deploy.sh -p edge-testnet-solana-com -C gce -z us-west1-b \
ci/testnet-deploy.sh -p edge-devnet-solana-com -C gce -z us-west1-b \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P \
-a edge-testnet-solana-com --letsencrypt edge.testnet.solana.com \
-a edge-devnet-solana-com --letsencrypt edge.devnet.solana.com \
--limit-ledger-size \
${skipCreate:+-e} \
${skipStart:+-s} \
@ -352,9 +352,9 @@ deploy() {
testnet-beta)
(
set -x
ci/testnet-deploy.sh -p beta-testnet-solana-com -C gce -z us-west1-b \
ci/testnet-deploy.sh -p beta-devnet-solana-com -C gce -z us-west1-b \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P \
-a beta-testnet-solana-com --letsencrypt beta.testnet.solana.com \
-a beta-devnet-solana-com --letsencrypt beta.devnet.solana.com \
--limit-ledger-size \
${skipCreate:+-e} \
${skipStart:+-s} \
@ -377,9 +377,9 @@ deploy() {
testnet)
(
set -x
ci/testnet-deploy.sh -p testnet-solana-com -C gce -z us-west1-b \
ci/testnet-deploy.sh -p devnet-solana-com -C gce -z us-west1-b \
-t "$CHANNEL_OR_TAG" -n 0 -c 0 -u -P \
-a testnet-solana-com --letsencrypt testnet.solana.com \
-a testnet-solana-com --letsencrypt devnet.solana.com \
--limit-ledger-size \
${skipCreate:+-e} \
${skipStart:+-s} \

View File

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

View File

@ -6,7 +6,7 @@ use solana_sdk::{
clock::UnixTimestamp,
native_token::sol_to_lamports,
pubkey::Pubkey,
signature::{read_keypair_file, Keypair, KeypairUtil, Signature},
signature::{read_keypair_file, Keypair, Signature, Signer},
};
use std::str::FromStr;
@ -93,12 +93,8 @@ pub fn pubkeys_sigs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<(Pubk
})
}
pub fn amount_of(matches: &ArgMatches<'_>, name: &str, unit: &str) -> Option<u64> {
if matches.value_of(unit) == Some("lamports") {
value_of(matches, name)
} else {
value_of(matches, name).map(sol_to_lamports)
}
pub fn lamports_of_sol(matches: &ArgMatches<'_>, name: &str) -> Option<u64> {
value_of(matches, name).map(sol_to_lamports)
}
pub fn derivation_of(matches: &ArgMatches<'_>, name: &str) -> Option<DerivationPath> {
@ -269,24 +265,21 @@ mod tests {
}
#[test]
fn test_amount_of() {
fn test_lamports_of_sol() {
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "50", "--unit", "lamports"]);
assert_eq!(amount_of(&matches, "single", "unit"), Some(50));
assert_eq!(amount_of(&matches, "multiple", "unit"), None);
.get_matches_from(vec!["test", "--single", "50"]);
assert_eq!(lamports_of_sol(&matches, "single"), Some(50000000000));
assert_eq!(lamports_of_sol(&matches, "multiple"), None);
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "50", "--unit", "SOL"]);
assert_eq!(amount_of(&matches, "single", "unit"), Some(50000000000));
.get_matches_from(vec!["test", "--single", "1.5"]);
assert_eq!(lamports_of_sol(&matches, "single"), Some(1500000000));
assert_eq!(lamports_of_sol(&matches, "multiple"), None);
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "1.5", "--unit", "SOL"]);
assert_eq!(amount_of(&matches, "single", "unit"), Some(1500000000));
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "1.5", "--unit", "lamports"]);
assert_eq!(amount_of(&matches, "single", "unit"), None);
.get_matches_from(vec!["test", "--single", "0.03"]);
assert_eq!(lamports_of_sol(&matches, "single"), Some(30000000));
}
#[test]

View File

@ -3,8 +3,7 @@ use bip39::{Language, Mnemonic, Seed};
use clap::values_t;
use rpassword::prompt_password_stderr;
use solana_sdk::signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair_file, Keypair,
KeypairUtil,
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair_file, Keypair, Signer,
};
use std::{
error,

View File

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

View File

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

View File

@ -36,7 +36,7 @@ use solana_sdk::{
message::Message,
native_token::lamports_to_sol,
pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, KeypairUtil, Signature},
signature::{keypair_from_seed, Keypair, Signature, Signer, SignerError},
system_instruction::{self, create_address_with_seed, SystemError, MAX_ADDRESS_SEED_LEN},
system_transaction,
transaction::{Transaction, TransactionError},
@ -407,8 +407,8 @@ pub enum CliCommand {
Airdrop {
faucet_host: Option<IpAddr>,
faucet_port: u16,
pubkey: Option<Pubkey>,
lamports: u64,
use_lamports_unit: bool,
},
Balance {
pubkey: Option<Pubkey>,
@ -640,14 +640,14 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
} else {
None
};
let lamports = required_lamports_from(matches, "amount", "unit")?;
let use_lamports_unit = matches.value_of("unit") == Some("lamports");
let pubkey = pubkey_of(&matches, "to");
let lamports = lamports_of_sol(matches, "amount").unwrap();
Ok(CliCommandInfo {
command: CliCommand::Airdrop {
faucet_host,
faucet_port,
pubkey,
lamports,
use_lamports_unit,
},
require_keypair: true,
})
@ -680,7 +680,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
}
},
("pay", Some(matches)) => {
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
let to = pubkey_of(&matches, "to").unwrap();
let timestamp = if matches.is_present("timestamp") {
// Parse input for serde_json
@ -764,7 +764,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
})
}
("transfer", Some(matches)) => {
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
let to = pubkey_of(&matches, "to").unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let signers = pubkeys_sigs_of(&matches, SIGNER_ARG.name);
@ -942,13 +942,13 @@ fn process_airdrop(
rpc_client: &RpcClient,
config: &CliConfig,
faucet_addr: &SocketAddr,
pubkey: &Option<Pubkey>,
lamports: u64,
use_lamports_unit: bool,
) -> ProcessResult {
let pubkey = config.pubkey()?;
let pubkey = pubkey.unwrap_or(config.pubkey()?);
println!(
"Requesting airdrop of {} from {}",
build_balance_message(lamports, use_lamports_unit, true),
build_balance_message(lamports, false, true),
faucet_addr
);
let previous_balance = match rpc_client.retry_get_balance(&pubkey, 5)? {
@ -967,11 +967,7 @@ fn process_airdrop(
.retry_get_balance(&pubkey, 5)?
.unwrap_or(previous_balance);
Ok(build_balance_message(
current_balance,
use_lamports_unit,
true,
))
Ok(build_balance_message(current_balance, false, true))
}
fn process_balance(
@ -1852,8 +1848,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::Airdrop {
faucet_host,
faucet_port,
pubkey,
lamports,
use_lamports_unit,
} => {
let faucet_addr = SocketAddr::new(
faucet_host.unwrap_or_else(|| {
@ -1869,13 +1865,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
*faucet_port,
);
process_airdrop(
&rpc_client,
config,
&faucet_addr,
*lamports,
*use_lamports_unit,
)
process_airdrop(&rpc_client, config, &faucet_addr, pubkey, *lamports)
}
// Check client balance
CliCommand::Balance {
@ -1979,13 +1969,13 @@ impl FaucetKeypair {
}
}
impl KeypairUtil for FaucetKeypair {
impl Signer for FaucetKeypair {
/// Return the public key of the keypair used to sign votes
fn pubkey(&self) -> Pubkey {
self.transaction.message().account_keys[0]
}
fn try_pubkey(&self) -> Result<Pubkey, Box<dyn error::Error>> {
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
Ok(self.pubkey())
}
@ -1993,7 +1983,7 @@ impl KeypairUtil for FaucetKeypair {
self.transaction.signatures[0]
}
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, Box<dyn error::Error>> {
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
Ok(self.sign_message(message))
}
}
@ -2044,22 +2034,6 @@ where
}
}
// If clap arg `name` is_required, and specifies an amount of either lamports or SOL, the only way
// `amount_of()` can return None is if `name` is an f64 and `unit`== "lamports". This method
// catches that case and converts it to an Error.
pub(crate) fn required_lamports_from(
matches: &ArgMatches<'_>,
name: &str,
unit: &str,
) -> Result<u64, CliError> {
amount_of(matches, name, unit).ok_or_else(|| {
CliError::BadParameter(format!(
"Lamports cannot be fractional: {}",
matches.value_of("amount").unwrap()
))
})
}
pub(crate) fn build_balance_message(
lamports: u64,
use_lamports_unit: bool,
@ -2117,15 +2091,15 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The airdrop amount to request (default unit SOL)"),
.help("The airdrop amount to request, in SOL"),
)
.arg(
Arg::with_name("unit")
Arg::with_name("to")
.index(2)
.value_name("UNIT")
.value_name("PUBKEY")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request and balance display"),
.validator(is_pubkey_or_keypair)
.help("The pubkey of airdrop recipient"),
),
)
.subcommand(
@ -2234,15 +2208,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The amount to send (default unit SOL)"),
)
.arg(
Arg::with_name("unit")
.index(3)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request"),
.help("The amount to send, in SOL"),
)
.arg(
Arg::with_name("timestamp")
@ -2347,15 +2313,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The amount to send (default unit SOL)"),
)
.arg(
Arg::with_name("unit")
.index(3)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request"),
.help("The amount to send, in SOL"),
)
.arg(
Arg::with_name("from")
@ -2455,17 +2413,18 @@ mod tests {
let dt = Utc.ymd(2018, 9, 19).and_hms(17, 30, 59);
// Test Airdrop Subcommand
let test_airdrop = test_commands
.clone()
.get_matches_from(vec!["test", "airdrop", "50", "lamports"]);
let test_airdrop =
test_commands
.clone()
.get_matches_from(vec!["test", "airdrop", "50", &pubkey_string]);
assert_eq!(
parse_command(&test_airdrop).unwrap(),
CliCommandInfo {
command: CliCommand::Airdrop {
faucet_host: None,
faucet_port: solana_faucet::faucet::FAUCET_PORT,
lamports: 50,
use_lamports_unit: true,
pubkey: Some(pubkey),
lamports: 50_000_000_000,
},
require_keypair: true,
}
@ -2613,18 +2572,15 @@ mod tests {
);
// Test Simple Pay Subcommand
let test_pay = test_commands.clone().get_matches_from(vec![
"test",
"pay",
&pubkey_string,
"50",
"lamports",
]);
let test_pay =
test_commands
.clone()
.get_matches_from(vec!["test", "pay", &pubkey_string, "50"]);
assert_eq!(
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
..PayCommand::default()
}),
@ -2638,7 +2594,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--require-signature-from",
&witness0_string,
"--require-signature-from",
@ -2648,7 +2603,7 @@ mod tests {
parse_command(&test_pay_multiple_witnesses).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
witnesses: Some(vec![witness0, witness1]),
..PayCommand::default()
@ -2661,7 +2616,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--require-signature-from",
&witness0_string,
]);
@ -2669,7 +2623,7 @@ mod tests {
parse_command(&test_pay_single_witness).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
witnesses: Some(vec![witness0]),
..PayCommand::default()
@ -2684,7 +2638,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--after",
"2018-09-19T17:30:59",
"--require-timestamp-from",
@ -2694,7 +2647,7 @@ mod tests {
parse_command(&test_pay_timestamp).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(witness0),
@ -2712,7 +2665,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--sign-only",
@ -2721,7 +2673,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
sign_only: true,
@ -2740,7 +2692,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--signer",
@ -2750,7 +2701,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
signers: Some(vec![(key1, sig1)]),
@ -2769,7 +2720,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--signer",
@ -2781,7 +2731,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
signers: Some(vec![(key1, sig1), (key2, sig2)]),
@ -2797,7 +2747,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
]);
@ -2805,7 +2754,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
..PayCommand::default()
@ -2822,7 +2771,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
@ -2832,7 +2780,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey),
@ -2851,7 +2799,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
@ -2863,7 +2810,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey),
@ -2885,7 +2832,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
@ -2899,7 +2845,7 @@ mod tests {
parse_command(&test_pay).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
nonce_account: Some(pubkey),
@ -2923,7 +2869,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
@ -2954,7 +2899,6 @@ mod tests {
"pay",
&pubkey_string,
"50",
"lamports",
"--after",
"2018-09-19T17:30:59",
"--require-signature-from",
@ -2968,7 +2912,7 @@ mod tests {
parse_command(&test_pay_multiple_witnesses).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
lamports: 50,
lamports: 50_000_000_000,
to: pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(witness0),
@ -3269,11 +3213,12 @@ mod tests {
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
// Need airdrop cases
let to = Pubkey::new_rand();
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: 1234,
pubkey: Some(to),
lamports: 50,
use_lamports_unit: true,
};
assert!(process_command(&config).is_ok());
@ -3310,8 +3255,8 @@ mod tests {
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: 1234,
pubkey: None,
lamports: 50,
use_lamports_unit: true,
};
assert!(process_command(&config).is_err());
@ -3420,35 +3365,13 @@ mod tests {
fn test_parse_transfer_subcommand() {
let test_commands = app("test", "desc", "version");
//Test Transfer Subcommand, lamports
//Test Transfer Subcommand, SOL
let from_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let from_pubkey = from_keypair.pubkey();
let from_string = from_pubkey.to_string();
let to_keypair = keypair_from_seed(&[1u8; 32]).unwrap();
let to_pubkey = to_keypair.pubkey();
let to_string = to_pubkey.to_string();
let test_transfer = test_commands
.clone()
.get_matches_from(vec!["test", "transfer", &to_string, "42", "lamports"]);
assert_eq!(
parse_command(&test_transfer).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
lamports: 42,
to: to_pubkey,
from: None,
sign_only: false,
signers: None,
blockhash_query: BlockhashQuery::All,
nonce_account: None,
nonce_authority: None,
fee_payer: None,
},
require_keypair: true,
}
);
//Test Transfer Subcommand, SOL
let test_transfer = test_commands
.clone()
.get_matches_from(vec!["test", "transfer", &to_string, "42"]);
@ -3478,7 +3401,6 @@ mod tests {
"transfer",
&to_string,
"42",
"lamports",
"--blockhash",
&blockhash_string,
"--sign-only",
@ -3487,7 +3409,7 @@ mod tests {
parse_command(&test_transfer).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
lamports: 42,
lamports: 42_000_000_000,
to: to_pubkey,
from: None,
sign_only: true,
@ -3509,7 +3431,6 @@ mod tests {
"transfer",
&to_string,
"42",
"lamports",
"--from",
&from_string,
"--fee-payer",
@ -3523,7 +3444,7 @@ mod tests {
parse_command(&test_transfer).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
lamports: 42,
lamports: 42_000_000_000,
to: to_pubkey,
from: Some(from_pubkey.into()),
sign_only: false,
@ -3548,7 +3469,6 @@ mod tests {
"transfer",
&to_string,
"42",
"lamports",
"--blockhash",
&blockhash_string,
"--nonce",
@ -3560,7 +3480,7 @@ mod tests {
parse_command(&test_transfer).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
lamports: 42,
lamports: 42_000_000_000,
to: to_pubkey,
from: None,
sign_only: false,

View File

@ -17,7 +17,7 @@ use solana_sdk::{
epoch_schedule::Epoch,
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_transaction,
};
use std::{

View File

@ -1,7 +1,7 @@
use crate::cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
log_instruction_custom_error, required_lamports_from, CliCommand, CliCommandInfo, CliConfig,
CliError, ProcessResult, SigningAuthority,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
SigningAuthority,
};
use crate::offline::BLOCKHASH_ARG;
use clap::{App, Arg, ArgMatches, SubCommand};
@ -13,7 +13,7 @@ use solana_sdk::{
hash::Hash,
nonce_state::{Meta, NonceState},
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_instruction::{
advance_nonce_account, authorize_nonce_account, create_address_with_seed,
create_nonce_account, create_nonce_account_with_seed, withdraw_nonce_account, NonceError,
@ -121,15 +121,7 @@ impl NonceSubCommands for App<'_, '_> {
.takes_value(true)
.required(true)
.validator(is_amount)
.help("The amount to load the nonce account with (default unit SOL)"),
)
.arg(
Arg::with_name("unit")
.index(3)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request"),
.help("The amount to load the nonce account with, in SOL"),
)
.arg(
Arg::with_name(NONCE_AUTHORITY_ARG.name)
@ -216,15 +208,7 @@ impl NonceSubCommands for App<'_, '_> {
.takes_value(true)
.required(true)
.validator(is_amount)
.help("The amount to withdraw from the nonce 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"),
.help("The amount to withdraw from the nonce account, in SOL"),
)
.arg(nonce_authority_arg()),
)
@ -250,7 +234,7 @@ pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliComm
pub fn parse_nonce_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let nonce_account = keypair_of(matches, "nonce_account_keypair").unwrap();
let seed = matches.value_of("seed").map(|s| s.to_string());
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
let nonce_authority = pubkey_of(matches, NONCE_AUTHORITY_ARG.name);
Ok(CliCommandInfo {
@ -305,7 +289,7 @@ pub fn parse_withdraw_from_nonce_account(
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
let nonce_authority =
SigningAuthority::new_from_matches(&matches, NONCE_AUTHORITY_ARG.name, None)?;
@ -689,7 +673,6 @@ mod tests {
"create-nonce-account",
&keypair_file,
"50",
"lamports",
]);
assert_eq!(
parse_command(&test_create_nonce_account).unwrap(),
@ -698,7 +681,7 @@ mod tests {
nonce_account: read_keypair_file(&keypair_file).unwrap().into(),
seed: None,
nonce_authority: None,
lamports: 50,
lamports: 50_000_000_000,
},
require_keypair: true
}
@ -710,7 +693,6 @@ mod tests {
"create-nonce-account",
&keypair_file,
"50",
"lamports",
"--nonce-authority",
&authority_keypair_file,
]);
@ -723,7 +705,7 @@ mod tests {
nonce_authority: Some(
read_keypair_file(&authority_keypair_file).unwrap().pubkey()
),
lamports: 50,
lamports: 50_000_000_000,
},
require_keypair: true
}
@ -806,7 +788,6 @@ mod tests {
&keypair_file,
&nonce_account_string,
"42",
"lamports",
]);
assert_eq!(
parse_command(&test_withdraw_from_nonce_account).unwrap(),
@ -815,7 +796,7 @@ mod tests {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: None,
destination_account_pubkey: nonce_account_pubkey,
lamports: 42
lamports: 42_000_000_000
},
require_keypair: true
}
@ -827,7 +808,6 @@ mod tests {
&keypair_file,
&nonce_account_string,
"42",
"SOL",
]);
assert_eq!(
parse_command(&test_withdraw_from_nonce_account).unwrap(),
@ -849,7 +829,6 @@ mod tests {
&keypair_file,
&nonce_account_string,
"42",
"lamports",
"--nonce-authority",
&authority_keypair_file,
]);
@ -862,7 +841,7 @@ mod tests {
read_keypair_file(&authority_keypair_file).unwrap().into()
),
destination_account_pubkey: nonce_account_pubkey,
lamports: 42
lamports: 42_000_000_000
},
require_keypair: true
}

View File

@ -1,9 +1,9 @@
use crate::{
cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys, fee_payer_arg,
log_instruction_custom_error, nonce_authority_arg, replace_signatures,
required_lamports_from, return_signers, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult, SigningAuthority, FEE_PAYER_ARG,
log_instruction_custom_error, nonce_authority_arg, replace_signatures, return_signers,
CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult, SigningAuthority,
FEE_PAYER_ARG,
},
nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
offline::*,
@ -16,7 +16,7 @@ use solana_sdk::signature::{Keypair, Signature};
use solana_sdk::{
account_utils::StateMut,
pubkey::Pubkey,
signature::KeypairUtil,
signature::Signer,
system_instruction::{create_address_with_seed, SystemError},
sysvar::{
stake_history::{self, StakeHistory},
@ -86,15 +86,7 @@ impl StakeSubCommands for App<'_, '_> {
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The amount of send to the vote account (default unit SOL)")
)
.arg(
Arg::with_name("unit")
.index(3)
.value_name("UNIT")
.takes_value(true)
.possible_values(&["SOL", "lamports"])
.help("Specify unit to use for request")
.help("The amount of send to the vote account, in SOL")
)
.arg(
Arg::with_name("custodian")
@ -287,15 +279,7 @@ impl StakeSubCommands for App<'_, '_> {
.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")
.help("The amount to move into the new stake account, in unit SOL")
)
.arg(
Arg::with_name("seed")
@ -338,15 +322,7 @@ impl StakeSubCommands for App<'_, '_> {
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The amount to withdraw from the 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")
.help("The amount to withdraw from the stake account, in SOL")
)
.arg(withdraw_authority_arg())
.offline_args()
@ -443,7 +419,7 @@ pub fn parse_stake_create_account(matches: &ArgMatches<'_>) -> Result<CliCommand
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
let staker = pubkey_of(matches, STAKE_AUTHORITY_ARG.name);
let withdrawer = pubkey_of(matches, WITHDRAW_AUTHORITY_ARG.name);
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
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);
@ -557,7 +533,7 @@ 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 lamports = lamports_of_sol(matches, "amount").unwrap();
let seed = matches.value_of("seed").map(|s| s.to_string());
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
@ -622,7 +598,7 @@ pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliComma
pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
let lamports = required_lamports_from(matches, "amount", "unit")?;
let lamports = lamports_of_sol(matches, "amount").unwrap();
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);
@ -1523,7 +1499,7 @@ mod tests {
use solana_sdk::{
fee_calculator::FeeCalculator,
hash::Hash,
signature::{keypair_from_seed, read_keypair_file, write_keypair, KeypairUtil},
signature::{keypair_from_seed, read_keypair_file, write_keypair, Signer},
};
use tempfile::NamedTempFile;
@ -1865,7 +1841,6 @@ mod tests {
&custodian_string,
"--lockup-epoch",
"43",
"lamports",
]);
assert_eq!(
parse_command(&test_create_stake_account).unwrap(),
@ -1880,7 +1855,7 @@ mod tests {
unix_timestamp: 0,
custodian,
},
lamports: 50,
lamports: 50_000_000_000,
sign_only: false,
signers: None,
blockhash_query: BlockhashQuery::All,
@ -1904,7 +1879,6 @@ mod tests {
"create-stake-account",
&keypair_file,
"50",
"lamports",
]);
assert_eq!(
@ -1916,7 +1890,7 @@ mod tests {
staker: None,
withdrawer: None,
lockup: Lockup::default(),
lamports: 50,
lamports: 50_000_000_000,
sign_only: false,
signers: None,
blockhash_query: BlockhashQuery::All,
@ -1944,7 +1918,6 @@ mod tests {
"create-stake-account",
&keypair_file,
"50",
"lamports",
"--blockhash",
&nonce_hash_string,
"--nonce",
@ -1968,7 +1941,7 @@ mod tests {
staker: None,
withdrawer: None,
lockup: Lockup::default(),
lamports: 50,
lamports: 50_000_000_000,
sign_only: false,
signers: Some(vec![(offline_pubkey, offline_sig)]),
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
@ -2270,7 +2243,6 @@ mod tests {
&stake_account_string,
&stake_account_string,
"42",
"lamports",
]);
assert_eq!(
@ -2279,7 +2251,7 @@ mod tests {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
destination_account_pubkey: stake_account_pubkey,
lamports: 42,
lamports: 42_000_000_000,
withdraw_authority: None,
sign_only: false,
signers: None,
@ -2299,7 +2271,6 @@ mod tests {
&stake_account_string,
&stake_account_string,
"42",
"lamports",
"--withdraw-authority",
&stake_authority_keypair_file,
]);
@ -2310,7 +2281,7 @@ mod tests {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
destination_account_pubkey: stake_account_pubkey,
lamports: 42,
lamports: 42_000_000_000,
withdraw_authority: Some(
read_keypair_file(&stake_authority_keypair_file)
.unwrap()
@ -2334,7 +2305,6 @@ mod tests {
&stake_account_string,
&stake_account_string,
"42",
"lamports",
"--withdraw-authority",
&stake_authority_keypair_file,
"--blockhash",
@ -2355,7 +2325,7 @@ mod tests {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
destination_account_pubkey: stake_account_pubkey,
lamports: 42,
lamports: 42_000_000_000,
withdraw_authority: Some(
read_keypair_file(&stake_authority_keypair_file)
.unwrap()
@ -2608,7 +2578,6 @@ mod tests {
&keypair_file,
&split_stake_account_keypair_file,
"50",
"lamports",
]);
assert_eq!(
parse_command(&test_split_stake_account).unwrap(),
@ -2625,7 +2594,7 @@ mod tests {
.unwrap()
.into(),
seed: None,
lamports: 50,
lamports: 50_000_000_000,
fee_payer: None,
},
require_keypair: true
@ -2654,7 +2623,6 @@ mod tests {
&keypair_file,
&split_stake_account_keypair_file,
"50",
"lamports",
"--stake-authority",
&stake_auth_string,
"--blockhash",
@ -2688,7 +2656,7 @@ mod tests {
.unwrap()
.into(),
seed: None,
lamports: 50,
lamports: 50_000_000_000,
fee_payer: Some(nonce_auth_pubkey.into()),
},
require_keypair: false,

View File

@ -7,7 +7,7 @@ use solana_clap_utils::{input_parsers::*, input_validators::*};
use solana_client::rpc_client::RpcClient;
use solana_sdk::signature::Keypair;
use solana_sdk::{
account_utils::StateMut, message::Message, pubkey::Pubkey, signature::KeypairUtil,
account_utils::StateMut, message::Message, pubkey::Pubkey, signature::Signer,
system_instruction::SystemError, transaction::Transaction,
};
use solana_storage_program::storage_instruction::{self, StorageAccountType};

View File

@ -19,7 +19,7 @@ use solana_sdk::{
commitment_config::CommitmentConfig,
message::Message,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
transaction::Transaction,
};
use std::error;

View File

@ -9,7 +9,7 @@ use solana_sdk::{
account::Account,
pubkey::Pubkey,
signature::Keypair,
signature::KeypairUtil,
signature::Signer,
system_instruction::{create_address_with_seed, SystemError},
transaction::Transaction,
};

View File

@ -42,8 +42,8 @@ fn test_cli_deploy_program() {
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: minimum_balance_for_rent_exemption + 1, // min balance for rent exemption + leftover for tx processing
use_lamports_unit: true,
};
process_command(&config).unwrap();

View File

@ -6,7 +6,7 @@ use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
hash::Hash,
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
signature::{read_keypair_file, write_keypair, Keypair, Signer},
system_instruction::create_address_with_seed,
system_program,
};

View File

@ -11,7 +11,7 @@ use solana_sdk::{
fee_calculator::FeeCalculator,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, KeypairUtil},
signature::{read_keypair_file, write_keypair, Keypair, Signer},
};
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;

View File

@ -2,7 +2,7 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::signature::Signer;
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;
@ -18,8 +18,8 @@ fn test_cli_request_airdrop() {
bob_config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 50,
use_lamports_unit: true,
};
let sig_response = process_command(&bob_config);

View File

@ -9,7 +9,7 @@ use solana_sdk::{
fee_calculator::FeeCalculator,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, read_keypair_file, write_keypair, Keypair, KeypairUtil},
signature::{keypair_from_seed, read_keypair_file, write_keypair, Keypair, Signer},
system_instruction::create_address_with_seed,
};
use solana_stake_program::stake_state::{Lockup, StakeAuthorize, StakeState};

View File

@ -9,7 +9,7 @@ use solana_sdk::{
fee_calculator::FeeCalculator,
nonce_state::NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, read_keypair_file, write_keypair, KeypairUtil},
signature::{keypair_from_seed, read_keypair_file, write_keypair, Signer},
};
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "0.23.5"
version = "0.23.6"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -19,11 +19,12 @@ reqwest = { version = "0.10.1", default-features = false, features = ["blocking"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-net-utils = { path = "../net-utils", version = "0.23.5" }
solana-sdk = { path = "../sdk", version = "0.23.5" }
solana-net-utils = { path = "../net-utils", version = "0.23.6" }
solana-sdk = { path = "../sdk", version = "0.23.6" }
thiserror = "1.0"
[dev-dependencies]
assert_matches = "1.3.0"
jsonrpc-core = "14.0.5"
jsonrpc-http-server = "14.0.5"
solana-logger = { path = "../logger", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.6" }

View File

@ -1,14 +1,16 @@
use crate::rpc_request;
use solana_sdk::transaction::TransactionError;
use solana_sdk::{signature::SignerError, transaction::TransactionError};
use std::{fmt, io};
use thiserror::Error;
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum ClientError {
Io(io::Error),
Reqwest(reqwest::Error),
RpcError(rpc_request::RpcError),
SerdeJson(serde_json::error::Error),
TransactionError(TransactionError),
Io(#[from] io::Error),
Reqwest(#[from] reqwest::Error),
RpcError(#[from] rpc_request::RpcError),
SerdeJson(#[from] serde_json::error::Error),
SigningError(#[from] SignerError),
TransactionError(#[from] TransactionError),
}
impl fmt::Display for ClientError {
@ -16,35 +18,3 @@ impl fmt::Display for ClientError {
write!(f, "solana client error")
}
}
impl std::error::Error for ClientError {}
impl From<io::Error> for ClientError {
fn from(err: io::Error) -> ClientError {
ClientError::Io(err)
}
}
impl From<reqwest::Error> for ClientError {
fn from(err: reqwest::Error) -> ClientError {
ClientError::Reqwest(err)
}
}
impl From<rpc_request::RpcError> for ClientError {
fn from(err: rpc_request::RpcError) -> ClientError {
ClientError::RpcError(err)
}
}
impl From<serde_json::error::Error> for ClientError {
fn from(err: serde_json::error::Error) -> ClientError {
ClientError::SerdeJson(err)
}
}
impl From<TransactionError> for ClientError {
fn from(err: TransactionError) -> ClientError {
ClientError::TransactionError(err)
}
}

View File

@ -22,7 +22,8 @@ use solana_sdk::{
hash::Hash,
inflation::Inflation,
pubkey::Pubkey,
signature::{KeypairUtil, Signature},
signature::Signature,
signers::Signers,
transaction::{self, Transaction, TransactionError},
};
use std::{
@ -405,10 +406,10 @@ impl RpcClient {
})
}
pub fn send_and_confirm_transaction<T: KeypairUtil>(
pub fn send_and_confirm_transaction<T: Signers>(
&self,
transaction: &mut Transaction,
signer_keys: &[&T],
signer_keys: &T,
) -> Result<String, ClientError> {
let mut send_retries = 20;
loop {
@ -456,10 +457,10 @@ impl RpcClient {
}
}
pub fn send_and_confirm_transactions<T: KeypairUtil>(
pub fn send_and_confirm_transactions<T: Signers>(
&self,
mut transactions: Vec<Transaction>,
signer_keys: &[&T],
signer_keys: &T,
) -> Result<(), Box<dyn error::Error>> {
let mut send_retries = 5;
loop {
@ -516,24 +517,22 @@ impl RpcClient {
// Re-sign any failed transactions with a new blockhash and retry
let (blockhash, _fee_calculator) =
self.get_new_blockhash(&transactions_signatures[0].0.message().recent_blockhash)?;
transactions = transactions_signatures
.into_iter()
.map(|(mut transaction, _)| {
transaction.sign(signer_keys, blockhash);
transaction
})
.collect();
transactions = vec![];
for (mut transaction, _) in transactions_signatures.into_iter() {
transaction.try_sign(signer_keys, blockhash)?;
transactions.push(transaction);
}
}
}
pub fn resign_transaction<T: KeypairUtil>(
pub fn resign_transaction<T: Signers>(
&self,
tx: &mut Transaction,
signer_keys: &[&T],
signer_keys: &T,
) -> Result<(), ClientError> {
let (blockhash, _fee_calculator) =
self.get_new_blockhash(&tx.message().recent_blockhash)?;
tx.sign(signer_keys, blockhash);
tx.try_sign(signer_keys, blockhash)?;
Ok(())
}

View File

@ -17,7 +17,8 @@ use solana_sdk::{
message::Message,
packet::PACKET_DATA_SIZE,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature},
signature::{Keypair, Signature, Signer},
signers::Signers,
system_instruction,
timing::duration_as_ms,
transaction::{self, Transaction},
@ -202,9 +203,9 @@ impl ThinClient {
}
/// Retry sending a signed Transaction to the server for processing
pub fn send_and_confirm_transaction(
pub fn send_and_confirm_transaction<T: Signers>(
&self,
keypairs: &[&Keypair],
keypairs: &T,
transaction: &mut Transaction,
tries: usize,
pending_confirmations: usize,
@ -351,9 +352,13 @@ impl Client for ThinClient {
}
impl SyncClient for ThinClient {
fn send_message(&self, keypairs: &[&Keypair], message: Message) -> TransportResult<Signature> {
fn send_message<T: Signers>(
&self,
keypairs: &T,
message: Message,
) -> TransportResult<Signature> {
let (blockhash, _fee_calculator) = self.get_recent_blockhash()?;
let mut transaction = Transaction::new(&keypairs, message, blockhash);
let mut transaction = Transaction::new(keypairs, message, blockhash);
let signature = self.send_and_confirm_transaction(keypairs, &mut transaction, 5, 0)?;
Ok(signature)
}
@ -561,13 +566,13 @@ impl AsyncClient for ThinClient {
.send_to(&buf[..], &self.tpu_addr())?;
Ok(transaction.signatures[0])
}
fn async_send_message(
fn async_send_message<T: Signers>(
&self,
keypairs: &[&Keypair],
keypairs: &T,
message: Message,
recent_blockhash: Hash,
) -> io::Result<Signature> {
let transaction = Transaction::new(&keypairs, message, recent_blockhash);
let transaction = Transaction::new(keypairs, message, recent_blockhash);
self.async_send_transaction(transaction)
}
fn async_send_instruction(

View File

@ -1,7 +1,7 @@
[package]
name = "solana-core"
description = "Blockchain, Rebuilt for Scale"
version = "0.23.5"
version = "0.23.6"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -18,6 +18,7 @@ bincode = "1.2.1"
bs58 = "0.3.0"
byteorder = "1.3.2"
chrono = { version = "0.4.10", features = ["serde"] }
compression = "0.1.5"
core_affinity = "0.5.10"
crc = { version = "1.8.1", optional = true }
crossbeam-channel = "0.3"
@ -40,26 +41,26 @@ rayon = "1.2.0"
serde = "1.0.104"
serde_derive = "1.0.103"
serde_json = "1.0.44"
solana-budget-program = { path = "../programs/budget", version = "0.23.5" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.5" }
solana-client = { path = "../client", version = "0.23.5" }
solana-faucet = { path = "../faucet", version = "0.23.5" }
solana-budget-program = { path = "../programs/budget", version = "0.23.6" }
solana-clap-utils = { path = "../clap-utils", version = "0.23.6" }
solana-client = { path = "../client", version = "0.23.6" }
solana-faucet = { path = "../faucet", version = "0.23.6" }
ed25519-dalek = "=1.0.0-pre.1"
solana-ledger = { path = "../ledger", version = "0.23.5" }
solana-logger = { path = "../logger", version = "0.23.5" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.5" }
solana-metrics = { path = "../metrics", version = "0.23.5" }
solana-measure = { path = "../measure", version = "0.23.5" }
solana-net-utils = { path = "../net-utils", version = "0.23.5" }
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.5" }
solana-perf = { path = "../perf", version = "0.23.5" }
solana-runtime = { path = "../runtime", version = "0.23.5" }
solana-sdk = { path = "../sdk", version = "0.23.5" }
solana-stake-program = { path = "../programs/stake", version = "0.23.5" }
solana-storage-program = { path = "../programs/storage", version = "0.23.5" }
solana-vote-program = { path = "../programs/vote", version = "0.23.5" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.5" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.5" }
solana-ledger = { path = "../ledger", version = "0.23.6" }
solana-logger = { path = "../logger", version = "0.23.6" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.23.6" }
solana-metrics = { path = "../metrics", version = "0.23.6" }
solana-measure = { path = "../measure", version = "0.23.6" }
solana-net-utils = { path = "../net-utils", version = "0.23.6" }
solana-chacha-cuda = { path = "../chacha-cuda", version = "0.23.6" }
solana-perf = { path = "../perf", version = "0.23.6" }
solana-runtime = { path = "../runtime", version = "0.23.6" }
solana-sdk = { path = "../sdk", version = "0.23.6" }
solana-stake-program = { path = "../programs/stake", version = "0.23.6" }
solana-storage-program = { path = "../programs/storage", version = "0.23.6" }
solana-vote-program = { path = "../programs/vote", version = "0.23.6" }
solana-vote-signer = { path = "../vote-signer", version = "0.23.6" }
solana-sys-tuner = { path = "../sys-tuner", version = "0.23.6" }
symlink = "0.1.0"
sys-info = "0.5.8"
tempfile = "3.1.0"
@ -69,7 +70,7 @@ tokio-codec = "0.1"
tokio-fs = "0.1"
tokio-io = "0.1"
untrusted = "0.7.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.5" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.23.6" }
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
[dev-dependencies]

View File

@ -21,8 +21,8 @@ use solana_sdk::genesis_config::GenesisConfig;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::signature::Signature;
use solana_sdk::signature::Signer;
use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
use solana_sdk::timing::{duration_as_us, timestamp};

View File

@ -3,7 +3,7 @@ extern crate test;
use solana_ledger::entry::{next_entry_mut, Entry, EntrySlice};
use solana_sdk::hash::{hash, Hash};
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_transaction;
use test::Bencher;

View File

@ -9,7 +9,7 @@ use solana_ledger::shred::{
};
use solana_perf::test_tx;
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::sync::Arc;
use test::Bencher;

View File

@ -11,7 +11,7 @@ use solana_core::sigverify::TransactionSigVerifier;
use solana_core::sigverify_stage::SigVerifyStage;
use solana_perf::test_tx::test_tx;
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_transaction;
use solana_sdk::timing::duration_as_ms;
use std::sync::mpsc::channel;

View File

@ -1029,7 +1029,7 @@ mod tests {
use solana_runtime::bank::HashAgeKind;
use solana_sdk::{
instruction::InstructionError,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_transaction,
transaction::TransactionError,
};

View File

@ -180,7 +180,7 @@ mod test {
use chrono::{DateTime, FixedOffset};
use serde_json::Value;
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_transaction;
use std::collections::HashSet;
use std::path::PathBuf;

View File

@ -107,7 +107,7 @@ mod test {
use solana_ledger::create_new_tmp_ledger;
use solana_ledger::entry::{create_ticks, Entry};
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_transaction;
use std::path::PathBuf;
use std::sync::mpsc::channel;

View File

@ -259,7 +259,7 @@ mod test {
use solana_runtime::bank::Bank;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::path::Path;
use std::sync::atomic::AtomicBool;
use std::sync::mpsc::channel;

View File

@ -82,7 +82,7 @@ impl BroadcastRun for FailEntryVerificationBroadcastRun {
// Broadcast data
let all_shred_bufs: Vec<Vec<u8>> = shreds.to_vec().into_iter().map(|s| s.payload).collect();
cluster_info
.read()
.write()
.unwrap()
.broadcast_shreds(sock, all_shred_bufs, &all_seeds, stakes)?;
Ok(())

View File

@ -264,7 +264,7 @@ impl StandardBroadcastRun {
trace!("Broadcasting {:?} shreds", shred_bufs.len());
cluster_info
.read()
.write()
.unwrap()
.broadcast_shreds(sock, shred_bufs, &seeds, stakes)?;
@ -362,7 +362,7 @@ mod test {
use solana_sdk::{
clock::Slot,
genesis_config::GenesisConfig,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
};
use std::sync::{Arc, RwLock};
use std::time::Duration;

View File

@ -12,6 +12,8 @@
//! * layer 2 - Everyone else, if layer 1 is `2^10`, layer 2 should be able to fit `2^20` number of nodes.
//!
//! Bank needs to provide an interface for us to query the stake weight
use crate::crds_value::CompressionType::*;
use crate::crds_value::EpochIncompleteSlots;
use crate::packet::limited_deserialize;
use crate::streamer::{PacketReceiver, PacketSender};
use crate::{
@ -19,15 +21,19 @@ use crate::{
crds_gossip::CrdsGossip,
crds_gossip_error::CrdsGossipError,
crds_gossip_pull::{CrdsFilter, CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS},
crds_value::{self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlots, Vote},
crds_value::{self, CrdsData, CrdsValue, CrdsValueLabel, EpochSlots, SnapshotHash, Vote},
packet::{Packet, PACKET_DATA_SIZE},
result::{Error, Result},
sendmmsg::{multicast, send_mmsg},
weighted_shuffle::{weighted_best, weighted_shuffle},
};
use bincode::{serialize, serialized_size};
use compression::prelude::*;
use core::cmp;
use itertools::Itertools;
use rayon::iter::IntoParallelIterator;
use rayon::iter::ParallelIterator;
use rayon::ThreadPool;
use solana_ledger::{bank_forks::BankForks, staking_utils};
use solana_measure::thread_mem_usage;
use solana_metrics::{datapoint_debug, inc_new_counter_debug, inc_new_counter_error};
@ -36,6 +42,9 @@ use solana_net_utils::{
multi_bind_in_range, PortRange,
};
use solana_perf::packet::{to_packets_with_destination, Packets, PacketsRecycler};
use solana_rayon_threadlimit::get_thread_count;
use solana_sdk::hash::Hash;
use solana_sdk::timing::duration_as_s;
use solana_sdk::{
clock::{Slot, DEFAULT_MS_PER_SLOT},
pubkey::Pubkey,
@ -67,6 +76,13 @@ pub const MAX_BLOOM_SIZE: usize = 1018;
const MAX_PROTOCOL_PAYLOAD_SIZE: u64 = PACKET_DATA_SIZE as u64 - MAX_PROTOCOL_HEADER_SIZE;
/// The largest protocol header size
const MAX_PROTOCOL_HEADER_SIZE: u64 = 214;
/// A hard limit on incoming gossip messages
/// Chosen to be able to handle 1Gbps of pure gossip traffic
/// 128MB/PACKET_DATA_SIZE
const MAX_GOSSIP_TRAFFIC: usize = 128_000_000 / PACKET_DATA_SIZE;
const NUM_BITS_PER_BYTE: u64 = 8;
const MIN_SIZE_TO_COMPRESS_GZIP: u64 = 64;
#[derive(Debug, PartialEq, Eq)]
pub enum ClusterInfoError {
@ -83,6 +99,7 @@ pub struct ClusterInfo {
pub(crate) keypair: Arc<Keypair>,
/// The network entrypoint
entrypoint: Option<ContactInfo>,
last_datapoint_submit: Instant,
}
#[derive(Default, Clone)]
@ -182,6 +199,7 @@ impl ClusterInfo {
gossip: CrdsGossip::default(),
keypair,
entrypoint: None,
last_datapoint_submit: Instant::now(),
};
let id = contact_info.id;
me.gossip.set_self(&id);
@ -307,10 +325,125 @@ impl ClusterInfo {
)
}
pub fn push_epoch_slots(&mut self, id: Pubkey, root: Slot, min: Slot, slots: BTreeSet<Slot>) {
pub fn compress_incomplete_slots(incomplete_slots: &BTreeSet<Slot>) -> EpochIncompleteSlots {
if !incomplete_slots.is_empty() {
let first_slot = incomplete_slots
.iter()
.next()
.expect("expected to find at least one slot");
let last_slot = incomplete_slots
.iter()
.next_back()
.expect("expected to find last slot");
let num_uncompressed_bits = last_slot.saturating_sub(*first_slot) + 1;
let num_uncompressed_bytes = if num_uncompressed_bits % NUM_BITS_PER_BYTE > 0 {
1
} else {
0
} + num_uncompressed_bits / NUM_BITS_PER_BYTE;
let mut uncompressed = vec![0u8; num_uncompressed_bytes as usize];
incomplete_slots.iter().for_each(|slot| {
let offset_from_first_slot = slot.saturating_sub(*first_slot);
let index = offset_from_first_slot / NUM_BITS_PER_BYTE;
let bit_index = offset_from_first_slot % NUM_BITS_PER_BYTE;
uncompressed[index as usize] |= 1 << bit_index;
});
if num_uncompressed_bytes >= MIN_SIZE_TO_COMPRESS_GZIP {
if let Ok(compressed) = uncompressed
.iter()
.cloned()
.encode(&mut GZipEncoder::new(), Action::Finish)
.collect::<std::result::Result<Vec<u8>, _>>()
{
return EpochIncompleteSlots {
first: *first_slot,
compression: GZip,
compressed_list: compressed,
};
}
} else {
return EpochIncompleteSlots {
first: *first_slot,
compression: Uncompressed,
compressed_list: uncompressed,
};
}
}
EpochIncompleteSlots::default()
}
fn bitmap_to_slot_list(first: Slot, bitmap: &[u8]) -> BTreeSet<Slot> {
let mut old_incomplete_slots: BTreeSet<Slot> = BTreeSet::new();
bitmap.iter().enumerate().for_each(|(i, val)| {
if *val != 0 {
(0..8).for_each(|bit_index| {
if (1 << bit_index & *val) != 0 {
let slot = first + i as u64 * NUM_BITS_PER_BYTE + bit_index as u64;
old_incomplete_slots.insert(slot);
}
})
}
});
old_incomplete_slots
}
pub fn decompress_incomplete_slots(slots: &EpochIncompleteSlots) -> BTreeSet<Slot> {
match slots.compression {
Uncompressed => Self::bitmap_to_slot_list(slots.first, &slots.compressed_list),
GZip => {
if let Ok(decompressed) = slots
.compressed_list
.iter()
.cloned()
.decode(&mut GZipDecoder::new())
.collect::<std::result::Result<Vec<u8>, _>>()
{
Self::bitmap_to_slot_list(slots.first, &decompressed)
} else {
BTreeSet::new()
}
}
BZip2 => {
if let Ok(decompressed) = slots
.compressed_list
.iter()
.cloned()
.decode(&mut BZip2Decoder::new())
.collect::<std::result::Result<Vec<u8>, _>>()
{
Self::bitmap_to_slot_list(slots.first, &decompressed)
} else {
BTreeSet::new()
}
}
}
}
pub fn push_epoch_slots(
&mut self,
id: Pubkey,
root: Slot,
min: Slot,
slots: BTreeSet<Slot>,
incomplete_slots: &BTreeSet<Slot>,
) {
let compressed = Self::compress_incomplete_slots(incomplete_slots);
let now = timestamp();
let entry = CrdsValue::new_signed(
CrdsData::EpochSlots(EpochSlots::new(id, root, min, slots, now)),
CrdsData::EpochSlots(
0,
EpochSlots::new(id, root, min, slots, vec![compressed], now),
),
&self.keypair,
);
self.gossip
.process_push_message(&self.id(), vec![entry], now);
}
pub fn push_snapshot_hashes(&mut self, snapshot_hashes: Vec<(Slot, Hash)>) {
let now = timestamp();
let entry = CrdsValue::new_signed(
CrdsData::SnapshotHash(SnapshotHash::new(self.id(), snapshot_hashes, now)),
&self.keypair,
);
self.gossip
@ -357,6 +490,31 @@ impl ClusterInfo {
(txs, max_ts)
}
pub fn get_snapshot_hash(&self, slot: Slot) -> Vec<(Pubkey, Hash)> {
self.gossip
.crds
.table
.values()
.filter_map(|x| x.value.snapshot_hash().map(|v| v))
.filter_map(|x| {
for (table_slot, hash) in &x.hashes {
if *table_slot == slot {
return Some((x.from, *hash));
}
}
None
})
.collect()
}
pub fn get_snapshot_hash_for_node(&self, pubkey: &Pubkey) -> Option<&Vec<(Slot, Hash)>> {
self.gossip
.crds
.table
.get(&CrdsValueLabel::SnapshotHash(*pubkey))
.map(|x| &x.value.snapshot_hash().unwrap().hashes)
}
pub fn get_epoch_state_for_node(
&self,
pubkey: &Pubkey,
@ -374,19 +532,6 @@ impl ClusterInfo {
.map(|x| (x.value.epoch_slots().unwrap(), x.insert_timestamp))
}
pub fn get_gossiped_root_for_node(&self, pubkey: &Pubkey, since: Option<u64>) -> Option<u64> {
self.gossip
.crds
.table
.get(&CrdsValueLabel::EpochSlots(*pubkey))
.filter(|x| {
since
.map(|since| x.insert_timestamp > since)
.unwrap_or(true)
})
.map(|x| x.value.epoch_slots().unwrap().root)
}
pub fn get_contact_info_for_node(&self, pubkey: &Pubkey) -> Option<&ContactInfo> {
self.gossip
.crds
@ -772,7 +917,7 @@ impl ClusterInfo {
/// broadcast messages from the leader to layer 1 nodes
/// # Remarks
pub fn broadcast_shreds(
&self,
&mut self,
s: &UdpSocket,
shreds: Vec<Vec<u8>>,
seeds: &[[u8; 32]],
@ -781,11 +926,14 @@ impl ClusterInfo {
let (peers, peers_and_stakes) = self.sorted_tvu_peers_and_stakes(stakes);
let broadcast_len = peers_and_stakes.len();
if broadcast_len == 0 {
datapoint_debug!(
"cluster_info-num_nodes",
("live_count", 1, i64),
("broadcast_count", 1, i64)
);
if duration_as_s(&Instant::now().duration_since(self.last_datapoint_submit)) >= 1.0 {
datapoint_info!(
"cluster_info-num_nodes",
("live_count", 1, i64),
("broadcast_count", 1, i64)
);
self.last_datapoint_submit = Instant::now();
}
return Ok(());
}
let mut packets: Vec<_> = shreds
@ -815,11 +963,14 @@ impl ClusterInfo {
num_live_peers += 1;
}
});
datapoint_debug!(
"cluster_info-num_nodes",
("live_count", num_live_peers, i64),
("broadcast_count", broadcast_len + 1, i64)
);
if duration_as_s(&Instant::now().duration_since(self.last_datapoint_submit)) >= 1.0 {
datapoint_info!(
"cluster_info-num_nodes",
("live_count", num_live_peers, i64),
("broadcast_count", broadcast_len + 1, i64)
);
self.last_datapoint_submit = Instant::now();
}
Ok(())
}
@ -1361,10 +1512,22 @@ impl ClusterInfo {
bank_forks: Option<&Arc<RwLock<BankForks>>>,
requests_receiver: &PacketReceiver,
response_sender: &PacketSender,
thread_pool: &ThreadPool,
) -> Result<()> {
//TODO cache connections
let timeout = Duration::new(1, 0);
let reqs = requests_receiver.recv_timeout(timeout)?;
let mut requests = vec![requests_receiver.recv_timeout(timeout)?];
let mut num_requests = requests.last().unwrap().packets.len();
while let Ok(more_reqs) = requests_receiver.try_recv() {
if num_requests >= MAX_GOSSIP_TRAFFIC {
continue;
}
num_requests += more_reqs.packets.len();
requests.push(more_reqs)
}
if num_requests >= MAX_GOSSIP_TRAFFIC {
warn!("Too much gossip traffic, ignoring some messages");
}
let epoch_ms;
let stakes: HashMap<_, _> = match bank_forks {
Some(ref bank_forks) => {
@ -1380,8 +1543,13 @@ impl ClusterInfo {
HashMap::new()
}
};
let sender = response_sender.clone();
thread_pool.install(|| {
requests.into_par_iter().for_each_with(sender, |s, reqs| {
Self::handle_packets(obj, &recycler, &stakes, reqs, s, epoch_ms)
});
});
Self::handle_packets(obj, &recycler, &stakes, reqs, response_sender, epoch_ms);
Ok(())
}
pub fn listen(
@ -1395,26 +1563,33 @@ impl ClusterInfo {
let recycler = PacketsRecycler::default();
Builder::new()
.name("solana-listen".to_string())
.spawn(move || loop {
let e = Self::run_listen(
&me,
&recycler,
bank_forks.as_ref(),
&requests_receiver,
&response_sender,
);
if exit.load(Ordering::Relaxed) {
return;
}
if e.is_err() {
let me = me.read().unwrap();
debug!(
"{}: run_listen timeout, table size: {}",
me.gossip.id,
me.gossip.crds.table.len()
.spawn(move || {
let thread_pool = rayon::ThreadPoolBuilder::new()
.num_threads(get_thread_count())
.build()
.unwrap();
loop {
let e = Self::run_listen(
&me,
&recycler,
bank_forks.as_ref(),
&requests_receiver,
&response_sender,
&thread_pool,
);
if exit.load(Ordering::Relaxed) {
return;
}
if e.is_err() {
let me = me.read().unwrap();
debug!(
"{}: run_listen timeout, table size: {}",
me.gossip.id,
me.gossip.crds.table.len()
);
}
thread_mem_usage::datapoint("solana-listen");
}
thread_mem_usage::datapoint("solana-listen");
})
.unwrap()
}
@ -1730,7 +1905,7 @@ mod tests {
use crate::crds_value::CrdsValueLabel;
use rayon::prelude::*;
use solana_perf::test_tx::test_tx;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, RwLock};
@ -2133,13 +2308,17 @@ mod tests {
for i in 0..128 {
btree_slots.insert(i);
}
let value = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots: btree_slots,
wallclock: 0,
}));
let value = CrdsValue::new_unsigned(CrdsData::EpochSlots(
0,
EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots: btree_slots,
stash: vec![],
wallclock: 0,
},
));
test_split_messages(value);
}
@ -2150,13 +2329,17 @@ mod tests {
let payload: Vec<CrdsValue> = vec![];
let vec_size = serialized_size(&payload).unwrap();
let desired_size = MAX_PROTOCOL_PAYLOAD_SIZE - vec_size;
let mut value = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots: BTreeSet::new(),
wallclock: 0,
}));
let mut value = CrdsValue::new_unsigned(CrdsData::EpochSlots(
0,
EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots: BTreeSet::new(),
stash: vec![],
wallclock: 0,
},
));
let mut i = 0;
while value.size() <= desired_size {
@ -2168,13 +2351,17 @@ mod tests {
desired_size
);
}
value.data = CrdsData::EpochSlots(EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots,
wallclock: 0,
});
value.data = CrdsData::EpochSlots(
0,
EpochSlots {
from: Pubkey::default(),
root: 0,
lowest: 0,
slots,
stash: vec![],
wallclock: 0,
},
);
i += 1;
}
let split = ClusterInfo::split_gossip_messages(vec![value.clone()]);
@ -2314,13 +2501,17 @@ mod tests {
let other_node_pubkey = Pubkey::new_rand();
let other_node = ContactInfo::new_localhost(&other_node_pubkey, timestamp());
cluster_info.insert_info(other_node.clone());
let value = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots::new(
other_node_pubkey,
peer_root,
peer_lowest,
BTreeSet::new(),
timestamp(),
)));
let value = CrdsValue::new_unsigned(CrdsData::EpochSlots(
0,
EpochSlots::new(
other_node_pubkey,
peer_root,
peer_lowest,
BTreeSet::new(),
vec![],
timestamp(),
),
));
let _ = cluster_info.gossip.crds.insert(value, timestamp());
}
// only half the visible peers should be eligible to serve this repair
@ -2380,4 +2571,38 @@ mod tests {
serialized_size(&protocol).expect("unable to serialize gossip protocol") as usize;
PACKET_DATA_SIZE - (protocol_size - filter_size)
}
#[test]
fn test_compress_incomplete_slots() {
let mut incomplete_slots: BTreeSet<Slot> = BTreeSet::new();
assert_eq!(
EpochIncompleteSlots::default(),
ClusterInfo::compress_incomplete_slots(&incomplete_slots)
);
incomplete_slots.insert(100);
let compressed = ClusterInfo::compress_incomplete_slots(&incomplete_slots);
assert_eq!(100, compressed.first);
let decompressed = ClusterInfo::decompress_incomplete_slots(&compressed);
assert_eq!(incomplete_slots, decompressed);
incomplete_slots.insert(104);
let compressed = ClusterInfo::compress_incomplete_slots(&incomplete_slots);
assert_eq!(100, compressed.first);
let decompressed = ClusterInfo::decompress_incomplete_slots(&compressed);
assert_eq!(incomplete_slots, decompressed);
incomplete_slots.insert(80);
let compressed = ClusterInfo::compress_incomplete_slots(&incomplete_slots);
assert_eq!(80, compressed.first);
let decompressed = ClusterInfo::decompress_incomplete_slots(&compressed);
assert_eq!(incomplete_slots, decompressed);
incomplete_slots.insert(10000);
let compressed = ClusterInfo::compress_incomplete_slots(&incomplete_slots);
assert_eq!(80, compressed.first);
let decompressed = ClusterInfo::decompress_incomplete_slots(&compressed);
assert_eq!(incomplete_slots, decompressed);
}
}

View File

@ -84,7 +84,7 @@ impl ClusterInfoVoteListener {
mod tests {
use crate::packet;
use solana_sdk::hash::Hash;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::transaction::Transaction;
use solana_vote_program::vote_instruction;
use solana_vote_program::vote_state::Vote;

View File

@ -1,6 +1,5 @@
use chrono::prelude::*;
use solana_ledger::bank_forks::BankForks;
use solana_metrics::datapoint_debug;
use solana_runtime::bank::Bank;
use solana_sdk::{
account::Account,
@ -118,7 +117,7 @@ impl Tower {
vote_state.nth_recent_vote(0).map(|v| v.slot).unwrap_or(0) as i64
);
debug!("observed root {}", vote_state.root_slot.unwrap_or(0) as i64);
datapoint_debug!(
datapoint_info!(
"tower-observed",
(
"slot",
@ -237,7 +236,7 @@ impl Tower {
self.lockouts.process_vote_unchecked(&vote);
self.last_vote = vote;
datapoint_debug!(
datapoint_info!(
"tower-vote",
("latest", slot, i64),
("root", self.lockouts.root_slot.unwrap_or(0), i64)

View File

@ -2,7 +2,7 @@ use solana_sdk::pubkey::Pubkey;
#[cfg(test)]
use solana_sdk::rpc_port;
#[cfg(test)]
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::timing::timestamp;
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::net::{IpAddr, SocketAddr};

View File

@ -3,11 +3,13 @@
//! designed to run with a simulator or over a UDP network connection with messages up to a
//! packet::PACKET_DATA_SIZE size.
use crate::crds::{Crds, VersionedCrdsValue};
use crate::crds_gossip_error::CrdsGossipError;
use crate::crds_gossip_pull::{CrdsFilter, CrdsGossipPull};
use crate::crds_gossip_push::{CrdsGossipPush, CRDS_GOSSIP_NUM_ACTIVE};
use crate::crds_value::{CrdsValue, CrdsValueLabel};
use crate::{
crds::{Crds, VersionedCrdsValue},
crds_gossip_error::CrdsGossipError,
crds_gossip_pull::{CrdsFilter, CrdsGossipPull},
crds_gossip_push::{CrdsGossipPush, CRDS_GOSSIP_NUM_ACTIVE},
crds_value::{CrdsValue, CrdsValueLabel},
};
use solana_sdk::pubkey::Pubkey;
use std::collections::{HashMap, HashSet};

View File

@ -8,25 +8,24 @@
//! the local nodes wallclock window they are drooped silently.
//! 2. The prune set is stored in a Bloom filter.
use crate::contact_info::ContactInfo;
use crate::crds::{Crds, VersionedCrdsValue};
use crate::crds_gossip::{get_stake, get_weight, CRDS_GOSSIP_DEFAULT_BLOOM_ITEMS};
use crate::crds_gossip_error::CrdsGossipError;
use crate::crds_value::{CrdsValue, CrdsValueLabel};
use crate::weighted_shuffle::weighted_shuffle;
use crate::{
contact_info::ContactInfo,
crds::{Crds, VersionedCrdsValue},
crds_gossip::{get_stake, get_weight, CRDS_GOSSIP_DEFAULT_BLOOM_ITEMS},
crds_gossip_error::CrdsGossipError,
crds_value::{CrdsValue, CrdsValueLabel},
weighted_shuffle::weighted_shuffle,
};
use bincode::serialized_size;
use indexmap::map::IndexMap;
use itertools::Itertools;
use rand;
use rand::seq::SliceRandom;
use rand::{thread_rng, RngCore};
use rand::{self, seq::SliceRandom, thread_rng, RngCore};
use solana_runtime::bloom::Bloom;
use solana_sdk::hash::Hash;
use solana_sdk::packet::PACKET_DATA_SIZE;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing::timestamp;
use std::cmp;
use std::collections::{HashMap, HashSet};
use solana_sdk::{hash::Hash, packet::PACKET_DATA_SIZE, pubkey::Pubkey, timing::timestamp};
use std::{
cmp,
collections::{HashMap, HashSet},
};
pub const CRDS_GOSSIP_NUM_ACTIVE: usize = 30;
pub const CRDS_GOSSIP_PUSH_FANOUT: usize = 6;

View File

@ -1,18 +1,23 @@
use crate::contact_info::ContactInfo;
use bincode::{serialize, serialized_size};
use solana_sdk::clock::Slot;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signable, Signature};
use solana_sdk::transaction::Transaction;
use std::borrow::Borrow;
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::collections::HashSet;
use std::fmt;
use solana_sdk::{
clock::Slot,
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, Signable, Signature},
transaction::Transaction,
};
use std::{
borrow::{Borrow, Cow},
collections::{BTreeSet, HashSet},
fmt,
};
pub type VoteIndex = u8;
pub const MAX_VOTES: VoteIndex = 32;
pub type EpochSlotIndex = u8;
/// CrdsValue that is replicated across the cluster
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct CrdsValue {
@ -50,15 +55,51 @@ impl Signable for CrdsValue {
}
/// CrdsData that defines the different types of items CrdsValues can hold
/// * Merge Strategy - Latest wallclock is picked
#[allow(clippy::large_enum_variant)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum CrdsData {
/// * Merge Strategy - Latest wallclock is picked
ContactInfo(ContactInfo),
/// * Merge Strategy - Latest wallclock is picked
Vote(VoteIndex, Vote),
/// * Merge Strategy - Latest wallclock is picked
EpochSlots(EpochSlots),
EpochSlots(EpochSlotIndex, EpochSlots),
SnapshotHash(SnapshotHash),
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum CompressionType {
Uncompressed,
GZip,
BZip2,
}
impl Default for CompressionType {
fn default() -> Self {
Self::Uncompressed
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
pub struct EpochIncompleteSlots {
pub first: Slot,
pub compression: CompressionType,
pub compressed_list: Vec<u8>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct SnapshotHash {
pub from: Pubkey,
pub hashes: Vec<(Slot, Hash)>,
pub wallclock: u64,
}
impl SnapshotHash {
pub fn new(from: Pubkey, hashes: Vec<(Slot, Hash)>, wallclock: u64) -> Self {
Self {
from,
hashes,
wallclock,
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
@ -67,6 +108,7 @@ pub struct EpochSlots {
pub root: Slot,
pub lowest: Slot,
pub slots: BTreeSet<Slot>,
pub stash: Vec<EpochIncompleteSlots>,
pub wallclock: u64,
}
@ -76,6 +118,7 @@ impl EpochSlots {
root: Slot,
lowest: Slot,
slots: BTreeSet<Slot>,
stash: Vec<EpochIncompleteSlots>,
wallclock: u64,
) -> Self {
Self {
@ -83,6 +126,7 @@ impl EpochSlots {
root,
lowest,
slots,
stash,
wallclock,
}
}
@ -112,6 +156,7 @@ pub enum CrdsValueLabel {
ContactInfo(Pubkey),
Vote(VoteIndex, Pubkey),
EpochSlots(Pubkey),
SnapshotHash(Pubkey),
}
impl fmt::Display for CrdsValueLabel {
@ -120,6 +165,7 @@ impl fmt::Display for CrdsValueLabel {
CrdsValueLabel::ContactInfo(_) => write!(f, "ContactInfo({})", self.pubkey()),
CrdsValueLabel::Vote(ix, _) => write!(f, "Vote({}, {})", ix, self.pubkey()),
CrdsValueLabel::EpochSlots(_) => write!(f, "EpochSlots({})", self.pubkey()),
CrdsValueLabel::SnapshotHash(_) => write!(f, "SnapshotHash({})", self.pubkey()),
}
}
}
@ -130,6 +176,7 @@ impl CrdsValueLabel {
CrdsValueLabel::ContactInfo(p) => *p,
CrdsValueLabel::Vote(_, p) => *p,
CrdsValueLabel::EpochSlots(p) => *p,
CrdsValueLabel::SnapshotHash(p) => *p,
}
}
}
@ -154,21 +201,24 @@ impl CrdsValue {
match &self.data {
CrdsData::ContactInfo(contact_info) => contact_info.wallclock,
CrdsData::Vote(_, vote) => vote.wallclock,
CrdsData::EpochSlots(vote) => vote.wallclock,
CrdsData::EpochSlots(_, vote) => vote.wallclock,
CrdsData::SnapshotHash(hash) => hash.wallclock,
}
}
pub fn pubkey(&self) -> Pubkey {
match &self.data {
CrdsData::ContactInfo(contact_info) => contact_info.id,
CrdsData::Vote(_, vote) => vote.from,
CrdsData::EpochSlots(slots) => slots.from,
CrdsData::EpochSlots(_, slots) => slots.from,
CrdsData::SnapshotHash(hash) => hash.from,
}
}
pub fn label(&self) -> CrdsValueLabel {
match &self.data {
CrdsData::ContactInfo(_) => CrdsValueLabel::ContactInfo(self.pubkey()),
CrdsData::Vote(ix, _) => CrdsValueLabel::Vote(*ix, self.pubkey()),
CrdsData::EpochSlots(_) => CrdsValueLabel::EpochSlots(self.pubkey()),
CrdsData::EpochSlots(_, _) => CrdsValueLabel::EpochSlots(self.pubkey()),
CrdsData::SnapshotHash(_) => CrdsValueLabel::SnapshotHash(self.pubkey()),
}
}
pub fn contact_info(&self) -> Option<&ContactInfo> {
@ -193,15 +243,24 @@ impl CrdsValue {
pub fn epoch_slots(&self) -> Option<&EpochSlots> {
match &self.data {
CrdsData::EpochSlots(slots) => Some(slots),
CrdsData::EpochSlots(_, slots) => Some(slots),
_ => None,
}
}
pub fn snapshot_hash(&self) -> Option<&SnapshotHash> {
match &self.data {
CrdsData::SnapshotHash(slots) => Some(slots),
_ => None,
}
}
/// Return all the possible labels for a record identified by Pubkey.
pub fn record_labels(key: &Pubkey) -> Vec<CrdsValueLabel> {
let mut labels = vec![
CrdsValueLabel::ContactInfo(*key),
CrdsValueLabel::EpochSlots(*key),
CrdsValueLabel::SnapshotHash(*key),
];
labels.extend((0..MAX_VOTES).map(|ix| CrdsValueLabel::Vote(ix, *key)));
labels
@ -246,18 +305,19 @@ mod test {
use crate::contact_info::ContactInfo;
use bincode::deserialize;
use solana_perf::test_tx::test_tx;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::timing::timestamp;
#[test]
fn test_labels() {
let mut hits = [false; 2 + MAX_VOTES as usize];
let mut hits = [false; 3 + MAX_VOTES as usize];
// this method should cover all the possible labels
for v in &CrdsValue::record_labels(&Pubkey::default()) {
match v {
CrdsValueLabel::ContactInfo(_) => hits[0] = true,
CrdsValueLabel::EpochSlots(_) => hits[1] = true,
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 2] = true,
CrdsValueLabel::SnapshotHash(_) => hits[2] = true,
CrdsValueLabel::Vote(ix, _) => hits[*ix as usize + 3] = true,
}
}
assert!(hits.iter().all(|x| *x));
@ -277,13 +337,10 @@ mod test {
let key = v.clone().vote().unwrap().from;
assert_eq!(v.label(), CrdsValueLabel::Vote(0, key));
let v = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots::new(
Pubkey::default(),
let v = CrdsValue::new_unsigned(CrdsData::EpochSlots(
0,
0,
BTreeSet::new(),
0,
)));
EpochSlots::new(Pubkey::default(), 0, 0, BTreeSet::new(), vec![], 0),
));
assert_eq!(v.wallclock(), 0);
let key = v.clone().epoch_slots().unwrap().from;
assert_eq!(v.label(), CrdsValueLabel::EpochSlots(key));
@ -304,13 +361,10 @@ mod test {
));
verify_signatures(&mut v, &keypair, &wrong_keypair);
let btreeset: BTreeSet<Slot> = vec![1, 2, 3, 6, 8].into_iter().collect();
v = CrdsValue::new_unsigned(CrdsData::EpochSlots(EpochSlots::new(
keypair.pubkey(),
v = CrdsValue::new_unsigned(CrdsData::EpochSlots(
0,
0,
btreeset,
timestamp(),
)));
EpochSlots::new(keypair.pubkey(), 0, 0, btreeset, vec![], timestamp()),
));
verify_signatures(&mut v, &keypair, &wrong_keypair);
}

View File

@ -41,7 +41,7 @@ impl GenKeys {
mod tests {
use super::*;
pub use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::signature::Signer;
use std::collections::HashSet;
#[test]

View File

@ -8,7 +8,7 @@ use solana_client::thin_client::{create_client, ThinClient};
use solana_ledger::bank_forks::BankForks;
use solana_perf::recycler::Recycler;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::net::{SocketAddr, TcpListener, UdpSocket};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel;

View File

@ -12,11 +12,11 @@ use std::thread::{Builder, JoinHandle};
use std::time::Duration;
// This is chosen to allow enough time for
// - To try and keep the RocksDB size under 128GB at 50k tps (100 slots take ~2GB).
// - To try and keep the RocksDB size under 512GB at 50k tps (100 slots take ~2GB).
// - A validator to download a snapshot from a peer and boot from it
// - To make sure that if a validator needs to reboot from its own snapshot, it has enough slots locally
// to catch back up to where it was when it stopped
pub const DEFAULT_MAX_LEDGER_SLOTS: u64 = 6400;
pub const DEFAULT_MAX_LEDGER_SLOTS: u64 = 270_000;
// Remove a fixed number of slots at a time, it's more efficient than doing it one-by-one
pub const DEFAULT_PURGE_BATCH_SIZE: u64 = 256;

View File

@ -9,11 +9,12 @@ use solana_ledger::{
bank_forks::BankForks,
blockstore::{Blockstore, CompletedSlotsReceiver, SlotMeta},
};
use solana_sdk::clock::DEFAULT_SLOTS_PER_EPOCH;
use solana_sdk::{clock::Slot, epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
collections::BTreeSet,
net::UdpSocket,
ops::Bound::{Excluded, Unbounded},
ops::Bound::{Included, Unbounded},
sync::atomic::{AtomicBool, Ordering},
sync::{Arc, RwLock},
thread::sleep,
@ -25,6 +26,9 @@ pub const MAX_REPAIR_LENGTH: usize = 512;
pub const REPAIR_MS: u64 = 100;
pub const MAX_ORPHANS: usize = 5;
const MAX_COMPLETED_SLOT_CACHE_LEN: usize = 256;
const COMPLETED_SLOT_CACHE_FLUSH_TRIGGER: usize = 512;
pub enum RepairStrategy {
RepairRange(RepairSlotRange),
RepairAll {
@ -85,17 +89,18 @@ impl RepairService {
) {
let serve_repair = ServeRepair::new(cluster_info.clone());
let mut epoch_slots: BTreeSet<Slot> = BTreeSet::new();
let mut old_incomplete_slots: BTreeSet<Slot> = BTreeSet::new();
let id = cluster_info.read().unwrap().id();
let mut current_root = 0;
if let RepairStrategy::RepairAll {
ref epoch_schedule, ..
} = repair_strategy
{
current_root = blockstore.last_root();
let current_root = blockstore.last_root();
Self::initialize_epoch_slots(
id,
blockstore,
&mut epoch_slots,
&old_incomplete_slots,
current_root,
epoch_schedule,
cluster_info,
@ -127,8 +132,8 @@ impl RepairService {
id,
new_root,
lowest_slot,
&mut current_root,
&mut epoch_slots,
&mut old_incomplete_slots,
&cluster_info,
completed_slots_receiver,
);
@ -292,6 +297,7 @@ impl RepairService {
id: Pubkey,
blockstore: &Blockstore,
slots_in_gossip: &mut BTreeSet<Slot>,
old_incomplete_slots: &BTreeSet<Slot>,
root: Slot,
epoch_schedule: &EpochSchedule,
cluster_info: &RwLock<ClusterInfo>,
@ -307,6 +313,7 @@ impl RepairService {
root,
blockstore.lowest_slot(),
slots_in_gossip.clone(),
old_incomplete_slots,
);
}
@ -316,44 +323,83 @@ impl RepairService {
id: Pubkey,
latest_known_root: Slot,
lowest_slot: Slot,
prev_root: &mut Slot,
slots_in_gossip: &mut BTreeSet<Slot>,
completed_slot_cache: &mut BTreeSet<Slot>,
incomplete_slot_stash: &mut BTreeSet<Slot>,
cluster_info: &RwLock<ClusterInfo>,
completed_slots_receiver: &CompletedSlotsReceiver,
) {
// If the latest known root is different, update gossip.
let mut should_update = latest_known_root != *prev_root;
let mut should_update = false;
while let Ok(completed_slots) = completed_slots_receiver.try_recv() {
for slot in completed_slots {
// If the newly completed slot > root, and the set did not contain this value
// before, we should update gossip.
if slot > latest_known_root {
should_update |= slots_in_gossip.insert(slot);
let last_slot_in_stash = *incomplete_slot_stash.iter().next_back().unwrap_or(&0);
let removed_from_stash = incomplete_slot_stash.remove(&slot);
// If the newly completed slot was not being tracked in stash, and is > last
// slot being tracked in stash, add it to cache. Also, update gossip
if !removed_from_stash && slot >= last_slot_in_stash {
should_update |= completed_slot_cache.insert(slot);
}
// If the slot was removed from stash, update gossip
should_update |= removed_from_stash;
}
}
if should_update {
// Filter out everything <= root
if latest_known_root != *prev_root {
*prev_root = latest_known_root;
Self::retain_slots_greater_than_root(slots_in_gossip, latest_known_root);
if completed_slot_cache.len() >= COMPLETED_SLOT_CACHE_FLUSH_TRIGGER {
Self::stash_old_incomplete_slots(completed_slot_cache, incomplete_slot_stash);
let lowest_completed_slot_in_cache =
*completed_slot_cache.iter().next().unwrap_or(&0);
Self::prune_incomplete_slot_stash(
incomplete_slot_stash,
lowest_completed_slot_in_cache,
);
}
cluster_info.write().unwrap().push_epoch_slots(
id,
latest_known_root,
lowest_slot,
slots_in_gossip.clone(),
completed_slot_cache.clone(),
incomplete_slot_stash,
);
}
}
fn retain_slots_greater_than_root(slot_set: &mut BTreeSet<Slot>, root: Slot) {
*slot_set = slot_set
.range((Excluded(&root), Unbounded))
.cloned()
.collect();
fn stash_old_incomplete_slots(cache: &mut BTreeSet<Slot>, stash: &mut BTreeSet<Slot>) {
if cache.len() > MAX_COMPLETED_SLOT_CACHE_LEN {
let mut prev = *cache.iter().next().expect("Expected to find some slot");
cache.remove(&prev);
while cache.len() >= MAX_COMPLETED_SLOT_CACHE_LEN {
let next = *cache.iter().next().expect("Expected to find some slot");
cache.remove(&next);
// Prev slot and next slot are not included in incomplete slot list.
(prev + 1..next).for_each(|slot| {
stash.insert(slot);
});
prev = next;
}
}
}
fn prune_incomplete_slot_stash(
stash: &mut BTreeSet<Slot>,
lowest_completed_slot_in_cache: Slot,
) {
if let Some(oldest_incomplete_slot) = stash.iter().next() {
// Prune old slots
// Prune in batches to reduce overhead. Pruning starts when oldest slot is 1.5 epochs
// earlier than the new root. But, we prune all the slots that are older than 1 epoch.
// So slots in a batch of half epoch are getting pruned
if oldest_incomplete_slot + DEFAULT_SLOTS_PER_EPOCH + DEFAULT_SLOTS_PER_EPOCH / 2
< lowest_completed_slot_in_cache
{
let oldest_slot_to_retain =
lowest_completed_slot_in_cache.saturating_sub(DEFAULT_SLOTS_PER_EPOCH);
*stash = stash
.range((Included(&oldest_slot_to_retain), Unbounded))
.cloned()
.collect();
}
}
}
pub fn join(self) -> thread::Result<()> {
@ -373,7 +419,6 @@ mod test {
};
use solana_ledger::shred::max_ticks_per_n_shreds;
use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path};
use std::sync::mpsc::channel;
use std::thread::Builder;
#[test]
@ -703,13 +748,14 @@ mod test {
node_info.info.clone(),
));
let mut old_incomplete_slots: BTreeSet<Slot> = BTreeSet::new();
while completed_slots.len() < num_slots as usize {
RepairService::update_epoch_slots(
Pubkey::default(),
root,
blockstore.lowest_slot(),
&mut root.clone(),
&mut completed_slots,
&mut old_incomplete_slots,
&cluster_info,
&completed_slots_receiver,
);
@ -726,13 +772,12 @@ mod test {
Pubkey::default(),
root,
0,
&mut 0,
&mut completed_slots,
&mut old_incomplete_slots,
&cluster_info,
&completed_slots_receiver,
);
expected.insert(num_slots + 2);
RepairService::retain_slots_greater_than_root(&mut expected, root);
assert_eq!(completed_slots, expected);
writer.join().unwrap();
}
@ -740,95 +785,133 @@ mod test {
}
#[test]
fn test_update_epoch_slots_new_root() {
let mut current_root = 0;
fn test_stash_old_incomplete_slots() {
let mut cache: BTreeSet<Slot> = BTreeSet::new();
let mut stash: BTreeSet<Slot> = BTreeSet::new();
let mut completed_slots = BTreeSet::new();
let node_info = Node::new_localhost_with_pubkey(&Pubkey::default());
let cluster_info = RwLock::new(ClusterInfo::new_with_invalid_keypair(
node_info.info.clone(),
));
let my_pubkey = Pubkey::new_rand();
let (completed_slots_sender, completed_slots_receiver) = channel();
// When cache is empty.
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
assert_eq!(stash.len(), 0);
// Send a new slot before the root is updated
let newly_completed_slot = 63;
completed_slots_sender
.send(vec![newly_completed_slot])
.unwrap();
RepairService::update_epoch_slots(
my_pubkey.clone(),
current_root,
0,
&mut current_root.clone(),
&mut completed_slots,
&cluster_info,
&completed_slots_receiver,
// Insert some slots in cache ( < MAX_COMPLETED_SLOT_CACHE_LEN + 1)
cache.insert(101);
cache.insert(102);
cache.insert(104);
cache.insert(105);
// Not enough slots in cache. So stash should remain empty.
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
assert_eq!(stash.len(), 0);
assert_eq!(cache.len(), 4);
// Insert slots in cache ( = MAX_COMPLETED_SLOT_CACHE_LEN)
let mut cache: BTreeSet<Slot> = BTreeSet::new();
(0..MAX_COMPLETED_SLOT_CACHE_LEN as u64)
.into_iter()
.for_each(|slot| {
cache.insert(slot);
});
// Not enough slots in cache. So stash should remain empty.
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
assert_eq!(stash.len(), 0);
assert_eq!(cache.len(), MAX_COMPLETED_SLOT_CACHE_LEN);
// Insert 1 more to cross the threshold
cache.insert(MAX_COMPLETED_SLOT_CACHE_LEN as u64);
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
// Stash is still empty, as no missing slots
assert_eq!(stash.len(), 0);
// It removed some entries from cache
assert_eq!(cache.len(), MAX_COMPLETED_SLOT_CACHE_LEN - 1);
// Insert more slots to create a missing slot
let mut cache: BTreeSet<Slot> = BTreeSet::new();
cache.insert(0);
(2..=MAX_COMPLETED_SLOT_CACHE_LEN as u64 + 2)
.into_iter()
.for_each(|slot| {
cache.insert(slot);
});
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
// Stash is not empty
assert!(stash.contains(&1));
// It removed some entries from cache
assert_eq!(cache.len(), MAX_COMPLETED_SLOT_CACHE_LEN - 1);
// Test multiple missing slots at dispersed locations
let mut cache: BTreeSet<Slot> = BTreeSet::new();
(0..MAX_COMPLETED_SLOT_CACHE_LEN as u64 * 2)
.into_iter()
.for_each(|slot| {
cache.insert(slot);
});
cache.remove(&10);
cache.remove(&11);
cache.remove(&28);
cache.remove(&29);
cache.remove(&148);
cache.remove(&149);
cache.remove(&150);
cache.remove(&151);
RepairService::stash_old_incomplete_slots(&mut cache, &mut stash);
// Stash is not empty
assert!(stash.contains(&10));
assert!(stash.contains(&11));
assert!(stash.contains(&28));
assert!(stash.contains(&29));
assert!(stash.contains(&148));
assert!(stash.contains(&149));
assert!(stash.contains(&150));
assert!(stash.contains(&151));
assert!(!stash.contains(&147));
assert!(!stash.contains(&152));
// It removed some entries from cache
assert_eq!(cache.len(), MAX_COMPLETED_SLOT_CACHE_LEN - 1);
(MAX_COMPLETED_SLOT_CACHE_LEN + 1..MAX_COMPLETED_SLOT_CACHE_LEN * 2)
.into_iter()
.for_each(|slot| {
let slot: u64 = slot as u64;
assert!(cache.contains(&slot));
});
}
#[test]
fn test_prune_incomplete_slot_stash() {
// Prune empty stash
let mut stash: BTreeSet<Slot> = BTreeSet::new();
RepairService::prune_incomplete_slot_stash(&mut stash, 0);
assert!(stash.is_empty());
// Prune stash with slots < DEFAULT_SLOTS_PER_EPOCH
stash.insert(0);
stash.insert(10);
stash.insert(11);
stash.insert(50);
assert_eq!(stash.len(), 4);
RepairService::prune_incomplete_slot_stash(&mut stash, 100);
assert_eq!(stash.len(), 4);
// Prune stash with slots > DEFAULT_SLOTS_PER_EPOCH, but < 1.5 * DEFAULT_SLOTS_PER_EPOCH
stash.insert(DEFAULT_SLOTS_PER_EPOCH + 50);
assert_eq!(stash.len(), 5);
RepairService::prune_incomplete_slot_stash(&mut stash, DEFAULT_SLOTS_PER_EPOCH + 100);
assert_eq!(stash.len(), 5);
// Prune stash with slots > 1.5 * DEFAULT_SLOTS_PER_EPOCH
stash.insert(DEFAULT_SLOTS_PER_EPOCH + DEFAULT_SLOTS_PER_EPOCH / 2);
assert_eq!(stash.len(), 6);
RepairService::prune_incomplete_slot_stash(
&mut stash,
DEFAULT_SLOTS_PER_EPOCH + DEFAULT_SLOTS_PER_EPOCH / 2 + 1,
);
// We should see epoch state update
let (my_epoch_slots_in_gossip, updated_ts) = {
let r_cluster_info = cluster_info.read().unwrap();
let (my_epoch_slots_in_gossip, updated_ts) = r_cluster_info
.get_epoch_state_for_node(&my_pubkey, None)
.clone()
.unwrap();
(my_epoch_slots_in_gossip.clone(), updated_ts)
};
assert_eq!(my_epoch_slots_in_gossip.root, 0);
assert_eq!(current_root, 0);
assert_eq!(my_epoch_slots_in_gossip.slots.len(), 1);
assert!(my_epoch_slots_in_gossip
.slots
.contains(&newly_completed_slot));
// Calling update again with no updates to either the roots or set of completed slots
// should not update gossip
RepairService::update_epoch_slots(
my_pubkey.clone(),
current_root,
0,
&mut current_root,
&mut completed_slots,
&cluster_info,
&completed_slots_receiver,
);
assert!(cluster_info
.read()
.unwrap()
.get_epoch_state_for_node(&my_pubkey, Some(updated_ts))
.is_none());
sleep(Duration::from_millis(10));
// Updating just the root again should update gossip (simulates replay stage updating root
// after a slot has been signaled as completed)
RepairService::update_epoch_slots(
my_pubkey.clone(),
current_root + 1,
0,
&mut current_root,
&mut completed_slots,
&cluster_info,
&completed_slots_receiver,
);
let r_cluster_info = cluster_info.read().unwrap();
let (my_epoch_slots_in_gossip, _) = r_cluster_info
.get_epoch_state_for_node(&my_pubkey, Some(updated_ts))
.clone()
.unwrap();
// Check the root was updated correctly
assert_eq!(my_epoch_slots_in_gossip.root, 1);
assert_eq!(current_root, 1);
assert_eq!(my_epoch_slots_in_gossip.slots.len(), 1);
assert!(my_epoch_slots_in_gossip
.slots
.contains(&newly_completed_slot));
assert_eq!(stash.len(), 2);
}
}

View File

@ -27,7 +27,7 @@ use solana_sdk::{
clock::Slot,
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
timing::{self, duration_as_ms},
transaction::Transaction,
};
@ -489,7 +489,7 @@ impl ReplayStage {
return;
}
datapoint_debug!(
datapoint_info!(
"replay_stage-new_leader",
("slot", poh_slot, i64),
("leader", next_leader.to_string(), String),
@ -1039,7 +1039,7 @@ pub(crate) mod tests {
instruction::InstructionError,
packet::PACKET_DATA_SIZE,
rent::Rent,
signature::{Keypair, KeypairUtil, Signature},
signature::{Keypair, Signature, Signer},
system_transaction,
transaction::TransactionError,
};

View File

@ -1121,7 +1121,7 @@ pub mod tests {
hash::{hash, Hash},
instruction::InstructionError,
rpc_port,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_transaction,
transaction::TransactionError,
};

View File

@ -288,7 +288,7 @@ mod tests {
use solana_runtime::bank::Bank;
use solana_sdk::{
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_program, system_transaction,
transaction::{self, Transaction},
};

View File

@ -181,7 +181,7 @@ mod tests {
};
use solana_ledger::get_tmp_ledger_path;
use solana_runtime::bank::Bank;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::signature::Signer;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::atomic::AtomicBool;

View File

@ -506,7 +506,7 @@ pub(crate) mod tests {
use jsonrpc_pubsub::typed::Subscriber;
use solana_budget_program;
use solana_sdk::{
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
system_transaction,
};
use tokio::prelude::{Async, Stream};

View File

@ -14,7 +14,7 @@ use solana_metrics::{datapoint_debug, inc_new_counter_debug};
use solana_perf::packet::{Packets, PacketsRecycler};
use solana_sdk::{
clock::Slot,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
timing::duration_as_ms,
};
use std::{
@ -298,7 +298,7 @@ impl ServeRepair {
Ok(self.window_index_request_bytes(*slot, *shred_index)?)
}
RepairType::HighestShred(slot, shred_index) => {
datapoint_debug!(
datapoint_info!(
"serve_repair-repair_highest",
("repair-highest-slot", *slot, i64),
("repair-highest-ix", *shred_index, i64)
@ -306,7 +306,7 @@ impl ServeRepair {
Ok(self.window_highest_index_request_bytes(*slot, *shred_index)?)
}
RepairType::Orphan(slot) => {
datapoint_debug!("serve_repair-repair_orphan", ("repair-orphan", *slot, i64));
datapoint_info!("serve_repair-repair_orphan", ("repair-orphan", *slot, i64));
Ok(self.orphan_bytes(*slot)?)
}
}

View File

@ -76,7 +76,7 @@ pub mod tests {
use crate::packet::Packet;
use solana_ledger::shred::{Shred, Shredder};
use solana_runtime::bank::Bank;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
#[test]
fn test_sigverify_shreds_read_slots() {

View File

@ -1,3 +1,4 @@
use crate::cluster_info::ClusterInfo;
use solana_ledger::{
snapshot_package::SnapshotPackageReceiver, snapshot_utils::archive_snapshot_package,
};
@ -5,7 +6,7 @@ use std::{
sync::{
atomic::{AtomicBool, Ordering},
mpsc::RecvTimeoutError,
Arc,
Arc, RwLock,
},
thread::{self, Builder, JoinHandle},
time::Duration,
@ -15,25 +16,42 @@ pub struct SnapshotPackagerService {
t_snapshot_packager: JoinHandle<()>,
}
const MAX_SNAPSHOT_HASHES: usize = 24;
impl SnapshotPackagerService {
pub fn new(snapshot_package_receiver: SnapshotPackageReceiver, exit: &Arc<AtomicBool>) -> Self {
pub fn new(
snapshot_package_receiver: SnapshotPackageReceiver,
exit: &Arc<AtomicBool>,
cluster_info: &Arc<RwLock<ClusterInfo>>,
) -> Self {
let exit = exit.clone();
let cluster_info = cluster_info.clone();
let t_snapshot_packager = Builder::new()
.name("solana-snapshot-packager".to_string())
.spawn(move || loop {
let mut hashes = vec![];
if exit.load(Ordering::Relaxed) {
break;
}
match snapshot_package_receiver.recv_timeout(Duration::from_secs(1)) {
Ok(mut snapshot_package) => {
hashes.push((snapshot_package.root, snapshot_package.hash));
// Only package the latest
while let Ok(new_snapshot_package) = snapshot_package_receiver.try_recv() {
snapshot_package = new_snapshot_package;
hashes.push((snapshot_package.root, snapshot_package.hash));
}
if let Err(err) = archive_snapshot_package(&snapshot_package) {
warn!("Failed to create snapshot archive: {}", err);
}
while hashes.len() > MAX_SNAPSHOT_HASHES {
hashes.remove(0);
}
cluster_info
.write()
.unwrap()
.push_snapshot_hashes(hashes.clone());
}
Err(RecvTimeoutError::Disconnected) => break,
Err(RecvTimeoutError::Timeout) => (),
@ -59,10 +77,9 @@ mod tests {
snapshot_utils::{self, SNAPSHOT_STATUS_CACHE_FILE_NAME},
};
use solana_runtime::{
accounts_db::AccountStorageEntry, bank::MAX_SNAPSHOT_DATA_FILE_SIZE,
status_cache::SlotDelta,
accounts_db::AccountStorageEntry, bank::BankSlotDelta, bank::MAX_SNAPSHOT_DATA_FILE_SIZE,
};
use solana_sdk::transaction;
use solana_sdk::hash::Hash;
use std::{
fs::{self, remove_dir_all, OpenOptions},
io::Write,
@ -139,8 +156,9 @@ mod tests {
5,
vec![],
link_snapshots_dir,
storage_entries.clone(),
vec![storage_entries],
output_tar_path.clone(),
Hash::default(),
);
// Make tarball from packageable snapshot
@ -149,7 +167,7 @@ mod tests {
// before we compare, stick an empty status_cache in this dir so that the package comparision works
// This is needed since the status_cache is added by the packager and is not collected from
// the source dir for snapshots
let dummy_slot_deltas: Vec<SlotDelta<transaction::Result<()>>> = vec![];
let dummy_slot_deltas: Vec<BankSlotDelta> = vec![];
snapshot_utils::serialize_snapshot_data_file(
&snapshots_dir.join(SNAPSHOT_STATUS_CACHE_FILE_NAME),
MAX_SNAPSHOT_DATA_FILE_SIZE,

View File

@ -20,7 +20,7 @@ use solana_sdk::{
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature},
signature::{Keypair, Signature, Signer},
transaction::Transaction,
};
use solana_storage_program::{
@ -649,7 +649,7 @@ mod tests {
use rayon::prelude::*;
use solana_runtime::bank::Bank;
use solana_sdk::hash::Hasher;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use std::cmp::{max, min};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::mpsc::channel;

View File

@ -26,7 +26,7 @@ use solana_ledger::{
};
use solana_sdk::{
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
};
use std::{
net::UdpSocket,
@ -153,7 +153,8 @@ impl Tvu {
if snapshot_config.is_some() {
// Start a snapshot packaging service
let (sender, receiver) = channel();
let snapshot_packager_service = SnapshotPackagerService::new(receiver, exit);
let snapshot_packager_service =
SnapshotPackagerService::new(receiver, exit, &cluster_info.clone());
(Some(snapshot_packager_service), Some(sender))
} else {
(None, None)

View File

@ -38,9 +38,8 @@ use solana_sdk::{
clock::{Slot, DEFAULT_SLOTS_PER_TURN},
genesis_config::GenesisConfig,
hash::Hash,
poh_config::PohConfig,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
timing::timestamp,
};
use std::{
@ -159,14 +158,14 @@ impl Validator {
info!("creating bank...");
let (
genesis_hash,
genesis_config,
bank_forks,
bank_forks_info,
blockstore,
ledger_signal_receiver,
completed_slots_receiver,
leader_schedule_cache,
poh_config,
snapshot_hash,
) = new_banks_from_blockstore(
config.expected_genesis_hash,
ledger_path,
@ -196,8 +195,10 @@ impl Validator {
let validator_exit = Arc::new(RwLock::new(Some(validator_exit)));
node.info.wallclock = timestamp();
node.info.shred_version =
compute_shred_version(&genesis_hash, Some(&bank.hard_forks().read().unwrap()));
node.info.shred_version = compute_shred_version(
&genesis_config.hash(),
Some(&bank.hard_forks().read().unwrap()),
);
Self::print_node_info(&node);
if let Some(expected_shred_version) = config.expected_shred_version {
@ -241,7 +242,7 @@ impl Validator {
block_commitment_cache.clone(),
blockstore.clone(),
cluster_info.clone(),
genesis_hash,
genesis_config.hash(),
ledger_path,
storage_state.clone(),
validator_exit.clone(),
@ -299,7 +300,7 @@ impl Validator {
std::thread::park();
}
let poh_config = Arc::new(poh_config);
let poh_config = Arc::new(genesis_config.poh_config);
let (mut poh_recorder, entry_receiver) = PohRecorder::new_with_clear_signal(
bank.tick_height(),
bank.last_blockhash(),
@ -343,6 +344,14 @@ impl Validator {
.set_entrypoint(entrypoint_info.clone());
}
// If the node was loaded from a snapshot, advertise it in gossip
if let Some(snapshot_hash) = snapshot_hash {
cluster_info
.write()
.unwrap()
.push_snapshot_hashes(vec![snapshot_hash]);
}
wait_for_supermajority(config, &bank, &cluster_info);
let voting_keypair = if config.voting_disabled {
@ -505,20 +514,21 @@ impl Validator {
}
}
#[allow(clippy::type_complexity)]
fn new_banks_from_blockstore(
expected_genesis_hash: Option<Hash>,
blockstore_path: &Path,
poh_verify: bool,
config: &ValidatorConfig,
) -> (
Hash,
GenesisConfig,
BankForks,
Vec<BankForksInfo>,
Blockstore,
Receiver<bool>,
CompletedSlotsReceiver,
LeaderScheduleCache,
PohConfig,
Option<(Slot, Hash)>,
) {
let genesis_config = GenesisConfig::load(blockstore_path).unwrap_or_else(|err| {
error!("Failed to load genesis from {:?}: {}", blockstore_path, err);
@ -548,31 +558,32 @@ fn new_banks_from_blockstore(
..blockstore_processor::ProcessOptions::default()
};
let (mut bank_forks, bank_forks_info, mut leader_schedule_cache) = bank_forks_utils::load(
&genesis_config,
&blockstore,
config.account_paths.clone(),
config.snapshot_config.as_ref(),
process_options,
)
.unwrap_or_else(|err| {
error!("Failed to load ledger: {:?}", err);
std::process::exit(1);
});
let (mut bank_forks, bank_forks_info, mut leader_schedule_cache, snapshot_hash) =
bank_forks_utils::load(
&genesis_config,
&blockstore,
config.account_paths.clone(),
config.snapshot_config.as_ref(),
process_options,
)
.unwrap_or_else(|err| {
error!("Failed to load ledger: {:?}", err);
std::process::exit(1);
});
leader_schedule_cache.set_fixed_leader_schedule(config.fixed_leader_schedule.clone());
bank_forks.set_snapshot_config(config.snapshot_config.clone());
(
genesis_hash,
genesis_config,
bank_forks,
bank_forks_info,
blockstore,
ledger_signal_receiver,
completed_slots_receiver,
leader_schedule_cache,
genesis_config.poh_config,
snapshot_hash,
)
}

View File

@ -494,7 +494,7 @@ mod test {
clock::Slot,
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
hash::Hash,
signature::{Keypair, KeypairUtil},
signature::{Keypair, Signer},
};
use std::{
net::UdpSocket,

View File

@ -5,6 +5,8 @@ mod tests {
use bincode::serialize_into;
use fs_extra::dir::CopyOptions;
use itertools::Itertools;
use solana_core::cluster_info::ClusterInfo;
use solana_core::contact_info::ContactInfo;
use solana_core::{
genesis_utils::{create_genesis_config, GenesisConfigInfo},
snapshot_packager_service::SnapshotPackagerService,
@ -14,16 +16,17 @@ mod tests {
snapshot_utils,
};
use solana_runtime::{
bank::Bank,
status_cache::{SlotDelta, MAX_CACHE_ENTRIES},
bank::{Bank, BankSlotDelta},
status_cache::MAX_CACHE_ENTRIES,
};
use solana_sdk::{
clock::Slot,
hash::hashv,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
system_transaction, transaction,
signature::{Keypair, Signer},
system_transaction,
};
use std::sync::RwLock;
use std::{fs, path::PathBuf, sync::atomic::AtomicBool, sync::mpsc::channel, sync::Arc};
use tempfile::TempDir;
@ -128,6 +131,7 @@ mod tests {
}
// Generate a snapshot package for last bank
let last_bank = bank_forks.get(last_slot).unwrap();
let storages: Vec<_> = last_bank.get_snapshot_storages();
let slot_snapshot_paths =
snapshot_utils::get_snapshot_paths(&snapshot_config.snapshot_path);
let snapshot_package = snapshot_utils::package_snapshot(
@ -140,6 +144,7 @@ mod tests {
),
&snapshot_config.snapshot_path,
&last_bank.src.roots(),
storages,
)
.unwrap();
@ -199,7 +204,8 @@ mod tests {
// Take snapshot of zeroth bank
let bank0 = bank_forks.get(0).unwrap();
snapshot_utils::add_snapshot(&snapshot_config.snapshot_path, bank0).unwrap();
let storages: Vec<_> = bank0.get_snapshot_storages();
snapshot_utils::add_snapshot(&snapshot_config.snapshot_path, bank0, &storages).unwrap();
// Set up snapshotting channels
let (sender, receiver) = channel();
@ -296,7 +302,13 @@ mod tests {
// correctly construct the earlier snapshots because the SnapshotPackage's on the
// channel hold hard links to these deleted snapshots. We verify this is the case below.
let exit = Arc::new(AtomicBool::new(false));
let snapshot_packager_service = SnapshotPackagerService::new(receiver, &exit);
let cluster_info = Arc::new(RwLock::new(ClusterInfo::new_with_invalid_keypair(
ContactInfo::default(),
)));
let snapshot_packager_service =
SnapshotPackagerService::new(receiver, &exit, &cluster_info);
// Close the channel so that the package service will exit after reading all the
// packages off the channel
@ -312,7 +324,7 @@ mod tests {
// before we compare, stick an empty status_cache in this dir so that the package comparision works
// This is needed since the status_cache is added by the packager and is not collected from
// the source dir for snapshots
let dummy_slot_deltas: Vec<SlotDelta<transaction::Result<()>>> = vec![];
let dummy_slot_deltas: Vec<BankSlotDelta> = vec![];
snapshot_utils::serialize_snapshot_data_file(
&saved_snapshots_dir
.path()

View File

@ -1,12 +1,13 @@
use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::system_transaction;
use std::fs::remove_dir_all;
use std::thread::sleep;
use std::time::{Duration, Instant};
use solana_sdk::{
commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Signer, system_transaction,
};
use std::{
fs::remove_dir_all,
thread::sleep,
time::{Duration, Instant},
};
#[test]
fn test_rpc_client() {

View File

@ -6,7 +6,7 @@ use solana_core::cluster_info::{ClusterInfo, Node};
use solana_core::gossip_service::GossipService;
use solana_core::packet::Packet;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::timing::timestamp;
use std::net::UdpSocket;
use std::sync::atomic::{AtomicBool, Ordering};

View File

@ -15,7 +15,7 @@ mod tests {
use solana_sdk::hash::Hash;
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::transaction::Transaction;
use solana_storage_program::storage_instruction;
use solana_storage_program::storage_instruction::StorageAccountType;

View File

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

View File

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

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