Compare commits

...

25 Commits

Author SHA1 Message Date
6672d640f5 Tune bench-tps blockhash poller and stop panicking (bp #7563) (#7567)
* Tune bench-tps blockhash poller and stop panicking

(cherry picked from commit 4b3176a9a1)

* Revert blockhash sleep

(cherry picked from commit e82db6fc2f)

* @sakridge feedback

(cherry picked from commit 848fe51f3d)

* reduce error logging

(cherry picked from commit a096ade345)

* clippy

(cherry picked from commit 54f16ca2bf)
2019-12-19 11:42:42 -07:00
b8b84a4c95 Speed up show-block-production command (#7565)
automerge
2019-12-19 10:31:47 -08:00
9677b602e7 Add show-block-production command (#7562)
automerge
2019-12-18 23:39:38 -08:00
771e1e3a71 Add get_confirmed_block()/get_confirmed_blocks()
(cherry picked from commit 05664d150b)
2019-12-19 00:01:04 -07:00
c12ea7a112 Add support for multiple params
(cherry picked from commit fcda972cec)
2019-12-19 00:01:04 -07:00
6047796c24 Improve bench-tps stability (#7537) (#7558)
automerge
2019-12-18 21:25:53 -08:00
11a0a9ac47 Add getConfirmedBlocks rpc method (bp #7550) (#7557)
automerge
2019-12-18 17:00:05 -08:00
5fbe5aa22d Speed up getLeaderSchedule RPC call by reducing pubkey duplication (#7556)
automerge
2019-12-18 15:45:20 -08:00
8a879a52ef GetLeaderSchedule can now return a schedule for arbitrary epochs (#7545)
automerge
2019-12-17 23:15:04 -08:00
c7669d4afe Only return accounts that have changed since the bank's parent (#7520) (#7523)
automerge
2019-12-17 08:42:39 -08:00
1f81206210 Add Telegram notification support 2019-12-16 15:19:03 -07:00
5a2a34b035 watchtower: Add Slack/Discord sanity failure notification (#7467)
automerge
2019-12-16 15:19:03 -07:00
2ef7579b6c Revert "Add Telegram notification support (#7511)"
This reverts commit fed7cfef58.
2019-12-16 14:43:17 -07:00
fed7cfef58 Add Telegram notification support (#7511)
automerge
2019-12-16 13:33:36 -08:00
8b2ad77699 Add validator-identity argument to support monitoring a specific validator only (#7501)
automerge
2019-12-16 11:25:34 -08:00
abcabc18ac getVoteAccounts now excludes listing inactive unstaked accounts as delinquent (#7483)
automerge
2019-12-14 09:41:04 -08:00
4e0a3862a6 Bump version to 0.21.5 2019-12-14 00:49:04 -07:00
2eaf47d563 Ship solana-watchtower program 2019-12-13 23:04:31 -07:00
31f7b3782e Fix Blocktree Config (#7399) (#7468)
automerge
2019-12-13 00:16:19 -08:00
d6169f92c1 Add vote-update-validator subcommand
(cherry picked from commit f7a87d5e52)
2019-12-13 00:19:10 -07:00
7df72d36c4 Publish solana-docker releases (#7460) (#7462)
automerge
2019-12-12 16:50:23 -08:00
5318cdac8f Add solana-watchtower program 2019-12-12 16:21:39 -07:00
00434d5e6e Clarify show-vote-account/uptime output: "node id" really means "validator identity" (#7458)
automerge
2019-12-12 14:50:44 -08:00
ebf644ddef Add uptime column to show-validators (#7441) (#7445)
automerge
2019-12-12 08:27:50 -08:00
5e4fe9c67b Bump version to 0.21.4 2019-12-11 21:35:45 -07:00
105 changed files with 2229 additions and 1010 deletions

629
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@ members = [
"vote-signer",
"cli",
"rayon-threadlimit",
"watchtower",
]
exclude = [

View File

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

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "0.21.3"
version = "0.21.5"
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.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-measure = { path = "../measure", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-core = { path = "../core", version = "0.21.5" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-measure = { path = "../measure", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
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.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -23,19 +23,19 @@ serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-core = { path = "../core", version = "0.21.3" }
solana-genesis = { path = "../genesis", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-drone = { path = "../drone", version = "0.21.3" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-core = { path = "../core", version = "0.21.5" }
solana-genesis = { path = "../genesis", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-drone = { path = "../drone", version = "0.21.5" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
untrusted = "0.7.0"
ws = "0.9.1"
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "0.21.3" }
solana-local-cluster = { path = "../local-cluster", version = "0.21.5" }

View File

@ -2,14 +2,14 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "0.21.3"
version = "0.21.5"
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.21.3" }
solana-core = { path = "../core", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-core = { path = "../core", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }

View File

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

View File

@ -24,6 +24,7 @@ use std::{
cmp,
collections::VecDeque,
net::SocketAddr,
process::exit,
sync::{
atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering},
Arc, RwLock,
@ -88,8 +89,13 @@ where
let clients: Vec<_> = clients.into_iter().map(Arc::new).collect();
let client = &clients[0];
let start = gen_keypairs.len() - (tx_count * 2) as usize;
let keypairs = &gen_keypairs[start..];
let mut source_keypair_chunks: Vec<Vec<&Keypair>> = Vec::new();
let mut dest_keypair_chunks: Vec<VecDeque<&Keypair>> = Vec::new();
assert!(gen_keypairs.len() >= 2 * tx_count);
for chunk in gen_keypairs.chunks_exact(2 * tx_count) {
source_keypair_chunks.push(chunk[..tx_count].iter().collect());
dest_keypair_chunks.push(chunk[tx_count..].iter().collect());
}
let first_tx_count = loop {
match client.get_transaction_count() {
@ -126,9 +132,23 @@ where
let shared_txs: SharedTransactions = Arc::new(RwLock::new(VecDeque::new()));
let recent_blockhash = Arc::new(RwLock::new(get_recent_blockhash(client.as_ref()).0));
let shared_tx_active_thread_count = Arc::new(AtomicIsize::new(0));
let total_tx_sent_count = Arc::new(AtomicUsize::new(0));
let blockhash_thread = {
let exit_signal = exit_signal.clone();
let recent_blockhash = recent_blockhash.clone();
let client = client.clone();
let id = id.pubkey();
Builder::new()
.name("solana-blockhash-poller".to_string())
.spawn(move || {
poll_blockhash(&exit_signal, &recent_blockhash, &client, &id);
})
.unwrap()
};
let s_threads: Vec<_> = (0..threads)
.map(|_| {
let exit_signal = exit_signal.clone();
@ -154,58 +174,40 @@ where
// generate and send transactions for the specified duration
let start = Instant::now();
let keypair_chunks = source_keypair_chunks.len() as u64;
let mut reclaim_lamports_back_to_source_account = false;
let mut i = keypair0_balance;
let mut blockhash = Hash::default();
let mut blockhash_time;
while start.elapsed() < duration {
// ping-pong between source and destination accounts for each loop iteration
// this seems to be faster than trying to determine the balance of individual
// accounts
let len = tx_count as usize;
blockhash_time = Instant::now();
if let Ok((new_blockhash, _fee_calculator)) = client.get_new_blockhash(&blockhash) {
blockhash = new_blockhash;
} else {
if blockhash_time.elapsed().as_secs() > 30 {
panic!("Blockhash is not updating");
}
sleep(Duration::from_millis(100));
continue;
}
datapoint_debug!(
"bench-tps-get_blockhash",
("duration", duration_as_us(&blockhash_time.elapsed()), i64)
);
blockhash_time = Instant::now();
let balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
datapoint_debug!(
"bench-tps-get_balance",
("duration", duration_as_us(&blockhash_time.elapsed()), i64)
);
let chunk_index = (i % keypair_chunks) as usize;
generate_txs(
&shared_txs,
&blockhash,
&keypairs[..len],
&keypairs[len..],
&recent_blockhash,
&source_keypair_chunks[chunk_index],
&dest_keypair_chunks[chunk_index],
threads,
reclaim_lamports_back_to_source_account,
&libra_args,
);
// In sustained mode overlap the transfers with generation
// this has higher average performance but lower peak performance
// in tested environments.
if !sustained {
// In sustained mode, overlap the transfers with generation. This has higher average
// performance but lower peak performance in tested environments.
if sustained {
// Ensure that we don't generate more transactions than we can handle.
while shared_txs.read().unwrap().len() > 2 * threads {
sleep(Duration::from_millis(1));
}
} else {
while shared_tx_active_thread_count.load(Ordering::Relaxed) > 0 {
sleep(Duration::from_millis(1));
}
}
// Rotate destination keypairs so that the next round of transactions will have different
// transaction signatures even when blockhash is reused.
dest_keypair_chunks[chunk_index].rotate_left(1);
i += 1;
if should_switch_directions(num_lamports_per_account, i) {
if should_switch_directions(num_lamports_per_account, keypair_chunks, i) {
reclaim_lamports_back_to_source_account = !reclaim_lamports_back_to_source_account;
}
}
@ -228,6 +230,11 @@ where
}
}
info!("Waiting for blockhash thread...");
if let Err(err) = blockhash_thread.join() {
info!(" join() failed with: {:?}", err);
}
let balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
@ -252,8 +259,8 @@ fn metrics_submit_lamport_balance(lamport_balance: u64) {
#[cfg(feature = "move")]
fn generate_move_txs(
source: &[Keypair],
dest: &[Keypair],
source: &[&Keypair],
dest: &VecDeque<&Keypair>,
reclaim: bool,
move_keypairs: &[Keypair],
libra_pay_program_id: &Pubkey,
@ -297,8 +304,8 @@ fn generate_move_txs(
}
fn generate_system_txs(
source: &[Keypair],
dest: &[Keypair],
source: &[&Keypair],
dest: &VecDeque<&Keypair>,
reclaim: bool,
blockhash: &Hash,
) -> Vec<(Transaction, u64)> {
@ -321,15 +328,19 @@ fn generate_system_txs(
fn generate_txs(
shared_txs: &SharedTransactions,
blockhash: &Hash,
source: &[Keypair],
dest: &[Keypair],
blockhash: &Arc<RwLock<Hash>>,
source: &[&Keypair],
dest: &VecDeque<&Keypair>,
threads: usize,
reclaim: bool,
libra_args: &Option<LibraKeys>,
) {
let blockhash = *blockhash.read().unwrap();
let tx_count = source.len();
info!("Signing transactions... {} (reclaim={})", tx_count, reclaim);
info!(
"Signing transactions... {} (reclaim={}, blockhash={})",
tx_count, reclaim, &blockhash
);
let signing_start = Instant::now();
let transactions = if let Some((
@ -353,11 +364,11 @@ fn generate_txs(
&_libra_keys,
_libra_pay_program_id,
&_libra_genesis_keypair.pubkey(),
blockhash,
&blockhash,
)
}
} else {
generate_system_txs(source, dest, reclaim, blockhash)
generate_system_txs(source, dest, reclaim, &blockhash)
};
let duration = signing_start.elapsed();
@ -386,6 +397,48 @@ fn generate_txs(
}
}
fn poll_blockhash<T: Client>(
exit_signal: &Arc<AtomicBool>,
blockhash: &Arc<RwLock<Hash>>,
client: &Arc<T>,
id: &Pubkey,
) {
let mut blockhash_last_updated = Instant::now();
let mut last_error_log = Instant::now();
loop {
let blockhash_updated = {
let old_blockhash = *blockhash.read().unwrap();
if let Ok((new_blockhash, _fee)) = client.get_new_blockhash(&old_blockhash) {
*blockhash.write().unwrap() = new_blockhash;
blockhash_last_updated = Instant::now();
true
} else {
if blockhash_last_updated.elapsed().as_secs() > 120 {
eprintln!("Blockhash is stuck");
exit(1)
} else if blockhash_last_updated.elapsed().as_secs() > 30
&& last_error_log.elapsed().as_secs() >= 1
{
last_error_log = Instant::now();
error!("Blockhash is not updating");
}
false
}
};
if blockhash_updated {
let balance = client.get_balance(id).unwrap_or(0);
metrics_submit_lamport_balance(balance);
}
if exit_signal.load(Ordering::Relaxed) {
break;
}
sleep(Duration::from_millis(50));
}
}
fn do_tx_transfers<T: Client>(
exit_signal: &Arc<AtomicBool>,
shared_txs: &SharedTransactions,
@ -398,11 +451,10 @@ fn do_tx_transfers<T: Client>(
if thread_batch_sleep_ms > 0 {
sleep(Duration::from_millis(thread_batch_sleep_ms as u64));
}
let txs;
{
let txs = {
let mut shared_txs_wl = shared_txs.write().expect("write lock in do_tx_transfers");
txs = shared_txs_wl.pop_front();
}
shared_txs_wl.pop_front()
};
if let Some(txs0) = txs {
shared_tx_thread_count.fetch_add(1, Ordering::Relaxed);
info!(
@ -758,11 +810,15 @@ fn compute_and_report_stats(
);
}
// First transfer 3/4 of the lamports to the dest accounts
// then ping-pong 1/4 of the lamports back to the other account
// this leaves 1/4 lamport buffer in each account
fn should_switch_directions(num_lamports_per_account: u64, i: u64) -> bool {
i % (num_lamports_per_account / 4) == 0 && (i >= (3 * num_lamports_per_account) / 4)
// First transfer 2/3 of the lamports to the dest accounts
// then ping-pong 1/3 of the lamports back to the other account
// this leaves 1/3 lamport buffer in each account
fn should_switch_directions(num_lamports_per_account: u64, keypair_chunks: u64, i: u64) -> bool {
if i < keypair_chunks * (2 * num_lamports_per_account) / 3 {
return false;
}
i % (keypair_chunks * num_lamports_per_account / 3) == 0
}
pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec<Keypair>, u64) {
@ -897,9 +953,12 @@ fn fund_move_keys<T: Client>(
info!("funded libra funding key {}", i);
}
let tx_count = keypairs.len();
let amount = total / (tx_count as u64);
for (i, keys) in keypairs[..tx_count].chunks(NUM_FUNDING_KEYS).enumerate() {
let keypair_count = keypairs.len();
let amount = total / (keypair_count as u64);
for (i, keys) in keypairs[..keypair_count]
.chunks(NUM_FUNDING_KEYS)
.enumerate()
{
for (j, key) in keys.iter().enumerate() {
let tx = librapay_transaction::transfer(
libra_pay_program_id,
@ -949,18 +1008,18 @@ pub fn generate_and_fund_keypairs<T: Client>(
client: &T,
drone_addr: Option<SocketAddr>,
funding_key: &Keypair,
tx_count: usize,
keypair_count: usize,
lamports_per_account: u64,
use_move: bool,
) -> Result<(Vec<Keypair>, Option<LibraKeys>, u64)> {
info!("Creating {} keypairs...", tx_count * 2);
let (mut keypairs, extra) = generate_keypairs(funding_key, tx_count as u64 * 2);
info!("Creating {} keypairs...", keypair_count);
let (mut keypairs, extra) = generate_keypairs(funding_key, keypair_count as u64);
info!("Get lamports...");
// Sample the first keypair, see if it has lamports, if so then resume.
// This logic is to prevent lamport loss on repeated solana-bench-tps executions
let last_keypair_balance = client
.get_balance(&keypairs[tx_count * 2 - 1].pubkey())
.get_balance(&keypairs[keypair_count - 1].pubkey())
.unwrap_or(0);
#[cfg(feature = "move")]
@ -999,7 +1058,7 @@ pub fn generate_and_fund_keypairs<T: Client>(
// Still fund the solana ones which will be used for fees.
let seed = [0u8; 32];
let mut rnd = GenKeys::new(seed);
let move_keypairs = rnd.gen_n_keypairs(tx_count as u64 * 2);
let move_keypairs = rnd.gen_n_keypairs(keypair_count as u64);
fund_move_keys(
client,
funding_key,
@ -1032,7 +1091,7 @@ pub fn generate_and_fund_keypairs<T: Client>(
}
// 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys.
keypairs.truncate(2 * tx_count);
keypairs.truncate(keypair_count);
Ok((keypairs, move_keypairs_ret, last_keypair_balance))
}
@ -1048,17 +1107,21 @@ mod tests {
#[test]
fn test_switch_directions() {
assert_eq!(should_switch_directions(20, 0), false);
assert_eq!(should_switch_directions(20, 1), false);
assert_eq!(should_switch_directions(20, 14), false);
assert_eq!(should_switch_directions(20, 15), true);
assert_eq!(should_switch_directions(20, 16), false);
assert_eq!(should_switch_directions(20, 19), false);
assert_eq!(should_switch_directions(20, 20), true);
assert_eq!(should_switch_directions(20, 21), false);
assert_eq!(should_switch_directions(20, 99), false);
assert_eq!(should_switch_directions(20, 100), true);
assert_eq!(should_switch_directions(20, 101), false);
assert_eq!(should_switch_directions(30, 1, 0), false);
assert_eq!(should_switch_directions(30, 1, 1), false);
assert_eq!(should_switch_directions(30, 1, 20), true);
assert_eq!(should_switch_directions(30, 1, 21), false);
assert_eq!(should_switch_directions(30, 1, 30), true);
assert_eq!(should_switch_directions(30, 1, 90), true);
assert_eq!(should_switch_directions(30, 1, 91), false);
assert_eq!(should_switch_directions(30, 2, 0), false);
assert_eq!(should_switch_directions(30, 2, 1), false);
assert_eq!(should_switch_directions(30, 2, 20), false);
assert_eq!(should_switch_directions(30, 2, 40), true);
assert_eq!(should_switch_directions(30, 2, 90), false);
assert_eq!(should_switch_directions(30, 2, 100), true);
assert_eq!(should_switch_directions(30, 2, 101), false);
}
#[test]
@ -1072,8 +1135,9 @@ mod tests {
config.tx_count = 10;
config.duration = Duration::from_secs(5);
let keypair_count = config.tx_count * config.keypair_multiplier;
let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20, false)
generate_and_fund_keypairs(&clients[0], None, &config.id, keypair_count, 20, false)
.unwrap();
do_bench_tps(clients, config, keypairs, 0, None);
@ -1084,11 +1148,11 @@ mod tests {
let (genesis_config, id) = create_genesis_config(10_000);
let bank = Bank::new(&genesis_config);
let client = BankClient::new(bank);
let tx_count = 10;
let keypair_count = 20;
let lamports = 20;
let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap();
generate_and_fund_keypairs(&client, None, &id, keypair_count, lamports, false).unwrap();
for kp in &keypairs {
assert_eq!(
@ -1107,11 +1171,11 @@ mod tests {
genesis_config.fee_calculator = fee_calculator;
let bank = Bank::new(&genesis_config);
let client = BankClient::new(bank);
let tx_count = 10;
let keypair_count = 20;
let lamports = 20;
let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap();
generate_and_fund_keypairs(&client, None, &id, keypair_count, lamports, false).unwrap();
let max_fee = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())

View File

@ -15,6 +15,7 @@ pub struct Config {
pub num_nodes: usize,
pub duration: Duration,
pub tx_count: usize,
pub keypair_multiplier: usize,
pub thread_batch_sleep_ms: usize,
pub sustained: bool,
pub client_ids_and_stake_file: String,
@ -36,6 +37,7 @@ impl Default for Config {
num_nodes: 1,
duration: Duration::new(std::u64::MAX, 0),
tx_count: 50_000,
keypair_multiplier: 8,
thread_batch_sleep_ms: 1000,
sustained: false,
client_ids_and_stake_file: String::new(),
@ -122,6 +124,13 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.takes_value(true)
.help("Number of transactions to send per batch")
)
.arg(
Arg::with_name("keypair_multiplier")
.long("keypair-multiplier")
.value_name("NUM")
.takes_value(true)
.help("Multiply by transaction count to determine number of keypairs to create")
)
.arg(
Arg::with_name("thread-batch-sleep-ms")
.short("z")
@ -208,7 +217,15 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
}
if let Some(s) = matches.value_of("tx_count") {
args.tx_count = s.to_string().parse().expect("can't parse tx_account");
args.tx_count = s.to_string().parse().expect("can't parse tx_count");
}
if let Some(s) = matches.value_of("keypair_multiplier") {
args.keypair_multiplier = s
.to_string()
.parse()
.expect("can't parse keypair-multiplier");
assert!(args.keypair_multiplier >= 2);
}
if let Some(t) = matches.value_of("thread-batch-sleep-ms") {

View File

@ -24,6 +24,7 @@ fn main() {
id,
num_nodes,
tx_count,
keypair_multiplier,
client_ids_and_stake_file,
write_to_client_file,
read_from_client_file,
@ -34,9 +35,10 @@ fn main() {
..
} = &cli_config;
let keypair_count = *tx_count * keypair_multiplier;
if *write_to_client_file {
info!("Generating {} keypairs", *tx_count * 2);
let (keypairs, _) = generate_keypairs(&id, *tx_count as u64 * 2);
info!("Generating {} keypairs", keypair_count);
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let num_accounts = keypairs.len() as u64;
let max_fee =
FeeCalculator::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
@ -102,10 +104,10 @@ fn main() {
last_balance = primordial_account.balance;
});
if keypairs.len() < tx_count * 2 {
if keypairs.len() < keypair_count {
eprintln!(
"Expected {} accounts in {}, only received {} (--tx_count mismatch?)",
tx_count * 2,
keypair_count,
client_ids_and_stake_file,
keypairs.len(),
);
@ -121,7 +123,7 @@ fn main() {
&client,
Some(*drone_addr),
&id,
*tx_count,
keypair_count,
*num_lamports_per_account,
*use_move,
)

View File

@ -47,11 +47,12 @@ fn test_bench_tps_local_cluster(config: Config) {
let lamports_per_account = 100;
let keypair_count = config.tx_count * config.keypair_multiplier;
let (keypairs, move_keypairs, _keypair_balance) = generate_and_fund_keypairs(
&client,
Some(drone_addr),
&config.id,
config.tx_count,
keypair_count,
lamports_per_account,
config.use_move,
)

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.21.3
solana-cli 0.21.5
Blockchain, Rebuilt for Scale
USAGE:

View File

@ -21,6 +21,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
* [getBlockTime](jsonrpc-api.md#getblocktime)
* [getClusterNodes](jsonrpc-api.md#getclusternodes)
* [getConfirmedBlock](jsonrpc-api.md#getconfirmedblock)
* [getConfirmedBlocks](jsonrpc-api.md#getconfirmedblocks)
* [getEpochInfo](jsonrpc-api.md#getepochinfo)
* [getEpochSchedule](jsonrpc-api.md#getepochschedule)
* [getGenesisHash](jsonrpc-api.md#getgenesishash)
@ -156,7 +157,7 @@ The result value will be an RpcResponse JSON object containing an AccountInfo JS
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.3,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]}},"id":1}
{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.5,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]}},"id":1}
```
### getBalance
@ -295,6 +296,31 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m
{"jsonrpc":"2.0","result":{"blockhash":[165,245,120,183,32,205,89,222,249,114,229,49,250,231,149,122,156,232,181,83,238,194,157,153,7,213,180,54,177,6,25,101],"parentSlot":429,"previousBlockhash":[21,108,181,90,139,241,212,203,45,78,232,29,161,31,159,188,110,82,81,11,250,74,47,140,188,28,23,96,251,164,208,166],"transactions":[[{"message":{"accountKeys":[[5],[219,181,202,40,52,148,34,136,186,59,137,160,250,225,234,17,244,160,88,116,24,176,30,227,68,11,199,38,141,68,131,228],[233,48,179,56,91,40,254,206,53,48,196,176,119,248,158,109,121,77,11,69,108,160,128,27,228,122,146,249,53,184,68,87],[6,167,213,23,25,47,10,175,198,242,101,227,251,119,204,122,218,130,197,41,208,190,59,19,110,45,0,85,32,0,0,0],[6,167,213,23,24,199,116,201,40,86,99,152,105,29,94,182,139,94,184,163,155,75,109,92,115,85,91,33,0,0,0,0],[7,97,72,29,53,116,116,187,124,77,118,36,235,211,189,179,216,53,94,115,209,16,67,252,13,163,83,128,0,0,0,0]],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[[1],{"accounts":[[3],1,2,3],"data":[[52],2,0,0,0,1,0,0,0,0,0,0,0,173,1,0,0,0,0,0,0,86,55,9,248,142,238,135,114,103,83,247,124,67,68,163,233,55,41,59,129,64,50,110,221,234,234,27,213,205,193,219,50],"program_id_index":4}],"recentBlockhash":[21,108,181,90,139,241,212,203,45,78,232,29,161,31,159,188,110,82,81,11,250,74,47,140,188,28,23,96,251,164,208,166]},"signatures":[[2],[119,9,95,108,35,95,7,1,69,101,65,45,5,204,61,114,172,88,123,238,32,201,135,229,57,50,13,21,106,216,129,183,238,43,37,101,148,81,56,232,88,136,80,65,46,189,39,106,94,13,238,54,186,48,118,186,0,62,121,122,172,171,66,5],[78,40,77,250,10,93,6,157,48,173,100,40,251,9,7,218,7,184,43,169,76,240,254,34,235,48,41,175,119,126,75,107,106,248,45,161,119,48,174,213,57,69,111,225,245,60,148,73,124,82,53,6,203,126,120,180,111,169,89,64,29,23,237,13]]},{"fee":100000,"status":{"Ok":null}}]]},"id":1}
```
### getConfirmedBlocks
Returns a list of confirmed blocks
#### Parameters:
* `integer` - start_slot, as u64 integer
* `integer` - (optional) end_slot, as u64 integer
#### Results:
The result field will be an array of u64 integers listing confirmed blocks
between start_slot and either end_slot, if provided, or latest confirmed block,
inclusive.
#### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5, 10]}' localhost:8899
// Result
{"jsonrpc":"2.0","result":[5,6,7,8,9,10],"id":1}
```
### getEpochInfo
Returns information about the current epoch
@ -373,15 +399,18 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
### getLeaderSchedule
Returns the leader schedule for the current epoch
Returns the leader schedule for an epoch
#### Parameters:
* `slot` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetched
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the current epoch
The result field will be a dictionary of leader public keys \(as base-58 encoded
strings\) and their corresponding leader slot indices as values (indices are to
the first slot in the requested epoch)
#### Example:
@ -390,7 +419,7 @@ The result field will be an array of leader public keys \(as base-58 encoded str
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[...],"id":1}
{"jsonrpc":"2.0","result":{"4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63]},"id":1}
```
### getMinimumBalanceForRentExemption
@ -824,7 +853,7 @@ Subscribe to an account to receive notifications when the lamports or data for a
#### Notification Format:
```bash
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.3,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0.21.5,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
```
### accountUnsubscribe
@ -882,7 +911,7 @@ Subscribe to a program to receive notifications when the lamports or data for a
* `object` - account info JSON object \(see [getAccountInfo](jsonrpc-api.md#getaccountinfo) for field details\)
```bash
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"data":[1,1,1,0,0,0,0,0,0,0.21.3,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"data":[1,1,1,0,0,0,0,0,0,0.21.5,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
```
### programUnsubscribe

View File

@ -81,8 +81,8 @@ With a FEC rate: `16:4`
With FEC rate of `16:16`
* `G = 12800`
* `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.0.21.3`
* `B = (1 - 0.0.21.3) ^ (12800 / 32) = 0.42583`
* `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.0.21.5`
* `B = (1 - 0.0.21.5) ^ (12800 / 32) = 0.42583`
With FEC rate of `32:32`
* `G = 12800`

View File

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

View File

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

View File

@ -33,7 +33,7 @@ else
fi
if [[ -z $CHANNEL_OR_TAG ]]; then
echo +++ Unable to determine channel to publish into, exiting.
echo +++ Unable to determine channel or tag to publish into, exiting.
exit 0
fi

View File

@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "0.21.3"
version = "0.21.5"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ edition = "2018"
clap = "2.33.0"
rpassword = "4.0"
semver = "0.9.0"
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
tiny-bip39 = "0.6.2"
url = "2.1.0"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -28,24 +28,24 @@ serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
serde_yaml = "0.8.11"
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-config-program = { path = "../programs/config", version = "0.21.3" }
solana-drone = { path = "../drone", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-config-program = { path = "../programs/config", version = "0.21.5" }
solana-drone = { path = "../drone", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.5" }
url = "2.1.0"
[dev-dependencies]
solana-core = { path = "../core", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-core = { path = "../core", version = "0.21.5" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
tempfile = "3.1.0"
[[bin]]

View File

@ -20,7 +20,7 @@ use solana_drone::drone::request_airdrop_transaction;
use solana_drone::drone_mock::request_airdrop_transaction;
use solana_sdk::{
bpf_loader,
clock::Slot,
clock::{Epoch, Slot},
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
@ -100,6 +100,10 @@ pub enum CliCommand {
timeout: Duration,
commitment_config: CommitmentConfig,
},
ShowBlockProduction {
epoch: Option<Epoch>,
slot_limit: Option<u64>,
},
ShowGossip,
ShowValidators {
use_lamports_unit: bool,
@ -173,7 +177,16 @@ pub enum CliCommand {
aggregate: bool,
span: Option<u64>,
},
VoteAuthorize(Pubkey, Pubkey, VoteAuthorize),
VoteAuthorize {
vote_account_pubkey: Pubkey,
new_authorized_pubkey: Pubkey,
vote_authorize: VoteAuthorize,
},
VoteUpdateValidator {
vote_account_pubkey: Pubkey,
new_identity_pubkey: Pubkey,
authorized_voter: KeypairEq,
},
// Wallet Commands
Address,
Airdrop {
@ -299,6 +312,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
("get-slot", Some(matches)) => parse_get_slot(matches),
("get-transaction-count", Some(matches)) => parse_get_transaction_count(matches),
("ping", Some(matches)) => parse_cluster_ping(matches),
("show-block-production", Some(matches)) => parse_show_block_production(matches),
("show-gossip", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::ShowGossip,
require_keypair: false,
@ -346,6 +360,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
},
// Vote Commands
("create-vote-account", Some(matches)) => parse_vote_create_account(matches),
("vote-update-validator", Some(matches)) => parse_vote_update_validator(matches),
("vote-authorize-voter", Some(matches)) => {
parse_vote_authorize(matches, VoteAuthorize::Voter)
}
@ -1030,6 +1045,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
timeout,
commitment_config,
),
CliCommand::ShowBlockProduction { epoch, slot_limit } => {
process_show_block_production(&rpc_client, *epoch, *slot_limit)
}
CliCommand::ShowGossip => process_show_gossip(&rpc_client),
CliCommand::ShowValidators { use_lamports_unit } => {
process_show_validators(&rpc_client, *use_lamports_unit)
@ -1206,15 +1224,28 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
&vote_account_pubkey,
*use_lamports_unit,
),
CliCommand::VoteAuthorize(vote_account_pubkey, new_authorized_pubkey, vote_authorize) => {
process_vote_authorize(
&rpc_client,
config,
&vote_account_pubkey,
&new_authorized_pubkey,
*vote_authorize,
)
}
CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey,
vote_authorize,
} => process_vote_authorize(
&rpc_client,
config,
&vote_account_pubkey,
&new_authorized_pubkey,
*vote_authorize,
),
CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_pubkey,
authorized_voter,
} => process_vote_update_validator(
&rpc_client,
config,
&vote_account_pubkey,
&new_identity_pubkey,
authorized_voter,
),
CliCommand::Uptime {
pubkey: vote_account_pubkey,
aggregate,
@ -2184,8 +2215,20 @@ mod tests {
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
let new_authorized_pubkey = Pubkey::new_rand();
config.command =
CliCommand::VoteAuthorize(bob_pubkey, new_authorized_pubkey, VoteAuthorize::Voter);
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey: bob_pubkey,
new_authorized_pubkey,
vote_authorize: VoteAuthorize::Voter,
};
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
let new_identity_pubkey = Pubkey::new_rand();
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey: bob_pubkey,
new_identity_pubkey,
authorized_voter: Keypair::new().into(),
};
let signature = process_command(&config);
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
@ -2368,7 +2411,18 @@ mod tests {
};
assert!(process_command(&config).is_err());
config.command = CliCommand::VoteAuthorize(bob_pubkey, bob_pubkey, VoteAuthorize::Voter);
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey: bob_pubkey,
new_authorized_pubkey: bob_pubkey,
vote_authorize: VoteAuthorize::Voter,
};
assert!(process_command(&config).is_err());
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey: bob_pubkey,
new_identity_pubkey: bob_pubkey,
authorized_voter: Keypair::new().into(),
};
assert!(process_command(&config).is_err());
config.command = CliCommand::GetSlot {

View File

@ -5,7 +5,7 @@ use crate::{
},
display::println_name_value,
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle};
use solana_clap_utils::{input_parsers::*, input_validators::*};
@ -13,13 +13,14 @@ use solana_client::{rpc_client::RpcClient, rpc_request::RpcVoteAccountInfo};
use solana_sdk::{
clock::{self, Slot},
commitment_config::CommitmentConfig,
epoch_schedule::{Epoch, EpochSchedule},
hash::Hash,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
system_transaction,
};
use std::{
collections::VecDeque,
collections::{HashMap, VecDeque},
net::SocketAddr,
thread::sleep,
time::{Duration, Instant},
@ -147,6 +148,22 @@ impl ClusterQuerySubCommands for App<'_, '_> {
),
),
)
.subcommand(
SubCommand::with_name("show-block-production")
.about("Show information about block production")
.arg(
Arg::with_name("epoch")
.long("epoch")
.takes_value(true)
.help("Epoch to show block production for [default: current epoch]"),
)
.arg(
Arg::with_name("slot_limit")
.long("slot-limit")
.takes_value(true)
.help("Limit results to this many slots from the end of the epoch [default: full epoch]"),
),
)
.subcommand(
SubCommand::with_name("show-gossip")
.about("Show the current gossip network nodes"),
@ -260,6 +277,20 @@ fn new_spinner_progress_bar() -> ProgressBar {
progress_bar
}
/// Aggregate epoch credit stats and return (total credits, total slots, total epochs)
pub fn aggregate_epoch_credits(
epoch_credits: &[(Epoch, u64, u64)],
epoch_schedule: &EpochSchedule,
) -> (u64, u64, u64) {
epoch_credits
.iter()
.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
})
}
pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult {
let cluster_nodes = rpc_client.get_cluster_nodes()?;
@ -378,6 +409,149 @@ pub fn process_get_slot(
Ok(slot.to_string())
}
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let epoch = value_t!(matches, "epoch", Epoch).ok();
let slot_limit = value_t!(matches, "slot_limit", u64).ok();
Ok(CliCommandInfo {
command: CliCommand::ShowBlockProduction { epoch, slot_limit },
require_keypair: false,
})
}
pub fn process_show_block_production(
rpc_client: &RpcClient,
epoch: Option<Epoch>,
slot_limit: Option<u64>,
) -> ProcessResult {
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::max())?;
let epoch = epoch.unwrap_or(epoch_info.epoch);
if epoch > epoch_info.epoch {
return Err(format!("Epoch {} is in the future", epoch).into());
}
let end_slot = std::cmp::min(
epoch_info.absolute_slot,
epoch_schedule.get_last_slot_in_epoch(epoch),
);
let start_slot = {
let start_slot = epoch_schedule.get_first_slot_in_epoch(epoch);
std::cmp::max(
end_slot.saturating_sub(slot_limit.unwrap_or(start_slot)),
start_slot,
)
};
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Connecting...");
progress_bar.set_message(&format!("Fetching leader schedule for epoch {}...", epoch));
progress_bar.set_message(&format!(
"Fetching confirmed blocks between slots {} and {}...",
start_slot, end_slot
));
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
let total_slots = (end_slot - start_slot + 1) as usize;
let total_blocks = confirmed_blocks.len();
assert!(total_blocks <= total_slots);
let total_slots_missed = total_slots - total_blocks;
let mut leader_slot_count = HashMap::new();
let mut leader_missed_slots = HashMap::new();
let leader_schedule = rpc_client
.get_leader_schedule_with_commitment(Some(start_slot), CommitmentConfig::max())?;
if leader_schedule.is_none() {
return Err(format!("Unable to fetch leader schedule for slot {}", start_slot).into());
}
let leader_schedule = leader_schedule.unwrap();
let mut leader_per_slot_index = Vec::new();
leader_per_slot_index.resize(total_slots, "");
for (pubkey, leader_slots) in leader_schedule.iter() {
for slot_index in leader_slots.iter() {
if *slot_index < total_slots {
leader_per_slot_index[*slot_index] = pubkey;
}
}
}
progress_bar.set_message(&format!(
"Processing {} slots containing {} blocks and {} empty slots...",
total_slots, total_blocks, total_slots_missed
));
let mut confirmed_blocks_index = 0;
for (slot_index, leader) in leader_per_slot_index.iter().enumerate().take(total_slots) {
let slot = start_slot + slot_index as u64;
let slot_count = leader_slot_count.entry(leader).or_insert(0);
*slot_count += 1;
let missed_slots = leader_missed_slots.entry(leader).or_insert(0);
loop {
if !confirmed_blocks.is_empty() {
let slot_of_next_confirmed_block = confirmed_blocks[confirmed_blocks_index];
if slot_of_next_confirmed_block < slot {
confirmed_blocks_index += 1;
continue;
}
if slot_of_next_confirmed_block == slot {
break;
}
}
*missed_slots += 1;
break;
}
}
progress_bar.finish_and_clear();
println!(
"\n{}",
style(format!(
" {:<44} {:>15} {:>15} {:>15} {:>23}",
"Identity Pubkey",
"Leader Slots",
"Blocks Produced",
"Missed Slots",
"Missed Block Percentage",
))
.bold()
);
let mut table = vec![];
for (leader, leader_slots) in leader_slot_count.iter() {
let missed_slots = leader_missed_slots.get(leader).unwrap();
let blocks_produced = leader_slots - missed_slots;
table.push(format!(
" {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
leader,
leader_slots,
blocks_produced,
missed_slots,
*missed_slots as f64 / *leader_slots as f64 * 100.
));
}
table.sort();
println!(
"{}\n\n {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
table.join("\n"),
format!("Epoch {} total:", epoch),
total_slots,
total_blocks,
total_slots_missed,
total_slots_missed as f64 / total_slots as f64 * 100.
);
println!(
" (using data from {} slots: {} to {})",
total_slots, start_slot, end_slot
);
Ok("".to_string())
}
pub fn process_get_transaction_count(
rpc_client: &RpcClient,
commitment_config: &CommitmentConfig,
@ -550,6 +724,7 @@ pub fn process_show_gossip(rpc_client: &RpcClient) -> ProcessResult {
}
pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult {
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let vote_accounts = rpc_client.get_vote_accounts()?;
let total_active_stake = vote_accounts
.current
@ -592,19 +767,21 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
println!(
"{}",
style(format!(
" {:<44} {:<44} {} {} {} {}",
" {:<44} {:<44} {} {} {} {:>7} {}",
"Identity Pubkey",
"Vote Account Pubkey",
"Commission",
"Last Vote",
"Root Block",
"Uptime",
"Active Stake",
))
.bold()
);
fn print_vote_account(
vote_account: &RpcVoteAccountInfo,
vote_account: RpcVoteAccountInfo,
epoch_schedule: &EpochSchedule,
total_active_stake: f64,
use_lamports_unit: bool,
delinquent: bool,
@ -616,8 +793,20 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
format!("{}", v)
}
}
fn uptime(epoch_credits: Vec<(Epoch, u64, u64)>, epoch_schedule: &EpochSchedule) -> String {
let (total_credits, total_slots, _) =
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
if total_slots > 0 {
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
format!("{:.2}%", total_uptime)
} else {
"-".into()
}
}
println!(
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>12}",
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}",
if delinquent {
WARNING.to_string()
} else {
@ -628,6 +817,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
vote_account.commission,
non_zero_or_dash(vote_account.last_vote),
non_zero_or_dash(vote_account.root_slot),
uptime(vote_account.epoch_credits, epoch_schedule),
if vote_account.activated_stake > 0 {
format!(
"{} ({:.2}%)",
@ -640,11 +830,23 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
);
}
for vote_account in vote_accounts.current.iter() {
print_vote_account(vote_account, total_active_stake, use_lamports_unit, false);
for vote_account in vote_accounts.current.into_iter() {
print_vote_account(
vote_account,
&epoch_schedule,
total_active_stake,
use_lamports_unit,
false,
);
}
for vote_account in vote_accounts.delinquent.iter() {
print_vote_account(vote_account, total_active_stake, use_lamports_unit, true);
for vote_account in vote_accounts.delinquent.into_iter() {
print_vote_account(
vote_account,
&epoch_schedule,
total_active_stake,
use_lamports_unit,
true,
);
}
Ok("".to_string())

View File

@ -1,6 +1,10 @@
use crate::cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
use crate::{
cli::{
build_balance_message, check_account_for_fee, check_unique_pubkeys,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
cluster_query::aggregate_epoch_credits,
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*};
@ -34,9 +38,9 @@ impl VoteSubCommands for App<'_, '_> {
.help("Vote account keypair to fund"),
)
.arg(
Arg::with_name("node_pubkey")
Arg::with_name("identity_pubkey")
.index(2)
.value_name("VALIDATOR PUBKEY")
.value_name("VALIDATOR IDENTITY PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
@ -66,6 +70,37 @@ impl VoteSubCommands for App<'_, '_> {
.help("Public key of the authorized withdrawer (defaults to cli config pubkey)"),
),
)
.subcommand(
SubCommand::with_name("vote-update-validator")
.about("Update the vote account's validator identity")
.arg(
Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE ACCOUNT PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Vote account to update"),
)
.arg(
Arg::with_name("new_identity_pubkey")
.index(2)
.value_name("NEW VALIDATOR IDENTITY PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("New validator that will vote with this account"),
)
.arg(
Arg::with_name("authorized_voter")
.index(3)
.value_name("AUTHORIZED VOTER KEYPAIR")
.takes_value(true)
.required(true)
.validator(is_keypair)
.help("Authorized voter keypair"),
)
)
.subcommand(
SubCommand::with_name("vote-authorize-voter")
.about("Authorize a new vote signing keypair for the given vote account")
@ -159,7 +194,7 @@ impl VoteSubCommands for App<'_, '_> {
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let vote_account = keypair_of(matches, "vote_account").unwrap();
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
let identity_pubkey = pubkey_of(matches, "identity_pubkey").unwrap();
let commission = value_of(&matches, "commission").unwrap_or(0);
let authorized_voter = pubkey_of(matches, "authorized_voter");
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer");
@ -167,7 +202,7 @@ pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandI
Ok(CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: vote_account.into(),
node_pubkey,
node_pubkey: identity_pubkey,
authorized_voter,
authorized_withdrawer,
commission,
@ -184,11 +219,26 @@ pub fn parse_vote_authorize(
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
Ok(CliCommandInfo {
command: CliCommand::VoteAuthorize(
command: CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey,
vote_authorize,
),
},
require_keypair: true,
})
}
pub fn parse_vote_update_validator(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
let new_identity_pubkey = pubkey_of(matches, "new_identity_pubkey").unwrap();
let authorized_voter = keypair_of(matches, "authorized_voter").unwrap();
Ok(CliCommandInfo {
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_pubkey,
authorized_voter: authorized_voter.into(),
},
require_keypair: true,
})
}
@ -229,7 +279,7 @@ pub fn process_create_vote_account(
rpc_client: &RpcClient,
config: &CliConfig,
vote_account: &Keypair,
node_pubkey: &Pubkey,
identity_pubkey: &Pubkey,
authorized_voter: &Option<Pubkey>,
authorized_withdrawer: &Option<Pubkey>,
commission: u8,
@ -237,7 +287,7 @@ pub fn process_create_vote_account(
let vote_account_pubkey = vote_account.pubkey();
check_unique_pubkeys(
(&vote_account_pubkey, "vote_account_pubkey".to_string()),
(&node_pubkey, "node_pubkey".to_string()),
(&identity_pubkey, "identity_pubkey".to_string()),
)?;
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
@ -251,7 +301,7 @@ pub fn process_create_vote_account(
1
};
let vote_init = VoteInit {
node_pubkey: *node_pubkey,
node_pubkey: *identity_pubkey,
authorized_voter: authorized_voter.unwrap_or(vote_account_pubkey),
authorized_withdrawer: authorized_withdrawer.unwrap_or(config.keypair.pubkey()),
commission,
@ -313,6 +363,40 @@ pub fn process_vote_authorize(
log_instruction_custom_error::<VoteError>(result)
}
pub fn process_vote_update_validator(
rpc_client: &RpcClient,
config: &CliConfig,
vote_account_pubkey: &Pubkey,
new_identity_pubkey: &Pubkey,
authorized_voter: &Keypair,
) -> ProcessResult {
check_unique_pubkeys(
(vote_account_pubkey, "vote_account_pubkey".to_string()),
(new_identity_pubkey, "new_identity_pubkey".to_string()),
)?;
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = vec![vote_instruction::update_node(
vote_account_pubkey,
&authorized_voter.pubkey(),
new_identity_pubkey,
)];
let mut tx = Transaction::new_signed_with_payer(
ixs,
Some(&config.keypair.pubkey()),
&[&config.keypair, authorized_voter],
recent_blockhash,
);
check_account_for_fee(
rpc_client,
&config.keypair.pubkey(),
&fee_calculator,
&tx.message,
)?;
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair]);
log_instruction_custom_error::<VoteError>(result)
}
fn get_vote_account(
rpc_client: &RpcClient,
vote_account_pubkey: &Pubkey,
@ -348,7 +432,7 @@ pub fn process_show_vote_account(
"account balance: {}",
build_balance_message(vote_account.lamports, use_lamports_unit, true)
);
println!("node id: {}", vote_state.node_pubkey);
println!("validator identity: {}", vote_state.node_pubkey);
println!("authorized voter: {}", vote_state.authorized_voter);
println!(
"authorized withdrawer: {}",
@ -396,38 +480,42 @@ pub fn process_uptime(
let epoch_schedule = rpc_client.get_epoch_schedule()?;
println!("Node id: {}", vote_state.node_pubkey);
println!("Authorized voter: {}", vote_state.authorized_voter);
println!("validator identity: {}", vote_state.node_pubkey);
println!("authorized voter: {}", vote_state.authorized_voter);
if !vote_state.votes.is_empty() {
println!("Uptime:");
println!("uptime:");
let epoch_credits_vec: Vec<(u64, u64, u64)> = vote_state.epoch_credits().copied().collect();
let epoch_credits = if let Some(x) = span {
epoch_credits_vec.iter().rev().take(x as usize)
let epoch_credits: Vec<(u64, u64, u64)> = if let Some(x) = span {
vote_state
.epoch_credits()
.iter()
.rev()
.take(x as usize)
.cloned()
.collect()
} else {
epoch_credits_vec.iter().rev().take(epoch_credits_vec.len())
vote_state.epoch_credits().iter().rev().cloned().collect()
};
if aggregate {
let (credits_earned, slots_in_epoch, epochs): (u64, u64, u64) =
epoch_credits.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
});
let total_uptime = credits_earned as f64 / slots_in_epoch as f64;
println!("{:.2}% over {} epochs", total_uptime * 100_f64, epochs,);
let (total_credits, total_slots, epochs) =
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
if total_slots > 0 {
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
println!("{:.2}% over {} epochs", total_uptime, epochs);
} else {
println!("Insufficient voting history available");
}
} else {
for (epoch, credits, prev_credits) in epoch_credits {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
let uptime = credits_earned as f64 / slots_in_epoch as f64;
println!("- epoch: {} {:.2}% uptime", epoch, uptime * 100_f64,);
}
}
if let Some(x) = span {
if x > epoch_credits_vec.len() as u64 {
if x > vote_state.epoch_credits().len() as u64 {
println!("(span longer than available epochs)");
}
}
@ -453,17 +541,24 @@ mod tests {
let keypair = Keypair::new();
let pubkey = keypair.pubkey();
let pubkey_string = pubkey.to_string();
let keypair2 = Keypair::new();
let pubkey2 = keypair2.pubkey();
let pubkey2_string = pubkey2.to_string();
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter",
&pubkey_string,
&pubkey_string,
&pubkey2_string,
]);
assert_eq!(
parse_command(&test_authorize_voter).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize(pubkey, pubkey, VoteAuthorize::Voter),
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: pubkey2,
vote_authorize: VoteAuthorize::Voter
},
require_keypair: true
}
);
@ -574,6 +669,27 @@ mod tests {
}
);
let test_update_validator = test_commands.clone().get_matches_from(vec![
"test",
"vote-update-validator",
&pubkey_string,
&pubkey2_string,
&keypair_file,
]);
assert_eq!(
parse_command(&test_update_validator).unwrap(),
CliCommandInfo {
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey: pubkey,
new_identity_pubkey: pubkey2,
authorized_voter: solana_sdk::signature::read_keypair_file(&keypair_file)
.unwrap()
.into(),
},
require_keypair: true
}
);
// Test Uptime Subcommand
let pubkey = Pubkey::new_rand();
let matches = test_commands.clone().get_matches_from(vec![

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "0.21.3"
version = "0.21.5"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -19,10 +19,10 @@ reqwest = { version = "0.9.22", default-features = false, features = ["rustls-tl
serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
[dev-dependencies]
jsonrpc-core = "14.0.3"
jsonrpc-http-server = "14.0.3"
solana-logger = { path = "../logger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.5" }

View File

@ -1,12 +1,10 @@
use crate::{client_error::ClientError, rpc_request::RpcRequest};
use solana_sdk::commitment_config::CommitmentConfig;
pub(crate) trait GenericRpcClientRequest {
fn send(
&self,
request: &RpcRequest,
params: Option<serde_json::Value>,
params: serde_json::Value,
retries: usize,
commitment_config: Option<CommitmentConfig>,
) -> Result<serde_json::Value, ClientError>;
}

View File

@ -5,7 +5,6 @@ use crate::{
};
use serde_json::{Number, Value};
use solana_sdk::{
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
transaction::{self, TransactionError},
};
@ -28,17 +27,16 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
fn send(
&self,
request: &RpcRequest,
params: Option<serde_json::Value>,
params: serde_json::Value,
_retries: usize,
_commitment_config: Option<CommitmentConfig>,
) -> Result<serde_json::Value, ClientError> {
if self.url == "fails" {
return Ok(Value::Null);
}
let val = match request {
RpcRequest::ConfirmTransaction => {
if let Some(Value::Array(param_array)) = params {
if let Value::String(param_string) = &param_array[0] {
if let Some(params_array) = params.as_array() {
if let Value::String(param_string) = &params_array[0] {
Value::Bool(param_string == SIGNATURE)
} else {
Value::Null

View File

@ -4,7 +4,10 @@ use crate::{
generic_rpc_client_request::GenericRpcClientRequest,
mock_rpc_client_request::MockRpcClientRequest,
rpc_client_request::RpcClientRequest,
rpc_request::{RpcContactInfo, RpcEpochInfo, RpcRequest, RpcVersionInfo, RpcVoteAccountStatus},
rpc_request::{
RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest,
RpcVersionInfo, RpcVoteAccountStatus,
},
};
use bincode::serialize;
use log::*;
@ -67,14 +70,12 @@ impl RpcClient {
signature: &str,
commitment_config: CommitmentConfig,
) -> RpcResponse<bool> {
let params = json!(signature);
let response = self
.client
.send(
&RpcRequest::ConfirmTransaction,
Some(params),
json!([signature, commitment_config]),
0,
Some(commitment_config),
)
.map_err(|err| {
io::Error::new(
@ -93,10 +94,9 @@ impl RpcClient {
pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> {
let serialized = serialize(transaction).unwrap();
let params = json!(serialized);
let signature = self
.client
.send(&RpcRequest::SendTransaction, Some(params), 5, None)?;
.send(&RpcRequest::SendTransaction, json!([serialized]), 5)?;
if signature.as_str().is_none() {
Err(io::Error::new(
io::ErrorKind::Other,
@ -120,12 +120,10 @@ impl RpcClient {
signature: &str,
commitment_config: CommitmentConfig,
) -> Result<Option<transaction::Result<()>>, ClientError> {
let params = json!(signature.to_string());
let signature_status = self.client.send(
&RpcRequest::GetSignatureStatus,
Some(params),
json!([signature.to_string(), commitment_config]),
5,
commitment_config.ok(),
)?;
let result: Option<transaction::Result<()>> =
serde_json::from_value(signature_status).unwrap();
@ -142,7 +140,7 @@ impl RpcClient {
) -> io::Result<Slot> {
let response = self
.client
.send(&RpcRequest::GetSlot, None, 0, commitment_config.ok())
.send(&RpcRequest::GetSlot, json!([commitment_config]), 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -161,7 +159,7 @@ impl RpcClient {
pub fn get_vote_accounts(&self) -> io::Result<RpcVoteAccountStatus> {
let response = self
.client
.send(&RpcRequest::GetVoteAccounts, None, 0, None)
.send(&RpcRequest::GetVoteAccounts, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -180,7 +178,7 @@ impl RpcClient {
pub fn get_cluster_nodes(&self) -> io::Result<Vec<RpcContactInfo>> {
let response = self
.client
.send(&RpcRequest::GetClusterNodes, None, 0, None)
.send(&RpcRequest::GetClusterNodes, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -196,11 +194,56 @@ impl RpcClient {
})
}
pub fn get_block_time(&self, slot: Slot) -> io::Result<UnixTimestamp> {
let params = json!(slot);
pub fn get_confirmed_block(&self, slot: Slot) -> io::Result<RpcConfirmedBlock> {
let response = self
.client
.send(&RpcRequest::GetBlockTime, Some(params), 0, None);
.send(&RpcRequest::GetConfirmedBlock, json!([slot]), 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetConfirmedBlock request failure: {:?}", err),
)
})?;
serde_json::from_value(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetConfirmedBlock parse failure: {}", err),
)
})
}
pub fn get_confirmed_blocks(
&self,
start_slot: Slot,
end_slot: Option<Slot>,
) -> io::Result<Vec<Slot>> {
let response = self
.client
.send(
&RpcRequest::GetConfirmedBlocks,
json!([start_slot, end_slot]),
0,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetConfirmedBlocks request failure: {:?}", err),
)
})?;
serde_json::from_value(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetConfirmedBlocks parse failure: {}", err),
)
})
}
pub fn get_block_time(&self, slot: Slot) -> io::Result<UnixTimestamp> {
let response = self
.client
.send(&RpcRequest::GetBlockTime, json!([slot]), 0);
response
.map(|result_json| {
@ -232,7 +275,7 @@ impl RpcClient {
) -> io::Result<RpcEpochInfo> {
let response = self
.client
.send(&RpcRequest::GetEpochInfo, None, 0, commitment_config.ok())
.send(&RpcRequest::GetEpochInfo, json!([commitment_config]), 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -248,10 +291,41 @@ impl RpcClient {
})
}
pub fn get_leader_schedule(&self, slot: Option<Slot>) -> io::Result<Option<RpcLeaderSchedule>> {
self.get_leader_schedule_with_commitment(slot, CommitmentConfig::default())
}
pub fn get_leader_schedule_with_commitment(
&self,
slot: Option<Slot>,
commitment_config: CommitmentConfig,
) -> io::Result<Option<RpcLeaderSchedule>> {
let response = self
.client
.send(
&RpcRequest::GetLeaderSchedule,
json!([slot, commitment_config]),
0,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetLeaderSchedule request failure: {:?}", err),
)
})?;
serde_json::from_value(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetLeaderSchedule failure: {}", err),
)
})
}
pub fn get_epoch_schedule(&self) -> io::Result<EpochSchedule> {
let response = self
.client
.send(&RpcRequest::GetEpochSchedule, None, 0, None)
.send(&RpcRequest::GetEpochSchedule, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -270,7 +344,7 @@ impl RpcClient {
pub fn get_inflation(&self) -> io::Result<Inflation> {
let response = self
.client
.send(&RpcRequest::GetInflation, None, 0, None)
.send(&RpcRequest::GetInflation, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -289,7 +363,7 @@ impl RpcClient {
pub fn get_version(&self) -> io::Result<RpcVersionInfo> {
let response = self
.client
.send(&RpcRequest::GetVersion, None, 0, None)
.send(&RpcRequest::GetVersion, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -438,10 +512,13 @@ impl RpcClient {
pubkey: &Pubkey,
retries: usize,
) -> Result<Option<u64>, Box<dyn error::Error>> {
let params = json!(format!("{}", pubkey));
let balance_json = self
.client
.send(&RpcRequest::GetBalance, Some(params), retries, None)
.send(
&RpcRequest::GetBalance,
json!([pubkey.to_string()]),
retries,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -477,12 +554,10 @@ impl RpcClient {
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> RpcResponse<Option<Account>> {
let params = json!(format!("{}", pubkey));
let response = self.client.send(
&RpcRequest::GetAccountInfo,
Some(params),
json!([pubkey.to_string(), commitment_config]),
0,
Some(commitment_config),
);
response
@ -510,14 +585,12 @@ impl RpcClient {
}
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> {
let params = json!(data_len);
let minimum_balance_json = self
.client
.send(
&RpcRequest::GetMinimumBalanceForRentExemption,
Some(params),
json!([data_len]),
0,
None,
)
.map_err(|err| {
io::Error::new(
@ -555,14 +628,12 @@ impl RpcClient {
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> RpcResponse<u64> {
let params = json!(pubkey.to_string());
let balance_json = self
.client
.send(
&RpcRequest::GetBalance,
Some(params),
json!([pubkey.to_string(), commitment_config]),
0,
Some(commitment_config),
)
.map_err(|err| {
io::Error::new(
@ -580,10 +651,13 @@ impl RpcClient {
}
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> io::Result<Vec<(Pubkey, Account)>> {
let params = json!(format!("{}", pubkey));
let response = self
.client
.send(&RpcRequest::GetProgramAccounts, Some(params), 0, None)
.send(
&RpcRequest::GetProgramAccounts,
json!([pubkey.to_string()]),
0,
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -625,9 +699,8 @@ impl RpcClient {
.client
.send(
&RpcRequest::GetTransactionCount,
None,
json!([commitment_config]),
0,
commitment_config.ok(),
)
.map_err(|err| {
io::Error::new(
@ -658,9 +731,8 @@ impl RpcClient {
.client
.send(
&RpcRequest::GetRecentBlockhash,
None,
json!([commitment_config]),
0,
commitment_config.ok(),
)
.map_err(|err| {
io::Error::new(
@ -723,7 +795,7 @@ impl RpcClient {
pub fn get_genesis_hash(&self) -> io::Result<Hash> {
let response = self
.client
.send(&RpcRequest::GetGenesisHash, None, 0, None)
.send(&RpcRequest::GetGenesisHash, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -848,14 +920,12 @@ impl RpcClient {
/// Check a signature in the bank.
pub fn check_signature(&self, signature: &Signature) -> bool {
trace!("check_signature: {:?}", signature);
let params = json!(format!("{}", signature));
for _ in 0..30 {
let response = self.client.send(
&RpcRequest::ConfirmTransaction,
Some(params.clone()),
json!([signature.to_string(), CommitmentConfig::recent()]),
0,
Some(CommitmentConfig::recent()),
);
match response {
@ -942,16 +1012,14 @@ impl RpcClient {
pub fn get_num_blocks_since_signature_confirmation(
&self,
sig: &Signature,
signature: &Signature,
) -> io::Result<usize> {
let params = json!(format!("{}", sig));
let response = self
.client
.send(
&RpcRequest::GetNumBlocksSinceSignatureConfirmation,
Some(params.clone()),
json!([signature.to_string(), CommitmentConfig::recent().ok()]),
1,
CommitmentConfig::recent().ok(),
)
.map_err(|err| {
io::Error::new(
@ -976,7 +1044,7 @@ impl RpcClient {
pub fn validator_exit(&self) -> io::Result<bool> {
let response = self
.client
.send(&RpcRequest::ValidatorExit, None, 0, None)
.send(&RpcRequest::ValidatorExit, Value::Null, 0)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -994,11 +1062,11 @@ impl RpcClient {
pub fn send(
&self,
request: &RpcRequest,
params: Option<Value>,
params: Value,
retries: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Value, ClientError> {
self.client.send(request, params, retries, commitment)
assert!(params.is_array() || params.is_null());
self.client.send(request, params, retries)
}
}
@ -1062,25 +1130,19 @@ mod tests {
let balance = rpc_client.send(
&RpcRequest::GetBalance,
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
0,
None,
);
assert_eq!(balance.unwrap().as_u64().unwrap(), 50);
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, None, 0, None);
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, Value::Null, 0);
assert_eq!(
blockhash.unwrap().as_str().unwrap(),
"deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"
);
// Send erroneous parameter
let blockhash = rpc_client.send(
&RpcRequest::GetRecentBlockhash,
Some(json!("parameter")),
0,
None,
);
let blockhash = rpc_client.send(&RpcRequest::GetRecentBlockhash, json!(["parameter"]), 0);
assert_eq!(blockhash.is_err(), true);
}
@ -1116,9 +1178,8 @@ mod tests {
let balance = rpc_client.send(
&RpcRequest::GetBalance,
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"])),
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]),
10,
None,
);
assert_eq!(balance.unwrap().as_u64().unwrap(), 5);
}

View File

@ -5,10 +5,7 @@ use crate::{
};
use log::*;
use reqwest::{self, header::CONTENT_TYPE};
use solana_sdk::{
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
commitment_config::CommitmentConfig,
};
use solana_sdk::clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT};
use std::{thread::sleep, time::Duration};
pub struct RpcClientRequest {
@ -38,14 +35,13 @@ impl GenericRpcClientRequest for RpcClientRequest {
fn send(
&self,
request: &RpcRequest,
params: Option<serde_json::Value>,
params: serde_json::Value,
mut retries: usize,
commitment_config: Option<CommitmentConfig>,
) -> Result<serde_json::Value, ClientError> {
// Concurrent requests are not supported so reuse the same request id for all requests
let request_id = 1;
let request_json = request.build_request_json(request_id, params, commitment_config);
let request_json = request.build_request_json(request_id, params);
loop {
match self

View File

@ -2,11 +2,10 @@ use jsonrpc_core::Result as JsonResult;
use serde_json::{json, Value};
use solana_sdk::{
clock::{Epoch, Slot},
commitment_config::CommitmentConfig,
hash::Hash,
transaction::{Result, Transaction},
};
use std::{error, fmt, io, net::SocketAddr};
use std::{collections::HashMap, error, fmt, io, net::SocketAddr};
pub type RpcResponseIn<T> = JsonResult<Response<T>>;
pub type RpcResponse<T> = io::Result<Response<T>>;
@ -49,6 +48,9 @@ pub struct RpcContactInfo {
pub rpc: Option<SocketAddr>,
}
/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcEpochInfo {
@ -97,6 +99,10 @@ pub struct RpcVoteAccountInfo {
/// Whether this account is staked for the current epoch
pub epoch_vote_account: bool,
/// History of how many credits earned by the end of each epoch
/// each tuple is (Epoch, credits, prev_credits)
pub epoch_credits: Vec<(Epoch, u64, u64)>,
/// Most recent slot voted on by this vote account (0 if no votes exist)
pub last_vote: u64,
@ -113,10 +119,13 @@ pub enum RpcRequest {
GetBalance,
GetBlockTime,
GetClusterNodes,
GetConfirmedBlock,
GetConfirmedBlocks,
GetEpochInfo,
GetEpochSchedule,
GetGenesisHash,
GetInflation,
GetLeaderSchedule,
GetNumBlocksSinceSignatureConfirmation,
GetProgramAccounts,
GetRecentBlockhash,
@ -138,12 +147,7 @@ pub enum RpcRequest {
}
impl RpcRequest {
pub(crate) fn build_request_json(
&self,
id: u64,
params: Option<Value>,
commitment_config: Option<CommitmentConfig>,
) -> Value {
pub(crate) fn build_request_json(&self, id: u64, params: Value) -> Value {
let jsonrpc = "2.0";
let method = match self {
RpcRequest::ConfirmTransaction => "confirmTransaction",
@ -153,10 +157,13 @@ impl RpcRequest {
RpcRequest::GetBalance => "getBalance",
RpcRequest::GetBlockTime => "getBlockTime",
RpcRequest::GetClusterNodes => "getClusterNodes",
RpcRequest::GetConfirmedBlock => "getConfirmedBlock",
RpcRequest::GetConfirmedBlocks => "getConfirmedBlocks",
RpcRequest::GetEpochInfo => "getEpochInfo",
RpcRequest::GetEpochSchedule => "getEpochSchedule",
RpcRequest::GetGenesisHash => "getGenesisHash",
RpcRequest::GetInflation => "getInflation",
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
"getNumBlocksSinceSignatureConfirmation"
}
@ -178,21 +185,12 @@ impl RpcRequest {
RpcRequest::SignVote => "signVote",
RpcRequest::GetMinimumBalanceForRentExemption => "getMinimumBalanceForRentExemption",
};
let mut request = json!({
json!({
"jsonrpc": jsonrpc,
"id": id,
"method": method,
});
if let Some(param_string) = params {
if let Some(config) = commitment_config {
request["params"] = json!([param_string, config]);
} else {
request["params"] = json!([param_string]);
}
} else if let Some(config) = commitment_config {
request["params"] = json!([config]);
}
request
"params": params,
})
}
}
@ -221,46 +219,46 @@ impl error::Error for RpcError {
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::commitment_config::CommitmentLevel;
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
#[test]
fn test_build_request_json() {
let test_request = RpcRequest::GetAccountInfo;
let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
let request = test_request.build_request_json(1, Some(addr.clone()), None);
let request = test_request.build_request_json(1, json!([addr.clone()]));
assert_eq!(request["method"], "getAccountInfo");
assert_eq!(request["params"], json!([addr]));
let test_request = RpcRequest::GetBalance;
let request = test_request.build_request_json(1, Some(addr), None);
let request = test_request.build_request_json(1, json!([addr]));
assert_eq!(request["method"], "getBalance");
let test_request = RpcRequest::GetEpochInfo;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getEpochInfo");
let test_request = RpcRequest::GetInflation;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getInflation");
let test_request = RpcRequest::GetRecentBlockhash;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getRecentBlockhash");
let test_request = RpcRequest::GetSlot;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getSlot");
let test_request = RpcRequest::GetTransactionCount;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "getTransactionCount");
let test_request = RpcRequest::RequestAirdrop;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "requestAirdrop");
let test_request = RpcRequest::SendTransaction;
let request = test_request.build_request_json(1, None, None);
let request = test_request.build_request_json(1, Value::Null);
assert_eq!(request["method"], "sendTransaction");
}
@ -273,13 +271,13 @@ mod tests {
// Test request with CommitmentConfig and no params
let test_request = RpcRequest::GetRecentBlockhash;
let request = test_request.build_request_json(1, None, Some(commitment_config.clone()));
let request = test_request.build_request_json(1, json!([commitment_config.clone()]));
assert_eq!(request["params"], json!([commitment_config.clone()]));
// Test request with CommitmentConfig and params
let test_request = RpcRequest::GetBalance;
let request =
test_request.build_request_json(1, Some(addr.clone()), Some(commitment_config.clone()));
test_request.build_request_json(1, json!([addr.clone(), commitment_config.clone()]));
assert_eq!(request["params"], json!([addr, commitment_config]));
}
}

View File

@ -1,7 +1,7 @@
[package]
name = "solana-core"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -41,25 +41,25 @@ rayon = "1.2.0"
serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-drone = { path = "../drone", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-chacha-sys = { path = "../chacha-sys", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-drone = { path = "../drone", version = "0.21.5" }
ed25519-dalek = "1.0.0-pre.1"
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-measure = { path = "../measure", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-perf = { path = "../perf", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-measure = { path = "../measure", version = "0.21.5" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }
solana-perf = { path = "../perf", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.5" }
symlink = "0.1.0"
sys-info = "0.5.8"
tempfile = "3.1.0"
@ -68,7 +68,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.21.3" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.5" }
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
[target."cfg(unix)".dependencies]

View File

@ -748,9 +748,8 @@ impl Archiver {
Ok(rpc_client
.send(
&RpcRequest::GetSlotsPerSegment,
None,
serde_json::json!([client_commitment]),
0,
Some(client_commitment),
)
.map_err(|err| {
warn!("Error while making rpc request {:?}", err);
@ -803,7 +802,11 @@ impl Archiver {
RpcClient::new_socket(rpc_peers[node_index].rpc)
};
let response = rpc_client
.send(&RpcRequest::GetStorageTurn, None, 0, None)
.send(
&RpcRequest::GetStorageTurn,
serde_json::value::Value::Null,
0,
)
.map_err(|err| {
warn!("Error while making rpc request {:?}", err);
Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))

View File

@ -12,11 +12,13 @@ use bincode::serialize;
use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc;
use solana_client::rpc_request::{
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcResponseContext, RpcVersionInfo,
RpcVoteAccountInfo, RpcVoteAccountStatus,
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule,
RpcResponseContext, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
};
use solana_drone::drone::request_airdrop_transaction;
use solana_ledger::{bank_forks::BankForks, blocktree::Blocktree};
use solana_ledger::{
bank_forks::BankForks, blocktree::Blocktree, rooted_slot_iterator::RootedSlotIterator,
};
use solana_runtime::bank::Bank;
use solana_sdk::{
account::Account,
@ -33,6 +35,7 @@ use solana_sdk::{
};
use solana_vote_program::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
use std::{
collections::HashMap,
net::{SocketAddr, UdpSocket},
sync::{Arc, RwLock},
thread::sleep,
@ -251,14 +254,11 @@ impl JsonRpcRequestProcessor {
activated_stake: *activated_stake,
commission: vote_state.commission,
root_slot: vote_state.root_slot.unwrap_or(0),
epoch_credits: vote_state.epoch_credits().clone(),
epoch_vote_account,
last_vote,
}
})
.filter(|vote_account_info| {
// Remove vote accounts with no delegated stake that have never voted
vote_account_info.last_vote != 0 || vote_account_info.activated_stake != 0
})
.partition(|vote_account_info| {
if bank.slot() >= MAX_LOCKOUT_HISTORY as u64 {
vote_account_info.last_vote > bank.slot() - MAX_LOCKOUT_HISTORY as u64
@ -266,9 +266,15 @@ impl JsonRpcRequestProcessor {
vote_account_info.last_vote > 0
}
});
let delinquent_staked_vote_accounts = delinquent_vote_accounts
.into_iter()
.filter(|vote_account_info| vote_account_info.activated_stake > 0)
.collect::<Vec<_>>();
Ok(RpcVoteAccountStatus {
current: current_vote_accounts,
delinquent: delinquent_vote_accounts,
delinquent: delinquent_staked_vote_accounts,
})
}
@ -310,6 +316,29 @@ impl JsonRpcRequestProcessor {
Ok(self.blocktree.get_confirmed_block(slot).ok())
}
pub fn get_confirmed_blocks(
&self,
start_slot: Slot,
end_slot: Option<Slot>,
) -> Result<Vec<Slot>> {
let end_slot = end_slot.unwrap_or_else(|| self.bank(None).slot());
if end_slot < start_slot {
return Ok(vec![]);
}
let start_slot = (start_slot..end_slot).find(|&slot| self.blocktree.is_root(slot));
if let Some(start_slot) = start_slot {
let mut slots: Vec<Slot> = RootedSlotIterator::new(start_slot, &self.blocktree)
.unwrap()
.map(|(slot, _)| slot)
.collect();
slots.retain(|&x| x <= end_slot);
Ok(slots)
} else {
Ok(vec![])
}
}
// The `get_block_time` method is not fully implemented. It currently returns `slot` *
// DEFAULT_MS_PER_SLOT offset from 0 for all requests, and null for any values that would
// overflow.
@ -415,7 +444,7 @@ pub trait RpcSol {
fn get_block_commitment(
&self,
meta: Self::Metadata,
block: u64,
block: Slot,
) -> Result<(Option<BlockCommitment>, u64)>;
#[rpc(meta, name = "getGenesisHash")]
@ -425,8 +454,9 @@ pub trait RpcSol {
fn get_leader_schedule(
&self,
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>>;
) -> Result<Option<RpcLeaderSchedule>>;
#[rpc(meta, name = "getRecentBlockhash")]
fn get_recent_blockhash(
@ -536,6 +566,14 @@ pub trait RpcSol {
#[rpc(meta, name = "getBlockTime")]
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>>;
#[rpc(meta, name = "getConfirmedBlocks")]
fn get_confirmed_blocks(
&self,
meta: Self::Metadata,
start_slot: Slot,
end_slot: Option<Slot>,
) -> Result<Vec<Slot>>;
}
pub struct RpcSolImpl;
@ -675,8 +713,9 @@ impl RpcSol for RpcSolImpl {
) -> Result<RpcEpochInfo> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
let epoch_schedule = bank.epoch_schedule();
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot());
let slot = bank.slot();
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(slot);
Ok(RpcEpochInfo {
epoch,
slot_index,
@ -705,17 +744,25 @@ impl RpcSol for RpcSolImpl {
fn get_leader_schedule(
&self,
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>> {
) -> Result<Option<RpcLeaderSchedule>> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
let slot = slot.unwrap_or_else(|| bank.slot());
let epoch = bank.epoch_schedule().get_epoch(slot);
Ok(
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map(
solana_ledger::leader_schedule_utils::leader_schedule(epoch, &bank).map(
|leader_schedule| {
leader_schedule
.get_slot_leaders()
.iter()
.map(|pubkey| pubkey.to_string())
.collect()
let mut map = HashMap::new();
for (slot_index, pubkey) in
leader_schedule.get_slot_leaders().iter().enumerate()
{
let pubkey = pubkey.to_string();
map.entry(pubkey).or_insert_with(|| vec![]).push(slot_index);
}
map
},
),
)
@ -991,6 +1038,18 @@ impl RpcSol for RpcSolImpl {
.get_confirmed_block(slot)
}
fn get_confirmed_blocks(
&self,
meta: Self::Metadata,
start_slot: Slot,
end_slot: Option<Slot>,
) -> Result<Vec<Slot>> {
meta.request_processor
.read()
.unwrap()
.get_confirmed_blocks(start_slot, end_slot)
}
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>> {
meta.request_processor.read().unwrap().get_block_time(slot)
}
@ -1005,7 +1064,10 @@ pub mod tests {
replay_stage::tests::create_test_transactions_and_populate_blocktree,
};
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
use solana_ledger::get_tmp_ledger_path;
use solana_ledger::{
blocktree::entries_to_test_shreds, blocktree_processor::fill_blocktree_slot_with_ticks,
entry::next_entry_mut, get_tmp_ledger_path,
};
use solana_sdk::{
fee_calculator::DEFAULT_BURN_PERCENT,
hash::{hash, Hash},
@ -1014,7 +1076,10 @@ pub mod tests {
system_transaction,
transaction::TransactionError,
};
use solana_vote_program::{vote_instruction, vote_state::VoteInit};
use solana_vote_program::{
vote_instruction,
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
};
use std::{
collections::HashMap,
sync::atomic::{AtomicBool, Ordering},
@ -1022,20 +1087,30 @@ pub mod tests {
};
const TEST_MINT_LAMPORTS: u64 = 1_000_000;
const TEST_SLOTS_PER_EPOCH: u64 = 50;
struct RpcHandler {
io: MetaIoHandler<Meta>,
meta: Meta,
bank: Arc<Bank>,
bank_forks: Arc<RwLock<BankForks>>,
blockhash: Hash,
alice: Keypair,
leader_pubkey: Pubkey,
leader_vote_keypair: Keypair,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
confirmed_block_signatures: Vec<Signature>,
}
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
let (bank_forks, alice) = new_bank_forks();
start_rpc_handler_with_tx_and_blocktree(pubkey, vec![])
}
fn start_rpc_handler_with_tx_and_blocktree(
pubkey: &Pubkey,
blocktree_roots: Vec<Slot>,
) -> RpcHandler {
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
let bank = bank_forks.read().unwrap().working_bank();
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
@ -1064,6 +1139,55 @@ pub mod tests {
blocktree.clone(),
);
// Add timestamp vote to blocktree
let vote = Vote {
slots: vec![1],
hash: Hash::default(),
};
let vote_ix = vote_instruction::vote(
&leader_vote_keypair.pubkey(),
&leader_vote_keypair.pubkey(),
vote,
);
let vote_tx = Transaction::new_signed_instructions(
&[&leader_vote_keypair],
vec![vote_ix],
Hash::default(),
);
let shreds = entries_to_test_shreds(
vec![next_entry_mut(&mut Hash::default(), 0, vec![vote_tx])],
1,
0,
true,
0,
);
blocktree.insert_shreds(shreds, None, false).unwrap();
blocktree.set_roots(&[1]).unwrap();
let mut roots = blocktree_roots.clone();
if !roots.is_empty() {
roots.retain(|&x| x > 1);
let mut parent_bank = bank;
for (i, root) in roots.iter().enumerate() {
let new_bank =
Bank::new_from_parent(&parent_bank, parent_bank.collector_id(), *root);
parent_bank = bank_forks.write().unwrap().insert(new_bank);
parent_bank.squash();
bank_forks.write().unwrap().set_root(*root, &None);
let parent = if i > 0 { roots[i - 1] } else { 1 };
fill_blocktree_slot_with_ticks(&blocktree, 5, *root, parent, Hash::default());
}
blocktree.set_roots(&roots).unwrap();
let new_bank = Bank::new_from_parent(
&parent_bank,
parent_bank.collector_id(),
roots.iter().max().unwrap() + 1,
);
bank_forks.write().unwrap().insert(new_bank);
}
let bank = bank_forks.read().unwrap().working_bank();
let leader_pubkey = *bank.collector_id();
let exit = Arc::new(AtomicBool::new(false));
let validator_exit = create_validator_exit(&exit);
@ -1077,7 +1201,7 @@ pub mod tests {
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
JsonRpcConfig::default(),
bank_forks,
bank_forks.clone(),
block_commitment_cache.clone(),
blocktree,
StorageState::default(),
@ -1107,9 +1231,11 @@ pub mod tests {
io,
meta,
bank,
bank_forks,
blockhash,
alice,
leader_pubkey,
leader_vote_keypair,
block_commitment_cache,
confirmed_block_signatures,
}
@ -1120,7 +1246,7 @@ pub mod tests {
let bob_pubkey = Pubkey::new_rand();
let exit = Arc::new(AtomicBool::new(false));
let validator_exit = create_validator_exit(&exit);
let (bank_forks, alice) = new_bank_forks();
let (bank_forks, alice, _) = new_bank_forks();
let bank = bank_forks.read().unwrap().working_bank();
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
let ledger_path = get_tmp_ledger_path!();
@ -1326,6 +1452,62 @@ pub mod tests {
assert_eq!(epoch_schedule, *bank.epoch_schedule());
}
#[test]
fn test_rpc_get_leader_schedule() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&bob_pubkey);
for req in [
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [0]}"#,
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule"}"#,
]
.iter()
{
let rep = io.handle_request_sync(&req, meta.clone());
let res: Response = serde_json::from_str(&rep.expect("actual response"))
.expect("actual response deserialization");
let schedule: Option<RpcLeaderSchedule> = if let Response::Single(res) = res {
if let Output::Success(res) = res {
serde_json::from_value(res.result).unwrap()
} else {
panic!("Expected success for {}", req);
}
} else {
panic!("Expected single response");
};
let schedule = schedule.expect("leader schedule");
let bob_schedule = schedule
.get(&bank.collector_id().to_string())
.expect("leader not in the leader schedule");
assert_eq!(
bob_schedule.len(),
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank)
.unwrap()
.get_slot_leaders()
.len()
);
}
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [42424242]}"#;
let rep = io.handle_request_sync(&req, meta);
let res: Response = serde_json::from_str(&rep.expect("actual response"))
.expect("actual response deserialization");
let schedule: Option<RpcLeaderSchedule> = if let Response::Single(res) = res {
if let Output::Success(res) = res {
serde_json::from_value(res.result).unwrap()
} else {
panic!("Expected success");
}
} else {
panic!("Expected single response");
};
assert_eq!(schedule, None);
}
#[test]
fn test_rpc_get_account_info() {
let bob_pubkey = Pubkey::new_rand();
@ -1630,20 +1812,23 @@ pub mod tests {
);
}
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair) {
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair, Keypair) {
let GenesisConfigInfo {
mut genesis_config,
mint_keypair,
..
voting_keypair,
} = create_genesis_config(TEST_MINT_LAMPORTS);
genesis_config.rent.lamports_per_byte_year = 50;
genesis_config.rent.exemption_threshold = 2.0;
genesis_config.epoch_schedule =
EpochSchedule::custom(TEST_SLOTS_PER_EPOCH, TEST_SLOTS_PER_EPOCH, false);
let bank = Bank::new(&genesis_config);
(
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
mint_keypair,
voting_keypair,
)
}
@ -1847,6 +2032,54 @@ pub mod tests {
}
}
#[test]
fn test_get_confirmed_blocks() {
let bob_pubkey = Pubkey::new_rand();
let roots = vec![0, 1, 3, 4, 8];
let RpcHandler { io, meta, .. } =
start_rpc_handler_with_tx_and_blocktree(&bob_pubkey, roots.clone());
let req =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0]}}"#);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, roots);
let req =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[2]}}"#);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, vec![3, 4, 8]);
let req =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0, 4]}}"#);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, vec![0, 1, 3, 4]);
let req =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0, 7]}}"#);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, vec![0, 1, 3, 4]);
let req =
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[9, 11]}}"#);
let res = io.handle_request_sync(&req, meta);
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, Vec::<Slot>::new());
}
#[test]
fn test_get_block_time() {
let bob_pubkey = Pubkey::new_rand();
@ -1905,30 +2138,31 @@ pub mod tests {
let RpcHandler {
io,
meta,
bank,
mut bank,
bank_forks,
alice,
leader_vote_keypair,
..
} = start_rpc_handler_with_tx(&Pubkey::new_rand());
assert_eq!(bank.vote_accounts().len(), 1);
// Create a second vote account that has no stake. It should not be included in the
// getVoteAccounts response
let vote_keypair = Keypair::new();
// Create a vote account with no stake.
let alice_vote_keypair = Keypair::new();
let instructions = vote_instruction::create_account(
&alice.pubkey(),
&vote_keypair.pubkey(),
&alice_vote_keypair.pubkey(),
&VoteInit {
node_pubkey: alice.pubkey(),
authorized_voter: vote_keypair.pubkey(),
authorized_withdrawer: vote_keypair.pubkey(),
authorized_voter: alice_vote_keypair.pubkey(),
authorized_withdrawer: alice_vote_keypair.pubkey(),
commission: 0,
},
bank.get_minimum_balance_for_rent_exemption(VoteState::size_of()),
);
let transaction = Transaction::new_signed_instructions(
&[&alice, &vote_keypair],
&[&alice, &alice_vote_keypair],
instructions,
bank.last_blockhash(),
);
@ -1936,7 +2170,70 @@ pub mod tests {
.expect("process transaction");
assert_eq!(bank.vote_accounts().len(), 2);
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}}"#);
// Check getVoteAccounts: the bootstrap leader vote account will be delinquent as it has
// stake but has never voted, and the vote account with no stake should not be present.
{
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}}"#);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let vote_account_status: RpcVoteAccountStatus =
serde_json::from_value(result["result"].clone()).unwrap();
assert!(vote_account_status.current.is_empty());
assert_eq!(vote_account_status.delinquent.len(), 1);
for vote_account_info in vote_account_status.delinquent {
assert_ne!(vote_account_info.activated_stake, 0);
}
}
// Advance bank to the next epoch
for _ in 0..TEST_SLOTS_PER_EPOCH {
bank.freeze();
// Votes
let instructions = vec![
vote_instruction::vote(
&leader_vote_keypair.pubkey(),
&leader_vote_keypair.pubkey(),
Vote {
slots: vec![bank.slot()],
hash: bank.hash(),
},
),
vote_instruction::vote(
&alice_vote_keypair.pubkey(),
&alice_vote_keypair.pubkey(),
Vote {
slots: vec![bank.slot()],
hash: bank.hash(),
},
),
];
bank = bank_forks.write().unwrap().insert(Bank::new_from_parent(
&bank,
&Pubkey::default(),
bank.slot() + 1,
));
let transaction = Transaction::new_signed_with_payer(
instructions,
Some(&alice.pubkey()),
&[&alice, &leader_vote_keypair, &alice_vote_keypair],
bank.last_blockhash(),
);
bank.process_transaction(&transaction)
.expect("process transaction");
}
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
json!([CommitmentConfig::recent()])
);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
@ -1944,12 +2241,53 @@ pub mod tests {
let vote_account_status: RpcVoteAccountStatus =
serde_json::from_value(result["result"].clone()).unwrap();
// The bootstrap leader vote account will be delinquent as it has stake but has never
// voted. The vote account with no stake should not be present.
assert!(vote_account_status.current.is_empty());
assert_eq!(vote_account_status.delinquent.len(), 1);
for vote_account_info in vote_account_status.delinquent {
assert_ne!(vote_account_info.activated_stake, 0);
// The vote account with no stake should not be present.
assert!(vote_account_status.delinquent.is_empty());
// Both accounts should be active and have voting history.
assert_eq!(vote_account_status.current.len(), 2);
//let leader_info = &vote_account_status.current[0];
let leader_info = vote_account_status
.current
.iter()
.find(|x| x.vote_pubkey == leader_vote_keypair.pubkey().to_string())
.unwrap();
assert_ne!(leader_info.activated_stake, 0);
// Subtract one because the last vote always carries over to the next epoch
let expected_credits = TEST_SLOTS_PER_EPOCH - MAX_LOCKOUT_HISTORY as u64 - 1;
assert_eq!(leader_info.epoch_credits, vec![(0, expected_credits, 0)]);
// Advance bank with no voting
bank.freeze();
bank_forks.write().unwrap().insert(Bank::new_from_parent(
&bank,
&Pubkey::default(),
bank.slot() + TEST_SLOTS_PER_EPOCH,
));
// The leader vote account should now be delinquent, and the other vote account disappears
// because it's inactive with no stake
{
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
json!([CommitmentConfig::recent()])
);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let vote_account_status: RpcVoteAccountStatus =
serde_json::from_value(result["result"].clone()).unwrap();
assert!(vote_account_status.current.is_empty());
assert_eq!(vote_account_status.delinquent.len(), 1);
for vote_account_info in vote_account_status.delinquent {
assert_eq!(
vote_account_info.vote_pubkey,
leader_vote_keypair.pubkey().to_string()
);
}
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-crate-features"
version = "0.21.3"
version = "0.21.5"
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-drone"
version = "0.21.3"
version = "0.21.5"
description = "Solana Drone"
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.102"
serde_derive = "1.0.102"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-fixed-buf"
version = "0.21.3"
version = "0.21.5"
description = "A fixed-size byte array that supports bincode serde"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-genesis-programs"
version = "0.21.3"
version = "0.21.5"
description = "Solana genesis programs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,16 +10,16 @@ edition = "2018"
[dependencies]
log = { version = "0.4.8" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-config-program = { path = "../programs/config", version = "0.21.3" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vest-program = { path = "../programs/vest", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.21.5" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
solana-config-program = { path = "../programs/config", version = "0.21.5" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vest-program = { path = "../programs/vest", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
[lib]
crate-type = ["lib"]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-genesis"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,11 +16,11 @@ serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.5" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
tempfile = "3.1.0"

View File

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

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-install"
description = "The solana cluster software installer"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -26,11 +26,11 @@ reqwest = { version = "0.9.22", default-features = false, features = ["rustls-tl
serde = "1.0.102"
serde_derive = "1.0.102"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-config-program = { path = "../programs/config", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-config-program = { path = "../programs/config", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
tar = "0.4.26"
tempdir = "0.3.7"
url = "2.1.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-keygen"
version = "0.21.3"
version = "0.21.5"
description = "Solana key generation utility"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,8 +14,8 @@ clap = "2.33"
dirs = "2.0.2"
num_cpus = "1.11.1"
rpassword = "4.0"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
tiny-bip39 = "0.6.2"
[[bin]]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-ledger-tool"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -15,12 +15,12 @@ serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
[dev-dependencies]
assert_cmd = "0.11"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-ledger"
version = "0.21.3"
version = "0.21.5"
description = "Solana ledger"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -29,19 +29,19 @@ rayon = "1.2.0"
reed-solomon-erasure = { package = "solana-reed-solomon-erasure", version = "4.0.1-3", features = ["simd-accel"] }
serde = "1.0.102"
serde_derive = "1.0.102"
solana-client = { path = "../client", version = "0.21.3" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-measure = { path = "../measure", version = "0.21.3" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-perf = { path = "../perf", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.5" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-measure = { path = "../measure", version = "0.21.5" }
solana-merkle-tree = { path = "../merkle-tree", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-perf = { path = "../perf", version = "0.21.5" }
ed25519-dalek = "1.0.0-pre.1"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
sys-info = "0.5.8"
tar = "0.4.26"
tempfile = "3.1.0"
@ -56,7 +56,7 @@ features = ["lz4"]
[dev-dependencies]
assert_matches = "1.3.0"
matches = "0.1.6"
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
[lib]
crate-type = ["lib"]

View File

@ -716,8 +716,15 @@ fn get_cf_options() -> Options {
// 256 * 8 = 2GB. 6 of these columns should take at most 12GB of RAM
options.set_max_write_buffer_number(8);
options.set_write_buffer_size(MAX_WRITE_BUFFER_SIZE as usize);
options.set_target_file_size_base(MAX_WRITE_BUFFER_SIZE / 10);
options.set_max_bytes_for_level_base(MAX_WRITE_BUFFER_SIZE);
let file_num_compaction_trigger = 4;
// Recommend that this be around the size of level 0. Level 0 estimated size in stable state is
// write_buffer_size * min_write_buffer_number_to_merge * level0_file_num_compaction_trigger
// Source: https://docs.rs/rocksdb/0.6.0/rocksdb/struct.Options.html#method.set_level_zero_file_num_compaction_trigger
let total_size_base = MAX_WRITE_BUFFER_SIZE * file_num_compaction_trigger;
let file_size_base = total_size_base / 10;
options.set_level_zero_file_num_compaction_trigger(file_num_compaction_trigger as i32);
options.set_max_bytes_for_level_base(total_size_base);
options.set_target_file_size_base(file_size_base);
options
}

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-local-cluster"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -12,23 +12,23 @@ homepage = "https://solana.com/"
itertools = "0.8.1"
log = "0.4.8"
rand = "0.6.5"
solana-config-program = { path = "../programs/config", version = "0.21.3" }
solana-core = { path = "../core", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-drone = { path = "../drone", version = "0.21.3" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.3" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vest-program = { path = "../programs/vest", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-config-program = { path = "../programs/config", version = "0.21.5" }
solana-core = { path = "../core", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-drone = { path = "../drone", version = "0.21.5" }
solana-exchange-program = { path = "../programs/exchange", version = "0.21.5" }
solana-genesis-programs = { path = "../genesis-programs", version = "0.21.5" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vest-program = { path = "../programs/vest", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
symlink = "0.1.0"
tempfile = "3.1.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.3" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.5" }
[dev-dependencies]
serial_test = "0.2.0"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-log-analyzer"
description = "The solana cluster network analysis tool"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -17,8 +17,8 @@ semver = "0.9.0"
serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
[[bin]]
name = "solana-log-analyzer"

View File

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

View File

@ -1,7 +1,7 @@
[package]
name = "solana-measure"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@ -11,4 +11,4 @@ license = "Apache-2.0"
edition = "2018"
[dependencies]
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }

View File

@ -1,6 +1,6 @@
[package]
name = "solana-merkle-tree"
version = "0.21.3"
version = "0.21.5"
description = "Solana Merkle Tree"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -9,7 +9,7 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
[dev-dependencies]
hex = "0.4.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-metrics"
version = "0.21.3"
version = "0.21.5"
description = "Solana Metrics"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,7 +13,7 @@ env_logger = "0.7.1"
lazy_static = "1.4.0"
log = "0.4.8"
reqwest = { version = "0.9.22", default-features = false, features = ["rustls-tls"] }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
sys-info = "0.5.8"
[dev-dependencies]

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-net-shaper"
description = "The solana cluster network shaping tool"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,8 +16,8 @@ semver = "0.9.0"
serde = "1.0.102"
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
rand = "0.6.5"
[[bin]]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-net-utils"
version = "0.21.3"
version = "0.21.5"
description = "Solana Network Utilities"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,8 +18,8 @@ rand = "0.6.1"
serde = "1.0.102"
serde_derive = "1.0.102"
socket2 = "0.3.11"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-perf"
version = "0.21.3"
version = "0.21.5"
description = "Solana Performance APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,11 +18,11 @@ serde_derive = "1.0.102"
dlopen_derive = "0.1.4"
lazy_static = "1.4.0"
log = "0.4.8"
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.3" }
solana-budget-program = { path = "../programs/budget", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.5" }
solana-budget-program = { path = "../programs/budget", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
[lib]
name = "solana_perf"

View File

@ -1,7 +1,7 @@
[package]
name = "solana-bpf-programs"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "README.md"
@ -22,10 +22,10 @@ walkdir = "2"
bincode = "1.1.4"
byteorder = "1.3.2"
elf = "0.0.10"
solana-bpf-loader-program = { path = "../bpf_loader", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-bpf-loader-program = { path = "../bpf_loader", version = "0.21.5" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana_rbpf = "=0.1.19"
[[bench]]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "solana-budget-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Budget program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,10 +16,10 @@ num-derive = "0.3"
num-traits = "0.2"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-config-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Config program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -14,8 +14,8 @@ chrono = { version = "0.4.10", features = ["serde"] }
log = "0.4.8"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-config-tests"
version = "0.21.3"
version = "0.21.5"
description = "Solana config api tests"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,11 +13,11 @@ bincode = "1.2.0"
log = "0.4.8"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-config-program = { path = "../config", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana-config-program = { path = "../config", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
assert_matches = "1.3.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-exchange-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Exchange program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -13,12 +13,12 @@ bincode = "1.2.0"
log = "0.4.8"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-metrics = { path = "../../metrics", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-metrics = { path = "../../metrics", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-failure-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana failure program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,10 +10,10 @@ edition = "2018"
[dependencies]
log = "0.4.8"
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-librapay-api"
version = "0.21.3"
version = "0.21.5"
description = "Solana Libra Payment"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -11,10 +11,10 @@ edition = "2018"
[dependencies]
bincode = "1.2.0"
log = "0.4.8"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-move-loader-program = { path = "../move_loader", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-move-loader-program = { path = "../move_loader", version = "0.21.5" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
language_e2e_tests = { version = "0.0.1-sol4", package = "solana_libra_language_e2e_tests" }
types = { version = "0.0.1-sol4", package = "solana_libra_types" }

View File

@ -1,6 +1,6 @@
[package]
name = "solana-move-loader-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Move loader"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,8 +18,8 @@ serde = "1.0.102"
serde_bytes = "0.11"
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
bytecode_verifier = { version = "0.0.1-sol4", package = "solana_libra_bytecode_verifier" }
canonical_serialization = { version = "0.0.1-sol4", package = "solana_libra_canonical_serialization" }

View File

@ -1,6 +1,6 @@
[package]
name = "solana-noop-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Noop program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,8 +10,8 @@ edition = "2018"
[dependencies]
log = "0.4.8"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-ownable-api"
version = "0.21.3"
version = "0.21.5"
description = "ownable program API"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,12 +12,12 @@ edition = "2018"
bincode = "1.2.0"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
num-derive = "0.3"
num-traits = "0.2"
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
[lib]
crate-type = ["lib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-stake-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Stake program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,11 +16,11 @@ num-traits = "0.2"
rand = "0.6.5"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-metrics = { path = "../../metrics", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-vote-program = { path = "../vote", version = "0.21.3" }
solana-config-program = { path = "../config", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-metrics = { path = "../../metrics", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana-vote-program = { path = "../vote", version = "0.21.5" }
solana-config-program = { path = "../config", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-stake-tests"
version = "0.21.3"
version = "0.21.5"
description = "Solana stake tests"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,11 +10,11 @@ edition = "2018"
[dependencies]
log = "0.4.8"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-stake-program = { path = "../stake", version = "0.21.3" }
solana-vote-program = { path = "../vote", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana-stake-program = { path = "../stake", version = "0.21.5" }
solana-vote-program = { path = "../vote", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
assert_matches = "1.3.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-storage-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Storage program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,8 +16,8 @@ num-derive = "0.3"
num-traits = "0.2"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-storage-tests"
version = "0.21.3"
version = "0.21.5"
description = "Solana storage tests"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,11 +10,11 @@ edition = "2018"
[dependencies]
log = "0.4.8"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-storage-program = { path = "../storage", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana-storage-program = { path = "../storage", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
assert_matches = "1.3.0"
bincode = "1.2.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-vest-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Vest program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -16,11 +16,11 @@ num-derive = "0.2"
num-traits = "0.2"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-config-program = { path = "../config", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
solana-config-program = { path = "../config", version = "0.21.5" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "0.21.3" }
solana-runtime = { path = "../../runtime", version = "0.21.5" }
[lib]
crate-type = ["lib"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-vote-program"
version = "0.21.3"
version = "0.21.5"
description = "Solana Vote program"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -15,9 +15,9 @@ num-derive = "0.3"
num-traits = "0.2"
serde = "1.0.102"
serde_derive = "1.0.102"
solana-logger = { path = "../../logger", version = "0.21.3" }
solana-metrics = { path = "../../metrics", version = "0.21.3" }
solana-sdk = { path = "../../sdk", version = "0.21.3" }
solana-logger = { path = "../../logger", version = "0.21.5" }
solana-metrics = { path = "../../metrics", version = "0.21.5" }
solana-sdk = { path = "../../sdk", version = "0.21.5" }
[lib]
crate-type = ["lib", "cdylib"]

View File

@ -63,7 +63,7 @@ pub enum VoteInstruction {
/// Withdraw some amount of funds
Withdraw(u64),
/// Update the vote account's node id
/// Update the vote account's validator identity (node id)
UpdateNode(Pubkey),
}
@ -108,11 +108,12 @@ pub fn authorize(
}
pub fn update_node(
vote_pubkey: &Pubkey, // vote account
authorized_pubkey: &Pubkey, // currently authorized
vote_pubkey: &Pubkey,
authorized_voter_pubkey: &Pubkey,
node_pubkey: &Pubkey,
) -> Instruction {
let account_metas = vec![AccountMeta::new(*vote_pubkey, false)].with_signer(authorized_pubkey);
let account_metas =
vec![AccountMeta::new(*vote_pubkey, false)].with_signer(authorized_voter_pubkey);
Instruction::new(
id(),

View File

@ -315,8 +315,8 @@ impl VoteState {
/// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
/// credits for each epoch is credits - prev_credits; while redundant this makes
/// calculating rewards over partial epochs nice and simple
pub fn epoch_credits(&self) -> impl Iterator<Item = &(Epoch, u64, u64)> {
self.epoch_credits.iter()
pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
&self.epoch_credits
}
fn pop_expired_votes(&mut self, slot: Slot) {
@ -1194,13 +1194,7 @@ mod tests {
let mut vote_state = VoteState::default();
assert_eq!(vote_state.credits(), 0);
assert_eq!(
vote_state
.epoch_credits()
.cloned()
.collect::<Vec<(Epoch, u64, u64)>>(),
vec![]
);
assert_eq!(vote_state.epoch_credits().clone(), vec![]);
let mut expected = vec![];
let mut credits = 0;
@ -1218,45 +1212,18 @@ mod tests {
}
assert_eq!(vote_state.credits(), credits);
assert_eq!(
vote_state
.epoch_credits()
.cloned()
.collect::<Vec<(Epoch, u64, u64)>>(),
expected
);
assert_eq!(vote_state.epoch_credits().clone(), expected);
}
#[test]
fn test_vote_state_epoch0_no_credits() {
let mut vote_state = VoteState::default();
assert_eq!(
vote_state
.epoch_credits()
.cloned()
.collect::<Vec<(Epoch, u64, u64)>>()
.len(),
0
);
assert_eq!(vote_state.epoch_credits().len(), 0);
vote_state.increment_credits(1);
assert_eq!(
vote_state
.epoch_credits()
.cloned()
.collect::<Vec<(Epoch, u64, u64)>>()
.len(),
0
);
assert_eq!(vote_state.epoch_credits().len(), 0);
vote_state.increment_credits(2);
assert_eq!(
vote_state
.epoch_credits()
.cloned()
.collect::<Vec<(Epoch, u64, u64)>>()
.len(),
1
);
assert_eq!(vote_state.epoch_credits().len(), 1);
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-rayon-threadlimit"
version = "0.21.3"
version = "0.21.5"
description = "solana-rayon-threadlimit"
homepage = "https://solana.com/"
readme = "../README.md"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-runtime"
version = "0.21.3"
version = "0.21.5"
description = "Solana runtime"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -24,17 +24,17 @@ rayon = "1.2.0"
serde = { version = "1.0.102", features = ["rc"] }
serde_derive = "1.0.102"
serde_json = "1.0.41"
solana-logger = { path = "../logger", version = "0.21.3" }
solana-measure = { path = "../measure", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-stake-program = { path = "../programs/stake", version = "0.21.3" }
solana-storage-program = { path = "../programs/storage", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-measure = { path = "../measure", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-stake-program = { path = "../programs/stake", version = "0.21.5" }
solana-storage-program = { path = "../programs/storage", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
sys-info = "0.5.8"
tempfile = "3.1.0"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.3" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "0.21.5" }
itertools = "0.8.2"
[lib]
@ -42,4 +42,4 @@ crate-type = ["lib"]
name = "solana_runtime"
[dev-dependencies]
solana-noop-program = { path = "../programs/noop", version = "0.21.3" }
solana-noop-program = { path = "../programs/noop", version = "0.21.5" }

View File

@ -11,7 +11,7 @@ pub struct AccountsIndex<T> {
pub roots: HashSet<Slot>,
//This value that needs to be stored to recover the index from AppendVec
// This value that needs to be stored to recover the index from AppendVec
pub last_root: Slot,
}

View File

@ -1378,7 +1378,12 @@ impl Bank {
pub fn get_account_modified_since_parent(&self, pubkey: &Pubkey) -> Option<(Account, Slot)> {
let just_self: HashMap<u64, usize> = vec![(self.slot(), 0)].into_iter().collect();
self.rc.accounts.load_slow(&just_self, pubkey)
if let Some((account, slot)) = self.rc.accounts.load_slow(&just_self, pubkey) {
if slot == self.slot() {
return Some((account, slot));
}
}
None
}
pub fn transaction_count(&self) -> u64 {
@ -3272,6 +3277,39 @@ mod tests {
assert_eq!(bank4.get_balance(&key1.pubkey()), 8);
}
#[test]
fn test_bank_get_account_modified_since_parent() {
let pubkey = Pubkey::new_rand();
let (genesis_config, mint_keypair) = create_genesis_config(500);
let bank1 = Arc::new(Bank::new(&genesis_config));
bank1.transfer(1, &mint_keypair, &pubkey).unwrap();
let result = bank1.get_account_modified_since_parent(&pubkey);
assert!(result.is_some());
let (account, slot) = result.unwrap();
assert_eq!(account.lamports, 1);
assert_eq!(slot, 0);
let bank2 = Arc::new(Bank::new_from_parent(&bank1, &Pubkey::default(), 1));
assert!(bank2.get_account_modified_since_parent(&pubkey).is_none());
bank2.transfer(100, &mint_keypair, &pubkey).unwrap();
let result = bank1.get_account_modified_since_parent(&pubkey);
assert!(result.is_some());
let (account, slot) = result.unwrap();
assert_eq!(account.lamports, 1);
assert_eq!(slot, 0);
let result = bank2.get_account_modified_since_parent(&pubkey);
assert!(result.is_some());
let (account, slot) = result.unwrap();
assert_eq!(account.lamports, 101);
assert_eq!(slot, 1);
bank1.squash();
let bank3 = Bank::new_from_parent(&bank2, &Pubkey::default(), 3);
assert_eq!(None, bank3.get_account_modified_since_parent(&pubkey));
}
#[test]
fn test_bank_epoch_vote_accounts() {
let leader_pubkey = Pubkey::new_rand();

View File

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

View File

@ -83,6 +83,7 @@ BINS=(
solana-net-shaper
solana-archiver
solana-validator
solana-watchtower
)
#XXX: Ensure `solana-genesis` is built LAST!

View File

@ -1,6 +1,6 @@
[package]
name = "solana-sdk-c"
version = "0.21.3"
version = "0.21.5"
description = "Solana SDK C"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -18,7 +18,7 @@ bs58 = "0.3.0"
libc = "0.2.65"
rand_chacha = "0.1.1"
rand_core = { version = ">=0.2, <0.4", default-features = false }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
ed25519-dalek = "1.0.0-pre.1"
sha2 = "0.8.0"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-sdk"
version = "0.21.3"
version = "0.21.5"
description = "Solana SDK"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -46,8 +46,8 @@ serde_derive = "1.0.102"
serde_json = { version = "1.0.41", optional = true }
sha2 = "0.8.0"
ed25519-dalek = { version = "1.0.0-pre.1", optional = true }
solana-crate-features = { path = "../crate-features", version = "0.21.3", optional = true }
solana-logger = { path = "../logger", version = "0.21.3", optional = true }
solana-crate-features = { path = "../crate-features", version = "0.21.5", optional = true }
solana-logger = { path = "../logger", version = "0.21.5", optional = true }
solana-sdk-macro = { path = "macro" }
[dev-dependencies]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-sdk-bpf-test"
version = "0.21.3"
version = "0.21.5"
description = "Solana BPF SDK test utilities"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -5,8 +5,15 @@ cd "$(dirname "$0")"/../..
eval "$(ci/channel-info.sh)"
source ci/rust-version.sh
if [[ -z $CHANNEL ]]; then
echo Unable to determine channel to publish into, exiting.
CHANNEL_OR_TAG=
if [[ -n "$CI_TAG" ]]; then
CHANNEL_OR_TAG=$CI_TAG
else
CHANNEL_OR_TAG=$CHANNEL
fi
if [[ -z $CHANNEL_OR_TAG ]]; then
echo Unable to determine channel or tag to publish into, exiting.
echo "^^^ +++"
exit 0
fi
@ -18,7 +25,7 @@ rm -rf usr/
cp -f ../../run.sh usr/bin/solana-run.sh
docker build -t solanalabs/solana:"$CHANNEL" .
docker build -t solanalabs/solana:"$CHANNEL_OR_TAG" .
maybeEcho=
if [[ -z $CI ]]; then
@ -32,4 +39,4 @@ else
fi
)
fi
$maybeEcho docker push solanalabs/solana:"$CHANNEL"
$maybeEcho docker push solanalabs/solana:"$CHANNEL_OR_TAG"

View File

@ -1,6 +1,6 @@
[package]
name = "solana-sdk-macro"
version = "0.21.3"
version = "0.21.5"
description = "Solana SDK Macro"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

View File

@ -19,6 +19,12 @@ impl CommitmentConfig {
}
}
pub fn max() -> Self {
Self {
commitment: CommitmentLevel::Max,
}
}
pub fn ok(&self) -> Option<Self> {
if self == &Self::default() {
None

View File

@ -1,6 +1,6 @@
[package]
name = "solana-upload-perf"
version = "0.21.3"
version = "0.21.5"
description = "Metrics Upload Utility"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ publish = false
[dependencies]
log = "0.4.8"
serde_json = "1.0.41"
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
[[bin]]
name = "solana-upload-perf"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-validator"
description = "Blockchain, Rebuilt for Scale"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -17,19 +17,19 @@ log = "0.4.8"
indicatif = "0.13.0"
reqwest = { version = "0.9.22", default-features = false }
serde_json = "1.0.41"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-client = { path = "../client", version = "0.21.3" }
solana-core = { path = "../core", version = "0.21.3" }
solana-drone = { path = "../drone", version = "0.21.3" }
solana-ledger = { path = "../ledger", version = "0.21.3" }
solana-logger = { path = "../logger", version = "0.21.3" }
solana-perf = { path = "../perf", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-net-utils = { path = "../net-utils", version = "0.21.3" }
solana-runtime = { path = "../runtime", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-vote-program = { path = "../programs/vote", version = "0.21.3" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-client = { path = "../client", version = "0.21.5" }
solana-core = { path = "../core", version = "0.21.5" }
solana-drone = { path = "../drone", version = "0.21.5" }
solana-ledger = { path = "../ledger", version = "0.21.5" }
solana-logger = { path = "../logger", version = "0.21.5" }
solana-perf = { path = "../perf", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-net-utils = { path = "../net-utils", version = "0.21.5" }
solana-runtime = { path = "../runtime", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
solana-vote-program = { path = "../programs/vote", version = "0.21.5" }
solana-vote-signer = { path = "../vote-signer", version = "0.21.5" }
tar = "0.4.26"
tempfile = "3.1.0"

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-vote-signer"
description = "Solana Vote Signing Service"
version = "0.21.3"
version = "0.21.5"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -17,9 +17,9 @@ jsonrpc-http-server = "14.0.3"
log = "0.4.8"
serde = "1.0.102"
serde_json = "1.0.41"
solana-clap-utils = { path = "../clap-utils", version = "0.21.3" }
solana-metrics = { path = "../metrics", version = "0.21.3" }
solana-sdk = { path = "../sdk", version = "0.21.3" }
solana-clap-utils = { path = "../clap-utils", version = "0.21.5" }
solana-metrics = { path = "../metrics", version = "0.21.5" }
solana-sdk = { path = "../sdk", version = "0.21.5" }
[lib]
crate-type = ["lib"]

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