Use rooted bank by default in rpc bank selection (#6759)

* Name anonymous parameters for clarity

* Add CommitmentConfig to select bank for rpc

* Add commitment information to jsonrpc docs

* Update send_and_confirm retries as per commitment defaults

* Pass CommitmentConfig into client requests; also various 'use' cleanup

* Use _with_commitment methods to speed local_cluster tests

* Pass CommitmentConfig into Archiver in order to enable quick confirmations in local_cluster tests

* Restore solana ping speed

* Increase wallet-sanity timeout to account for longer confirmation time
This commit is contained in:
Tyera Eulberg
2019-11-06 14:15:00 -07:00
committed by GitHub
parent 5e8668799c
commit b3a75a60a4
27 changed files with 1225 additions and 463 deletions

View File

@ -1,13 +1,15 @@
use clap::{crate_description, crate_name, crate_version, App, Arg}; use clap::{crate_description, crate_name, crate_version, App, Arg};
use console::style; use console::style;
use solana_core::archiver::Archiver; use solana_core::{
use solana_core::cluster_info::{Node, VALIDATOR_PORT_RANGE}; archiver::Archiver,
use solana_core::contact_info::ContactInfo; cluster_info::{Node, VALIDATOR_PORT_RANGE},
use solana_sdk::signature::{read_keypair_file, Keypair, KeypairUtil}; contact_info::ContactInfo,
use std::net::SocketAddr; };
use std::path::PathBuf; use solana_sdk::{
use std::process::exit; commitment_config::CommitmentConfig,
use std::sync::Arc; signature::{read_keypair_file, Keypair, KeypairUtil},
};
use std::{net::SocketAddr, path::PathBuf, process::exit, sync::Arc};
// Return an error if a keypair file cannot be parsed. // Return an error if a keypair file cannot be parsed.
fn is_keypair(string: String) -> Result<(), String> { fn is_keypair(string: String) -> Result<(), String> {
@ -118,6 +120,7 @@ fn main() {
entrypoint_info, entrypoint_info,
Arc::new(keypair), Arc::new(keypair),
Arc::new(storage_keypair), Arc::new(storage_keypair),
CommitmentConfig::recent(),
) )
.unwrap(); .unwrap();

View File

@ -8,31 +8,35 @@ use rayon::prelude::*;
use solana_client::perf_utils::{sample_txs, SampleStats}; use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_core::gen_keys::GenKeys; use solana_core::gen_keys::GenKeys;
use solana_drone::drone::request_airdrop_transaction; use solana_drone::drone::request_airdrop_transaction;
use solana_exchange_api::exchange_instruction; use solana_exchange_api::{exchange_instruction, exchange_state::*, id};
use solana_exchange_api::exchange_state::*;
use solana_exchange_api::id;
use solana_genesis::Base64Account; use solana_genesis::Base64Account;
use solana_metrics::datapoint_info; use solana_metrics::datapoint_info;
use solana_sdk::client::Client; use solana_sdk::{
use solana_sdk::client::SyncClient; client::{Client, SyncClient},
use solana_sdk::pubkey::Pubkey; commitment_config::CommitmentConfig,
use solana_sdk::signature::{Keypair, KeypairUtil}; pubkey::Pubkey,
use solana_sdk::timing::{duration_as_ms, duration_as_s}; signature::{Keypair, KeypairUtil},
use solana_sdk::transaction::Transaction; timing::{duration_as_ms, duration_as_s},
use solana_sdk::{system_instruction, system_program}; transaction::Transaction,
use std::cmp; {system_instruction, system_program},
use std::collections::{HashMap, VecDeque}; };
use std::fs::File; use std::{
use std::io::prelude::*; cmp,
use std::mem; collections::{HashMap, VecDeque},
use std::net::SocketAddr; fs::File,
use std::path::Path; io::prelude::*,
use std::process::exit; mem,
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; net::SocketAddr,
use std::sync::mpsc::{channel, Receiver, Sender}; path::Path,
use std::sync::{Arc, RwLock}; process::exit,
use std::thread::{sleep, Builder}; sync::{
use std::time::{Duration, Instant}; atomic::{AtomicBool, AtomicUsize, Ordering},
mpsc::{channel, Receiver, Sender},
Arc, RwLock,
},
thread::{sleep, Builder},
time::{Duration, Instant},
};
// TODO Chunk length as specified results in a bunch of failures, divide by 10 helps... // TODO Chunk length as specified results in a bunch of failures, divide by 10 helps...
// Assume 4MB network buffers, and 512 byte packets // Assume 4MB network buffers, and 512 byte packets
@ -380,7 +384,10 @@ fn swapper<T>(
let mut tries = 0; let mut tries = 0;
let mut trade_index = 0; let mut trade_index = 0;
while client while client
.get_balance(&trade_infos[trade_index].trade_account) .get_balance_with_commitment(
&trade_infos[trade_index].trade_account,
CommitmentConfig::recent(),
)
.unwrap_or(0) .unwrap_or(0)
== 0 == 0
{ {
@ -434,7 +441,7 @@ fn swapper<T>(
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
let to_swap_txs: Vec<_> = to_swap let to_swap_txs: Vec<_> = to_swap
.par_iter() .par_iter()
@ -562,7 +569,7 @@ fn trader<T>(
account_group = (account_group + 1) % account_groups as usize; account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
trades.chunks(chunk_size).for_each(|chunk| { trades.chunks(chunk_size).for_each(|chunk| {
@ -638,7 +645,9 @@ where
T: SyncClient + ?Sized, T: SyncClient + ?Sized,
{ {
for s in &tx.signatures { for s in &tx.signatures {
if let Ok(Some(r)) = sync_client.get_signature_status(s) { if let Ok(Some(r)) =
sync_client.get_signature_status_with_commitment(s, CommitmentConfig::recent())
{
match r { match r {
Ok(_) => { Ok(_) => {
return true; return true;
@ -659,12 +668,15 @@ fn verify_funding_transfer<T: SyncClient + ?Sized>(
) -> bool { ) -> bool {
if verify_transaction(client, tx) { if verify_transaction(client, tx) {
for a in &tx.message().account_keys[1..] { for a in &tx.message().account_keys[1..] {
if client.get_balance(a).unwrap_or(0) >= amount { if client
.get_balance_with_commitment(a, CommitmentConfig::recent())
.unwrap_or(0)
>= amount
{
return true; return true;
} }
} }
} }
false false
} }
@ -742,8 +754,9 @@ pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>],
to_fund_txs.len(), to_fund_txs.len(),
); );
let (blockhash, _fee_calculator) = let (blockhash, _fee_calculator) = client
client.get_recent_blockhash().expect("blockhash"); .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("blockhash");
to_fund_txs.par_iter_mut().for_each(|(k, tx)| { to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
tx.sign(&[*k], blockhash); tx.sign(&[*k], blockhash);
}); });
@ -780,7 +793,11 @@ pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>],
}); });
funded.append(&mut new_funded); funded.append(&mut new_funded);
funded.retain(|(k, b)| { funded.retain(|(k, b)| {
client.get_balance(&k.pubkey()).unwrap_or(0) > lamports && *b > lamports client
.get_balance_with_commitment(&k.pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
> lamports
&& *b > lamports
}); });
debug!(" Funded: {} left: {}", funded.len(), notfunded.len()); debug!(" Funded: {} left: {}", funded.len(), notfunded.len());
} }
@ -819,7 +836,7 @@ pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], acco
let mut retries = 0; let mut retries = 0;
while !to_create_txs.is_empty() { while !to_create_txs.is_empty() {
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
to_create_txs.par_iter_mut().for_each(|(k, tx)| { to_create_txs.par_iter_mut().for_each(|(k, tx)| {
let kp: &Keypair = k; let kp: &Keypair = k;
@ -863,7 +880,11 @@ pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], acco
let mut new_notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = vec![]; let mut new_notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = vec![];
for f in &notfunded { for f in &notfunded {
if client.get_balance(&f.1).unwrap_or(0) == 0 { if client
.get_balance_with_commitment(&f.1, CommitmentConfig::recent())
.unwrap_or(0)
== 0
{
new_notfunded.push(*f) new_notfunded.push(*f)
} }
} }
@ -920,7 +941,7 @@ fn generate_keypairs(num: u64) -> Vec<Keypair> {
} }
pub fn airdrop_lamports(client: &dyn Client, drone_addr: &SocketAddr, id: &Keypair, amount: u64) { pub fn airdrop_lamports(client: &dyn Client, drone_addr: &SocketAddr, id: &Keypair, amount: u64) {
let balance = client.get_balance(&id.pubkey()); let balance = client.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent());
let balance = balance.unwrap_or(0); let balance = balance.unwrap_or(0);
if balance >= amount { if balance >= amount {
return; return;
@ -938,19 +959,26 @@ pub fn airdrop_lamports(client: &dyn Client, drone_addr: &SocketAddr, id: &Keypa
let mut tries = 0; let mut tries = 0;
loop { loop {
let (blockhash, _fee_calculator) = client let (blockhash, _fee_calculator) = client
.get_recent_blockhash() .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash"); .expect("Failed to get blockhash");
match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) { match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => { Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap(); let signature = client.async_send_transaction(transaction).unwrap();
for _ in 0..30 { for _ in 0..30 {
if let Ok(Some(_)) = client.get_signature_status(&signature) { if let Ok(Some(_)) = client.get_signature_status_with_commitment(
&signature,
CommitmentConfig::recent(),
) {
break; break;
} }
sleep(Duration::from_millis(100)); sleep(Duration::from_millis(100));
} }
if client.get_balance(&id.pubkey()).unwrap_or(0) >= amount { if client
.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
>= amount
{
break; break;
} }
} }

View File

@ -1,5 +1,3 @@
use solana_metrics;
use crate::cli::Config; use crate::cli::Config;
use log::*; use log::*;
use rayon::prelude::*; use rayon::prelude::*;
@ -9,10 +7,11 @@ use solana_drone::drone::request_airdrop_transaction;
#[cfg(feature = "move")] #[cfg(feature = "move")]
use solana_librapay_api::{create_genesis, upload_mint_program, upload_payment_program}; use solana_librapay_api::{create_genesis, upload_mint_program, upload_payment_program};
use solana_measure::measure::Measure; use solana_measure::measure::Measure;
use solana_metrics::datapoint_debug; use solana_metrics::{self, datapoint_debug};
use solana_sdk::{ use solana_sdk::{
client::Client, client::Client,
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE}, clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
pubkey::Pubkey, pubkey::Pubkey,
@ -55,7 +54,7 @@ type LibraKeys = (Keypair, Pubkey, Pubkey, Vec<Keypair>);
fn get_recent_blockhash<T: Client>(client: &T) -> (Hash, FeeCalculator) { fn get_recent_blockhash<T: Client>(client: &T) -> (Hash, FeeCalculator) {
loop { loop {
match client.get_recent_blockhash() { match client.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) {
Ok((blockhash, fee_calculator)) => return (blockhash, fee_calculator), Ok((blockhash, fee_calculator)) => return (blockhash, fee_calculator),
Err(err) => { Err(err) => {
info!("Couldn't get recent blockhash: {:?}", err); info!("Couldn't get recent blockhash: {:?}", err);
@ -451,7 +450,11 @@ fn do_tx_transfers<T: Client>(
fn verify_funding_transfer<T: Client>(client: &T, tx: &Transaction, amount: u64) -> bool { fn verify_funding_transfer<T: Client>(client: &T, tx: &Transaction, amount: u64) -> bool {
for a in &tx.message().account_keys[1..] { for a in &tx.message().account_keys[1..] {
if client.get_balance(a).unwrap_or(0) >= amount { if client
.get_balance_with_commitment(a, CommitmentConfig::recent())
.unwrap_or(0)
>= amount
{
return true; return true;
} }
} }
@ -666,7 +669,9 @@ pub fn airdrop_lamports<T: Client>(
} }
}; };
let current_balance = client.get_balance(&id.pubkey()).unwrap_or_else(|e| { let current_balance = client
.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent())
.unwrap_or_else(|e| {
info!("airdrop error {}", e); info!("airdrop error {}", e);
starting_balance starting_balance
}); });
@ -815,7 +820,11 @@ fn fund_move_keys<T: Client>(
let create_len = 8; let create_len = 8;
let mut funding_time = Measure::start("funding_time"); let mut funding_time = Measure::start("funding_time");
for (i, keys) in keypairs.chunks(create_len).enumerate() { for (i, keys) in keypairs.chunks(create_len).enumerate() {
if client.get_balance(&keys[0].pubkey()).unwrap_or(0) > 0 { if client
.get_balance_with_commitment(&keys[0].pubkey(), CommitmentConfig::recent())
.unwrap_or(0)
> 0
{
// already created these accounts. // already created these accounts.
break; break;
} }
@ -853,7 +862,9 @@ fn fund_move_keys<T: Client>(
client.send_message(&[funding_key], tx.message).unwrap(); client.send_message(&[funding_key], tx.message).unwrap();
let mut balance = 0; let mut balance = 0;
for _ in 0..20 { for _ in 0..20 {
if let Ok(balance_) = client.get_balance(&funding_keys[0].pubkey()) { if let Ok(balance_) = client
.get_balance_with_commitment(&funding_keys[0].pubkey(), CommitmentConfig::recent())
{
if balance_ > 0 { if balance_ > 0 {
balance = balance_; balance = balance_;
break; break;
@ -1078,7 +1089,12 @@ mod tests {
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap(); generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap();
for kp in &keypairs { for kp in &keypairs {
assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports); assert_eq!(
client
.get_balance_with_commitment(&kp.pubkey(), CommitmentConfig::recent())
.unwrap(),
lamports
);
} }
} }
@ -1096,7 +1112,7 @@ mod tests {
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap(); generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap();
let max_fee = client let max_fee = client
.get_recent_blockhash() .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap() .unwrap()
.1 .1
.max_lamports_per_signature; .max_lamports_per_signature;

View File

@ -78,6 +78,24 @@ Requests can be sent in batches by sending an array of JSON-RPC request objects
* Signature: An Ed25519 signature of a chunk of data. * Signature: An Ed25519 signature of a chunk of data.
* Transaction: A Solana instruction signed by a client key-pair. * Transaction: A Solana instruction signed by a client key-pair.
## Configuring State Commitment
Solana nodes choose which bank state to query based on a commitment requirement
set by the client. Clients may specify either:
* `{"commitment":"max"}` - the node will query the most recent bank having reached `MAX_LOCKOUT_HISTORY` confirmations
* `{"commitment":"recent"}` - the node will query its most recent bank state
The commitment parameter should be included as the last element in the `params` array:
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",{"commitment":"max"}]}' 192.168.1.88:8899
```
#### Default:
If commitment configuration is not provided, the node will default to `"commitment":"max"`
Only methods that query bank state accept the commitment parameter. They are indicated in the API Reference below.
## JSON RPC API Reference ## JSON RPC API Reference
### confirmTransaction ### confirmTransaction
@ -91,6 +109,7 @@ Returns a transaction receipt
#### Results: #### Results:
* `boolean` - Transaction status, true if Transaction is confirmed * `boolean` - Transaction status, true if Transaction is confirmed
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Example: #### Example:
@ -109,6 +128,7 @@ Returns all information associated with the account of provided Pubkey
#### Parameters: #### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string * `string` - Pubkey of account to query, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -136,6 +156,7 @@ Returns the balance of the account of provided Pubkey
#### Parameters: #### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string * `string` - Pubkey of account to query, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -212,7 +233,7 @@ Returns information about the current epoch
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -288,7 +309,7 @@ Returns the leader schedule for the current epoch
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -311,6 +332,7 @@ Returns minimum balance required to make account rent exempt.
#### Parameters: #### Parameters:
* `integer` - account data length, as unsigned integer * `integer` - account data length, as unsigned integer
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -333,6 +355,7 @@ Returns the current number of blocks since signature has been confirmed.
#### Parameters: #### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string * `string` - Signature of Transaction to confirm, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -355,6 +378,7 @@ Returns all accounts owned by the provided program Pubkey
#### Parameters: #### Parameters:
* `string` - Pubkey of program, as base-58 encoded string * `string` - Pubkey of program, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -382,7 +406,7 @@ Returns a recent block hash from the ledger, and a fee schedule that can be used
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -408,6 +432,7 @@ Returns the status of a given signature. This method is similar to [confirmTrans
#### Parameters: #### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string * `string` - Signature of Transaction to confirm, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -432,7 +457,7 @@ Returns the current slot the node is processing
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -454,7 +479,7 @@ Returns the current slot leader
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -476,7 +501,7 @@ Returns the current storage segment size in terms of slots
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -542,7 +567,7 @@ Returns the current Transaction count from the ledger
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -569,6 +594,7 @@ None
#### Results: #### Results:
* `integer` - Total supply, as unsigned 64-bit integer * `integer` - Total supply, as unsigned 64-bit integer
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Example: #### Example:
@ -609,7 +635,7 @@ Returns the account info and associated stake for all the voting accounts in the
#### Parameters: #### Parameters:
None * `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results: #### Results:
@ -640,6 +666,7 @@ Requests an airdrop of lamports to a Pubkey
* `string` - Pubkey of account to receive lamports, as base-58 encoded string * `string` - Pubkey of account to receive lamports, as base-58 encoded string
* `integer` - lamports, as a signed 64-bit integer * `integer` - lamports, as a signed 64-bit integer
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) (used for retrieving blockhash and verifying airdrop success)
#### Results: #### Results:

View File

@ -364,7 +364,7 @@ while [[ $iteration -le $iterations ]]; do
echo "--- Wallet sanity ($iteration)" echo "--- Wallet sanity ($iteration)"
( (
set -x set -x
timeout 60s scripts/wallet-sanity.sh --url http://127.0.0.1"$walletRpcPort" timeout 90s scripts/wallet-sanity.sh --url http://127.0.0.1"$walletRpcPort"
) || flag_error ) || flag_error
iteration=$((iteration + 1)) iteration=$((iteration + 1))

View File

@ -11,6 +11,7 @@ use serde_json::Value;
use solana_client::{rpc_client::RpcClient, rpc_request::RpcVoteAccountInfo}; use solana_client::{rpc_client::RpcClient, rpc_request::RpcVoteAccountInfo};
use solana_sdk::{ use solana_sdk::{
clock, clock,
commitment_config::CommitmentConfig,
hash::Hash, hash::Hash,
signature::{Keypair, KeypairUtil}, signature::{Keypair, KeypairUtil},
system_transaction, system_transaction,
@ -72,7 +73,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.long("timeout") .long("timeout")
.value_name("SECONDS") .value_name("SECONDS")
.takes_value(true) .takes_value(true)
.default_value("10") .default_value("15")
.help("Wait up to timeout seconds for transaction confirmation"), .help("Wait up to timeout seconds for transaction confirmation"),
), ),
) )
@ -221,7 +222,10 @@ pub fn process_ping(
Ok(signature) => { Ok(signature) => {
let transaction_sent = Instant::now(); let transaction_sent = Instant::now();
loop { loop {
let signature_status = rpc_client.get_signature_status(&signature)?; let signature_status = rpc_client.get_signature_status_with_commitment(
&signature,
CommitmentConfig::recent(),
)?;
let elapsed_time = Instant::now().duration_since(transaction_sent); let elapsed_time = Instant::now().duration_since(transaction_sent);
if let Some(transaction_status) = signature_status { if let Some(transaction_status) = signature_status {
match transaction_status { match transaction_status {

View File

@ -11,11 +11,14 @@ use serde_derive::{Deserialize, Serialize};
use serde_json::{Map, Value}; use serde_json::{Map, Value};
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_config_api::{config_instruction, get_config_data, ConfigKeys, ConfigState}; use solana_config_api::{config_instruction, get_config_data, ConfigKeys, ConfigState};
use solana_sdk::account::Account; use solana_sdk::{
use solana_sdk::message::Message; account::Account,
use solana_sdk::pubkey::Pubkey; commitment_config::CommitmentConfig,
use solana_sdk::signature::{Keypair, KeypairUtil}; message::Message,
use solana_sdk::transaction::Transaction; pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
transaction::Transaction,
};
use std::error; use std::error;
pub const MAX_SHORT_FIELD_LENGTH: usize = 70; pub const MAX_SHORT_FIELD_LENGTH: usize = 70;
@ -297,7 +300,9 @@ pub fn process_set_validator_info(
}; };
// Check existence of validator-info account // Check existence of validator-info account
let balance = rpc_client.poll_get_balance(&info_pubkey).unwrap_or(0); let balance = rpc_client
.poll_get_balance_with_commitment(&info_pubkey, CommitmentConfig::default())
.unwrap_or(0);
let keys = vec![(id(), false), (config.keypair.pubkey(), true)]; let keys = vec![(id(), false), (config.keypair.pubkey(), true)];
let (message, signers): (Message, Vec<&Keypair>) = if balance == 0 { let (message, signers): (Message, Vec<&Keypair>) = if balance == 0 {

View File

@ -1,14 +1,16 @@
use serde_json::{json, Value}; use serde_json::Value;
use solana_cli::cli::{process_command, CliCommand, CliConfig}; use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient; use solana_client::rpc_client::RpcClient;
use solana_client::rpc_request::RpcRequest;
use solana_core::validator::new_validator_for_tests; use solana_core::validator::new_validator_for_tests;
use solana_drone::drone::run_local_drone; use solana_drone::drone::run_local_drone;
use solana_sdk::bpf_loader; use solana_sdk::{bpf_loader, commitment_config::CommitmentConfig, pubkey::Pubkey};
use std::fs::{remove_dir_all, File}; use std::{
use std::io::Read; fs::{remove_dir_all, File},
use std::path::PathBuf; io::Read,
use std::sync::mpsc::channel; path::PathBuf,
str::FromStr,
sync::mpsc::channel,
};
#[test] #[test]
fn test_cli_deploy_program() { fn test_cli_deploy_program() {
@ -56,35 +58,20 @@ fn test_cli_deploy_program() {
.unwrap() .unwrap()
.as_str() .as_str()
.unwrap(); .unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let params = json!([program_id_str]); let account = rpc_client
let account_info = rpc_client .get_account_with_commitment(&program_id, CommitmentConfig::recent())
.retry_make_rpc_request(&RpcRequest::GetAccountInfo, Some(params), 0)
.unwrap(); .unwrap();
let account_info_obj = account_info.as_object().unwrap(); assert_eq!(account.lamports, minimum_balance_for_rent_exemption);
assert_eq!( assert_eq!(account.owner, bpf_loader::id());
account_info_obj.get("lamports").unwrap().as_u64().unwrap(), assert_eq!(account.executable, true);
minimum_balance_for_rent_exemption
);
let owner_array = account_info.get("owner").unwrap();
assert_eq!(owner_array, &json!(bpf_loader::id()));
assert_eq!(
account_info_obj
.get("executable")
.unwrap()
.as_bool()
.unwrap(),
true
);
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap(); let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
let mut elf = Vec::new(); let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap(); file.read_to_end(&mut elf).unwrap();
assert_eq!( assert_eq!(account.data, elf);
account_info_obj.get("data").unwrap().as_array().unwrap(),
&elf
);
server.close().unwrap(); server.close().unwrap();
remove_dir_all(ledger_path).unwrap(); remove_dir_all(ledger_path).unwrap();

View File

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

View File

@ -1,9 +1,13 @@
use crate::client_error::ClientError; use crate::{
use crate::generic_rpc_client_request::GenericRpcClientRequest; client_error::ClientError, generic_rpc_client_request::GenericRpcClientRequest,
use crate::rpc_request::RpcRequest; rpc_request::RpcRequest,
};
use serde_json::{Number, Value}; use serde_json::{Number, Value};
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::{
use solana_sdk::transaction::{self, TransactionError}; commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
transaction::{self, TransactionError},
};
pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8"; pub const PUBKEY: &str = "7RoSF9fUmdphVCpabEoefH81WwrW7orsWonXWqTXkKV8";
pub const SIGNATURE: &str = pub const SIGNATURE: &str =
@ -25,6 +29,7 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
request: &RpcRequest, request: &RpcRequest,
params: Option<serde_json::Value>, params: Option<serde_json::Value>,
_retries: usize, _retries: usize,
_commitment_config: Option<CommitmentConfig>,
) -> Result<serde_json::Value, ClientError> { ) -> Result<serde_json::Value, ClientError> {
if self.url == "fails" { if self.url == "fails" {
return Ok(Value::Null); return Ok(Value::Null);

View File

@ -1,10 +1,13 @@
use log::*; use log::*;
use solana_sdk::client::Client; use solana_sdk::{client::Client, commitment_config::CommitmentConfig, timing::duration_as_s};
use solana_sdk::timing::duration_as_s; use std::{
use std::sync::atomic::{AtomicBool, Ordering}; sync::{
use std::sync::{Arc, RwLock}; atomic::{AtomicBool, Ordering},
use std::thread::sleep; Arc, RwLock,
use std::time::{Duration, Instant}; },
thread::sleep,
time::{Duration, Instant},
};
#[derive(Default)] #[derive(Default)]
pub struct SampleStats { pub struct SampleStats {
@ -29,7 +32,9 @@ pub fn sample_txs<T>(
let mut total_txs; let mut total_txs;
let mut now = Instant::now(); let mut now = Instant::now();
let start_time = now; let start_time = now;
let initial_txs = client.get_transaction_count().expect("transaction count"); let initial_txs = client
.get_transaction_count_with_commitment(CommitmentConfig::recent())
.expect("transaction count");
let mut last_txs = initial_txs; let mut last_txs = initial_txs;
loop { loop {
@ -37,7 +42,7 @@ pub fn sample_txs<T>(
let elapsed = now.elapsed(); let elapsed = now.elapsed();
now = Instant::now(); now = Instant::now();
let mut txs; let mut txs;
match client.get_transaction_count() { match client.get_transaction_count_with_commitment(CommitmentConfig::recent()) {
Err(e) => { Err(e) => {
// ThinClient with multiple options should pick a better one now. // ThinClient with multiple options should pick a better one now.
info!("Couldn't get transaction count {:?}", e); info!("Couldn't get transaction count {:?}", e);

View File

@ -1,14 +1,17 @@
use crate::client_error::ClientError; use crate::{
use crate::generic_rpc_client_request::GenericRpcClientRequest; client_error::ClientError,
use crate::mock_rpc_client_request::MockRpcClientRequest; generic_rpc_client_request::GenericRpcClientRequest,
use crate::rpc_client_request::RpcClientRequest; mock_rpc_client_request::MockRpcClientRequest,
use crate::rpc_request::{RpcEpochInfo, RpcRequest, RpcVoteAccountStatus}; rpc_client_request::RpcClientRequest,
rpc_request::{RpcEpochInfo, RpcRequest, RpcVoteAccountStatus},
};
use bincode::serialize; use bincode::serialize;
use log::*; use log::*;
use serde_json::{json, Value}; use serde_json::{json, Value};
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}, clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
commitment_config::CommitmentConfig,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
@ -54,10 +57,10 @@ impl RpcClient {
pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> { pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> {
let serialized = serialize(transaction).unwrap(); let serialized = serialize(transaction).unwrap();
let params = json!([serialized]); let params = json!(serialized);
let signature = self let signature = self
.client .client
.send(&RpcRequest::SendTransaction, Some(params), 5)?; .send(&RpcRequest::SendTransaction, Some(params), 5, None)?;
if signature.as_str().is_none() { if signature.as_str().is_none() {
Err(io::Error::new( Err(io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -73,19 +76,37 @@ impl RpcClient {
&self, &self,
signature: &str, signature: &str,
) -> Result<Option<transaction::Result<()>>, ClientError> { ) -> Result<Option<transaction::Result<()>>, ClientError> {
let params = json!([signature.to_string()]); self.get_signature_status_with_commitment(signature, CommitmentConfig::default())
let signature_status = }
self.client
.send(&RpcRequest::GetSignatureStatus, Some(params), 5)?; pub fn get_signature_status_with_commitment(
&self,
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),
5,
commitment_config.ok(),
)?;
let result: Option<transaction::Result<()>> = let result: Option<transaction::Result<()>> =
serde_json::from_value(signature_status).unwrap(); serde_json::from_value(signature_status).unwrap();
Ok(result) Ok(result)
} }
pub fn get_slot(&self) -> io::Result<Slot> { pub fn get_slot(&self) -> io::Result<Slot> {
self.get_slot_with_commitment(CommitmentConfig::default())
}
pub fn get_slot_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> io::Result<Slot> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetSlot, None, 0) .send(&RpcRequest::GetSlot, None, 0, commitment_config.ok())
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -104,7 +125,7 @@ impl RpcClient {
pub fn get_vote_accounts(&self) -> io::Result<RpcVoteAccountStatus> { pub fn get_vote_accounts(&self) -> io::Result<RpcVoteAccountStatus> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetVoteAccounts, None, 0) .send(&RpcRequest::GetVoteAccounts, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -123,7 +144,7 @@ impl RpcClient {
pub fn get_epoch_info(&self) -> io::Result<RpcEpochInfo> { pub fn get_epoch_info(&self) -> io::Result<RpcEpochInfo> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetEpochInfo, None, 0) .send(&RpcRequest::GetEpochInfo, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -142,7 +163,7 @@ impl RpcClient {
pub fn get_epoch_schedule(&self) -> io::Result<EpochSchedule> { pub fn get_epoch_schedule(&self) -> io::Result<EpochSchedule> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetEpochSchedule, None, 0) .send(&RpcRequest::GetEpochSchedule, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -161,7 +182,7 @@ impl RpcClient {
pub fn get_inflation(&self) -> io::Result<Inflation> { pub fn get_inflation(&self) -> io::Result<Inflation> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetInflation, None, 0) .send(&RpcRequest::GetInflation, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -180,7 +201,7 @@ impl RpcClient {
pub fn get_version(&self) -> io::Result<String> { pub fn get_version(&self) -> io::Result<String> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetVersion, None, 0) .send(&RpcRequest::GetVersion, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -203,7 +224,7 @@ impl RpcClient {
) -> Result<String, ClientError> { ) -> Result<String, ClientError> {
let mut send_retries = 20; let mut send_retries = 20;
loop { loop {
let mut status_retries = 4; let mut status_retries = 15;
let signature_str = self.send_transaction(transaction)?; let signature_str = self.send_transaction(transaction)?;
let status = loop { let status = loop {
let status = self.get_signature_status(&signature_str)?; let status = self.get_signature_status(&signature_str)?;
@ -216,10 +237,8 @@ impl RpcClient {
break status; break status;
} }
if cfg!(not(test)) { if cfg!(not(test)) {
// Retry ~twice during a slot // Retry twice a second
sleep(Duration::from_millis( sleep(Duration::from_millis(500));
500 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND,
));
} }
}; };
send_retries = if let Some(result) = status.clone() { send_retries = if let Some(result) = status.clone() {
@ -252,7 +271,7 @@ impl RpcClient {
) -> Result<(), Box<dyn error::Error>> { ) -> Result<(), Box<dyn error::Error>> {
let mut send_retries = 5; let mut send_retries = 5;
loop { loop {
let mut status_retries = 4; let mut status_retries = 15;
// Send all transactions // Send all transactions
let mut transactions_signatures = vec![]; let mut transactions_signatures = vec![];
@ -273,10 +292,8 @@ impl RpcClient {
status_retries -= 1; status_retries -= 1;
if cfg!(not(test)) { if cfg!(not(test)) {
// Retry ~twice during a slot // Retry twice a second
sleep(Duration::from_millis( sleep(Duration::from_millis(500));
500 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND,
));
} }
transactions_signatures = transactions_signatures transactions_signatures = transactions_signatures
@ -333,19 +350,30 @@ impl RpcClient {
pubkey: &Pubkey, pubkey: &Pubkey,
retries: usize, retries: usize,
) -> Result<Option<u64>, Box<dyn error::Error>> { ) -> Result<Option<u64>, Box<dyn error::Error>> {
let params = json!([format!("{}", pubkey)]); let params = json!(format!("{}", pubkey));
let res = self let res = self
.client .client
.send(&RpcRequest::GetBalance, Some(params), retries)? .send(&RpcRequest::GetBalance, Some(params), retries, None)?
.as_u64(); .as_u64();
Ok(res) Ok(res)
} }
pub fn get_account(&self, pubkey: &Pubkey) -> io::Result<Account> { pub fn get_account(&self, pubkey: &Pubkey) -> io::Result<Account> {
let params = json!([format!("{}", pubkey)]); self.get_account_with_commitment(pubkey, CommitmentConfig::default())
let response = self }
.client
.send(&RpcRequest::GetAccountInfo, Some(params), 0); pub fn get_account_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> io::Result<Account> {
let params = json!(format!("{}", pubkey));
let response = self.client.send(
&RpcRequest::GetAccountInfo,
Some(params),
0,
commitment_config.ok(),
);
response response
.and_then(|account_json| { .and_then(|account_json| {
@ -366,13 +394,14 @@ impl RpcClient {
} }
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> { pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> io::Result<u64> {
let params = json!([data_len]); let params = json!(data_len);
let minimum_balance_json = self let minimum_balance_json = self
.client .client
.send( .send(
&RpcRequest::GetMinimumBalanceForRentExemption, &RpcRequest::GetMinimumBalanceForRentExemption,
Some(params), Some(params),
0, 0,
None,
) )
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
@ -398,18 +427,25 @@ impl RpcClient {
Ok(minimum_balance) Ok(minimum_balance)
} }
/// Request the balance of the user holding `pubkey`. This method blocks /// Request the balance of the account `pubkey`.
/// until the server sends a response. If the response packet is dropped
/// by the network, this method will hang indefinitely.
pub fn get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> { pub fn get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> {
self.get_account(pubkey).map(|account| account.lamports) self.get_balance_with_commitment(pubkey, CommitmentConfig::default())
}
pub fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> io::Result<u64> {
self.get_account_with_commitment(pubkey, commitment_config)
.map(|account| account.lamports)
} }
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> io::Result<Vec<(Pubkey, Account)>> { pub fn get_program_accounts(&self, pubkey: &Pubkey) -> io::Result<Vec<(Pubkey, Account)>> {
let params = json!([format!("{}", pubkey)]); let params = json!(format!("{}", pubkey));
let response = self let response = self
.client .client
.send(&RpcRequest::GetProgramAccounts, Some(params), 0) .send(&RpcRequest::GetProgramAccounts, Some(params), 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -438,12 +474,23 @@ impl RpcClient {
Ok(pubkey_accounts) Ok(pubkey_accounts)
} }
/// Request the transaction count. If the response packet is dropped by the network, /// Request the transaction count.
/// this method will try again 5 times.
pub fn get_transaction_count(&self) -> io::Result<u64> { pub fn get_transaction_count(&self) -> io::Result<u64> {
self.get_transaction_count_with_commitment(CommitmentConfig::default())
}
pub fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> io::Result<u64> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetTransactionCount, None, 0) .send(
&RpcRequest::GetTransactionCount,
None,
0,
commitment_config.ok(),
)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -460,9 +507,21 @@ impl RpcClient {
} }
pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> { pub fn get_recent_blockhash(&self) -> io::Result<(Hash, FeeCalculator)> {
self.get_recent_blockhash_with_commitment(CommitmentConfig::default())
}
pub fn get_recent_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> io::Result<(Hash, FeeCalculator)> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetRecentBlockhash, None, 0) .send(
&RpcRequest::GetRecentBlockhash,
None,
0,
commitment_config.ok(),
)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -518,7 +577,7 @@ impl RpcClient {
pub fn get_genesis_blockhash(&self) -> io::Result<Hash> { pub fn get_genesis_blockhash(&self) -> io::Result<Hash> {
let response = self let response = self
.client .client
.send(&RpcRequest::GetGenesisBlockhash, None, 0) .send(&RpcRequest::GetGenesisBlockhash, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -542,15 +601,16 @@ impl RpcClient {
Ok(blockhash) Ok(blockhash)
} }
pub fn poll_balance_with_timeout( pub fn poll_balance_with_timeout_and_commitment(
&self, &self,
pubkey: &Pubkey, pubkey: &Pubkey,
polling_frequency: &Duration, polling_frequency: &Duration,
timeout: &Duration, timeout: &Duration,
commitment_config: CommitmentConfig,
) -> io::Result<u64> { ) -> io::Result<u64> {
let now = Instant::now(); let now = Instant::now();
loop { loop {
match self.get_balance(&pubkey) { match self.get_balance_with_commitment(&pubkey, commitment_config.clone()) {
Ok(bal) => { Ok(bal) => {
return Ok(bal); return Ok(bal);
} }
@ -564,14 +624,29 @@ impl RpcClient {
} }
} }
pub fn poll_get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> { pub fn poll_get_balance_with_commitment(
self.poll_balance_with_timeout(pubkey, &Duration::from_millis(100), &Duration::from_secs(1)) &self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> io::Result<u64> {
self.poll_balance_with_timeout_and_commitment(
pubkey,
&Duration::from_millis(100),
&Duration::from_secs(1),
commitment_config,
)
} }
pub fn wait_for_balance(&self, pubkey: &Pubkey, expected_balance: Option<u64>) -> Option<u64> { pub fn wait_for_balance_with_commitment(
&self,
pubkey: &Pubkey,
expected_balance: Option<u64>,
commitment_config: CommitmentConfig,
) -> Option<u64> {
const LAST: usize = 30; const LAST: usize = 30;
for run in 0..LAST { for run in 0..LAST {
let balance_result = self.poll_get_balance(pubkey); let balance_result =
self.poll_get_balance_with_commitment(pubkey, commitment_config.clone());
if expected_balance.is_none() { if expected_balance.is_none() {
return balance_result.ok(); return balance_result.ok();
} }
@ -593,8 +668,23 @@ impl RpcClient {
/// Poll the server to confirm a transaction. /// Poll the server to confirm a transaction.
pub fn poll_for_signature(&self, signature: &Signature) -> io::Result<()> { pub fn poll_for_signature(&self, signature: &Signature) -> io::Result<()> {
self.poll_for_signature_with_commitment(signature, CommitmentConfig::default())
}
/// Poll the server to confirm a transaction.
pub fn poll_for_signature_with_commitment(
&self,
signature: &Signature,
commitment_config: CommitmentConfig,
) -> io::Result<()> {
let now = Instant::now(); let now = Instant::now();
while !self.check_signature(signature) { loop {
if let Ok(Some(_)) = self.get_signature_status_with_commitment(
&signature.to_string(),
commitment_config.clone(),
) {
break;
}
if now.elapsed().as_secs() > 15 { if now.elapsed().as_secs() > 15 {
// TODO: Return a better error. // TODO: Return a better error.
return Err(io::Error::new(io::ErrorKind::Other, "signature not found")); return Err(io::Error::new(io::ErrorKind::Other, "signature not found"));
@ -607,12 +697,15 @@ impl RpcClient {
/// Check a signature in the bank. /// Check a signature in the bank.
pub fn check_signature(&self, signature: &Signature) -> bool { pub fn check_signature(&self, signature: &Signature) -> bool {
trace!("check_signature: {:?}", signature); trace!("check_signature: {:?}", signature);
let params = json!([format!("{}", signature)]); let params = json!(format!("{}", signature));
for _ in 0..30 { for _ in 0..30 {
let response = let response = self.client.send(
self.client &RpcRequest::ConfirmTransaction,
.send(&RpcRequest::ConfirmTransaction, Some(params.clone()), 0); Some(params.clone()),
0,
Some(CommitmentConfig::recent()),
);
match response { match response {
Ok(confirmation) => { Ok(confirmation) => {
@ -666,7 +759,7 @@ impl RpcClient {
debug!("check_confirmations request failed: {:?}", err); debug!("check_confirmations request failed: {:?}", err);
} }
}; };
if now.elapsed().as_secs() > 15 { if now.elapsed().as_secs() > 20 {
info!( info!(
"signature {} confirmed {} out of {} failed after {} ms", "signature {} confirmed {} out of {} failed after {} ms",
signature, signature,
@ -690,13 +783,14 @@ impl RpcClient {
&self, &self,
sig: &Signature, sig: &Signature,
) -> io::Result<usize> { ) -> io::Result<usize> {
let params = json!([format!("{}", sig)]); let params = json!(format!("{}", sig));
let response = self let response = self
.client .client
.send( .send(
&RpcRequest::GetNumBlocksSinceSignatureConfirmation, &RpcRequest::GetNumBlocksSinceSignatureConfirmation,
Some(params.clone()), Some(params.clone()),
1, 1,
CommitmentConfig::recent().ok(),
) )
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
@ -721,7 +815,7 @@ impl RpcClient {
pub fn validator_exit(&self) -> io::Result<bool> { pub fn validator_exit(&self) -> io::Result<bool> {
let response = self let response = self
.client .client
.send(&RpcRequest::ValidatorExit, None, 0) .send(&RpcRequest::ValidatorExit, None, 0, None)
.map_err(|err| { .map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
@ -742,8 +836,9 @@ impl RpcClient {
request: &RpcRequest, request: &RpcRequest,
params: Option<Value>, params: Option<Value>,
retries: usize, retries: usize,
commitment: Option<CommitmentConfig>,
) -> Result<Value, ClientError> { ) -> Result<Value, ClientError> {
self.client.send(request, params, retries) self.client.send(request, params, retries, commitment)
} }
} }
@ -763,11 +858,12 @@ mod tests {
use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder}; use jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder};
use serde_json::Number; use serde_json::Number;
use solana_logger; use solana_logger;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::{
use solana_sdk::system_transaction; signature::{Keypair, KeypairUtil},
use solana_sdk::transaction::TransactionError; system_transaction,
use std::sync::mpsc::channel; transaction::TransactionError,
use std::thread; };
use std::{sync::mpsc::channel, thread};
#[test] #[test]
fn test_make_rpc_request() { fn test_make_rpc_request() {
@ -808,10 +904,12 @@ mod tests {
&RpcRequest::GetBalance, &RpcRequest::GetBalance,
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])), Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
0, 0,
None,
); );
assert_eq!(balance.unwrap().as_u64().unwrap(), 50); assert_eq!(balance.unwrap().as_u64().unwrap(), 50);
let blockhash = rpc_client.retry_make_rpc_request(&RpcRequest::GetRecentBlockhash, None, 0); let blockhash =
rpc_client.retry_make_rpc_request(&RpcRequest::GetRecentBlockhash, None, 0, None);
assert_eq!( assert_eq!(
blockhash.unwrap().as_str().unwrap(), blockhash.unwrap().as_str().unwrap(),
"deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx" "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"
@ -822,6 +920,7 @@ mod tests {
&RpcRequest::GetRecentBlockhash, &RpcRequest::GetRecentBlockhash,
Some(json!("parameter")), Some(json!("parameter")),
0, 0,
None,
); );
assert_eq!(blockhash.is_err(), true); assert_eq!(blockhash.is_err(), true);
} }
@ -860,6 +959,7 @@ mod tests {
&RpcRequest::GetBalance, &RpcRequest::GetBalance,
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"])), Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"])),
10, 10,
None,
); );
assert_eq!(balance.unwrap().as_u64().unwrap(), 5); assert_eq!(balance.unwrap().as_u64().unwrap(), 5);
} }

View File

@ -1,11 +1,15 @@
use crate::client_error::ClientError; use crate::{
use crate::generic_rpc_client_request::GenericRpcClientRequest; client_error::ClientError,
use crate::rpc_request::{RpcError, RpcRequest}; generic_rpc_client_request::GenericRpcClientRequest,
rpc_request::{RpcError, RpcRequest},
};
use log::*; use log::*;
use reqwest::{self, header::CONTENT_TYPE}; use reqwest::{self, header::CONTENT_TYPE};
use solana_sdk::clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT}; use solana_sdk::{
use std::thread::sleep; clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT},
use std::time::Duration; commitment_config::CommitmentConfig,
};
use std::{thread::sleep, time::Duration};
pub struct RpcClientRequest { pub struct RpcClientRequest {
client: reqwest::Client, client: reqwest::Client,
@ -36,11 +40,12 @@ impl GenericRpcClientRequest for RpcClientRequest {
request: &RpcRequest, request: &RpcRequest,
params: Option<serde_json::Value>, params: Option<serde_json::Value>,
mut retries: usize, mut retries: usize,
commitment_config: Option<CommitmentConfig>,
) -> Result<serde_json::Value, ClientError> { ) -> Result<serde_json::Value, ClientError> {
// Concurrent requests are not supported so reuse the same request id for all requests // Concurrent requests are not supported so reuse the same request id for all requests
let request_id = 1; let request_id = 1;
let request_json = request.build_request_json(request_id, params); let request_json = request.build_request_json(request_id, params, commitment_config);
loop { loop {
match self match self

View File

@ -1,5 +1,8 @@
use serde_json::{json, Value}; use serde_json::{json, Value};
use solana_sdk::clock::{Epoch, Slot}; use solana_sdk::{
clock::{Epoch, Slot},
commitment_config::CommitmentConfig,
};
use std::{error, fmt}; use std::{error, fmt};
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
@ -83,7 +86,12 @@ pub enum RpcRequest {
} }
impl RpcRequest { impl RpcRequest {
pub(crate) fn build_request_json(&self, id: u64, params: Option<Value>) -> Value { pub(crate) fn build_request_json(
&self,
id: u64,
params: Option<Value>,
commitment_config: Option<CommitmentConfig>,
) -> Value {
let jsonrpc = "2.0"; let jsonrpc = "2.0";
let method = match self { let method = match self {
RpcRequest::ConfirmTransaction => "confirmTransaction", RpcRequest::ConfirmTransaction => "confirmTransaction",
@ -123,7 +131,13 @@ impl RpcRequest {
"method": method, "method": method,
}); });
if let Some(param_string) = params { if let Some(param_string) = params {
request["params"] = param_string; 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 request
} }
@ -154,45 +168,65 @@ impl error::Error for RpcError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_sdk::commitment_config::CommitmentLevel;
#[test] #[test]
fn test_build_request_json() { fn test_build_request_json() {
let test_request = RpcRequest::GetAccountInfo; let test_request = RpcRequest::GetAccountInfo;
let addr = json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]); let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
let request = test_request.build_request_json(1, Some(addr.clone())); let request = test_request.build_request_json(1, Some(addr.clone()), None);
assert_eq!(request["method"], "getAccountInfo"); assert_eq!(request["method"], "getAccountInfo");
assert_eq!(request["params"], addr,); assert_eq!(request["params"], json!([addr]));
let test_request = RpcRequest::GetBalance; let test_request = RpcRequest::GetBalance;
let request = test_request.build_request_json(1, Some(addr)); let request = test_request.build_request_json(1, Some(addr), None);
assert_eq!(request["method"], "getBalance"); assert_eq!(request["method"], "getBalance");
let test_request = RpcRequest::GetEpochInfo; let test_request = RpcRequest::GetEpochInfo;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "getEpochInfo"); assert_eq!(request["method"], "getEpochInfo");
let test_request = RpcRequest::GetInflation; let test_request = RpcRequest::GetInflation;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "getInflation"); assert_eq!(request["method"], "getInflation");
let test_request = RpcRequest::GetRecentBlockhash; let test_request = RpcRequest::GetRecentBlockhash;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "getRecentBlockhash"); assert_eq!(request["method"], "getRecentBlockhash");
let test_request = RpcRequest::GetSlot; let test_request = RpcRequest::GetSlot;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "getSlot"); assert_eq!(request["method"], "getSlot");
let test_request = RpcRequest::GetTransactionCount; let test_request = RpcRequest::GetTransactionCount;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "getTransactionCount"); assert_eq!(request["method"], "getTransactionCount");
let test_request = RpcRequest::RequestAirdrop; let test_request = RpcRequest::RequestAirdrop;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "requestAirdrop"); assert_eq!(request["method"], "requestAirdrop");
let test_request = RpcRequest::SendTransaction; let test_request = RpcRequest::SendTransaction;
let request = test_request.build_request_json(1, None); let request = test_request.build_request_json(1, None, None);
assert_eq!(request["method"], "sendTransaction"); assert_eq!(request["method"], "sendTransaction");
} }
#[test]
fn test_build_request_json_config_options() {
let commitment_config = CommitmentConfig {
commitment: CommitmentLevel::Max,
};
let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
// 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()));
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()));
assert_eq!(request["params"], json!([addr, commitment_config]));
}
} }

View File

@ -6,25 +6,32 @@
use crate::rpc_client::RpcClient; use crate::rpc_client::RpcClient;
use bincode::{serialize_into, serialized_size}; use bincode::{serialize_into, serialized_size};
use log::*; use log::*;
use solana_sdk::account::Account; use solana_sdk::{
use solana_sdk::client::{AsyncClient, Client, SyncClient}; account::Account,
use solana_sdk::clock::MAX_PROCESSING_AGE; client::{AsyncClient, Client, SyncClient},
use solana_sdk::fee_calculator::FeeCalculator; clock::MAX_PROCESSING_AGE,
use solana_sdk::hash::Hash; commitment_config::CommitmentConfig,
use solana_sdk::instruction::Instruction; fee_calculator::FeeCalculator,
use solana_sdk::message::Message; hash::Hash,
use solana_sdk::packet::PACKET_DATA_SIZE; instruction::Instruction,
use solana_sdk::pubkey::Pubkey; message::Message,
use solana_sdk::signature::{Keypair, KeypairUtil, Signature}; packet::PACKET_DATA_SIZE,
use solana_sdk::system_instruction; pubkey::Pubkey,
use solana_sdk::timing::duration_as_ms; signature::{Keypair, KeypairUtil, Signature},
use solana_sdk::transaction::{self, Transaction}; system_instruction,
use solana_sdk::transport::Result as TransportResult; timing::duration_as_ms,
use std::io; transaction::{self, Transaction},
use std::net::{SocketAddr, UdpSocket}; transport::Result as TransportResult,
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; };
use std::sync::RwLock; use std::{
use std::time::{Duration, Instant}; io,
net::{SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
RwLock,
},
time::{Duration, Instant},
};
struct ClientOptimizer { struct ClientOptimizer {
cur_index: AtomicUsize, cur_index: AtomicUsize,
@ -244,22 +251,78 @@ impl ThinClient {
)) ))
} }
pub fn poll_balance_with_timeout_and_commitment(
&self,
pubkey: &Pubkey,
polling_frequency: &Duration,
timeout: &Duration,
commitment_config: CommitmentConfig,
) -> io::Result<u64> {
self.rpc_client().poll_balance_with_timeout_and_commitment(
pubkey,
polling_frequency,
timeout,
commitment_config,
)
}
pub fn poll_balance_with_timeout( pub fn poll_balance_with_timeout(
&self, &self,
pubkey: &Pubkey, pubkey: &Pubkey,
polling_frequency: &Duration, polling_frequency: &Duration,
timeout: &Duration, timeout: &Duration,
) -> io::Result<u64> { ) -> io::Result<u64> {
self.rpc_client() self.rpc_client().poll_balance_with_timeout_and_commitment(
.poll_balance_with_timeout(pubkey, polling_frequency, timeout) pubkey,
polling_frequency,
timeout,
CommitmentConfig::default(),
)
} }
pub fn poll_get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> { pub fn poll_get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> {
self.rpc_client().poll_get_balance(pubkey) self.rpc_client()
.poll_get_balance_with_commitment(pubkey, CommitmentConfig::default())
}
pub fn poll_get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> io::Result<u64> {
self.rpc_client()
.poll_get_balance_with_commitment(pubkey, commitment_config)
} }
pub fn wait_for_balance(&self, pubkey: &Pubkey, expected_balance: Option<u64>) -> Option<u64> { pub fn wait_for_balance(&self, pubkey: &Pubkey, expected_balance: Option<u64>) -> Option<u64> {
self.rpc_client().wait_for_balance(pubkey, expected_balance) self.rpc_client().wait_for_balance_with_commitment(
pubkey,
expected_balance,
CommitmentConfig::default(),
)
}
pub fn wait_for_balance_with_commitment(
&self,
pubkey: &Pubkey,
expected_balance: Option<u64>,
commitment_config: CommitmentConfig,
) -> Option<u64> {
self.rpc_client().wait_for_balance_with_commitment(
pubkey,
expected_balance,
commitment_config,
)
}
pub fn poll_for_signature_with_commitment(
&self,
signature: &Signature,
commitment_config: CommitmentConfig,
) -> TransportResult<()> {
Ok(self
.rpc_client()
.poll_for_signature_with_commitment(signature, commitment_config)?)
} }
/// Check a signature in the bank. This method blocks /// Check a signature in the bank. This method blocks
@ -323,15 +386,45 @@ impl SyncClient for ThinClient {
Ok(self.rpc_client().get_account(pubkey).ok()) Ok(self.rpc_client().get_account(pubkey).ok())
} }
fn get_account_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> TransportResult<Option<Account>> {
Ok(self
.rpc_client()
.get_account_with_commitment(pubkey, commitment_config)
.ok())
}
fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> { fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
let balance = self.rpc_client().get_balance(pubkey)?; let balance = self.rpc_client().get_balance(pubkey)?;
Ok(balance) Ok(balance)
} }
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> TransportResult<u64> {
let balance = self
.rpc_client()
.get_balance_with_commitment(pubkey, commitment_config)?;
Ok(balance)
}
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> { fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
self.get_recent_blockhash_with_commitment(CommitmentConfig::default())
}
fn get_recent_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> TransportResult<(Hash, FeeCalculator)> {
let index = self.optimizer.experiment(); let index = self.optimizer.experiment();
let now = Instant::now(); let now = Instant::now();
let recent_blockhash = self.rpc_clients[index].get_recent_blockhash(); let recent_blockhash =
self.rpc_clients[index].get_recent_blockhash_with_commitment(commitment_config);
match recent_blockhash { match recent_blockhash {
Ok(recent_blockhash) => { Ok(recent_blockhash) => {
self.optimizer.report(index, duration_as_ms(&now.elapsed())); self.optimizer.report(index, duration_as_ms(&now.elapsed()));
@ -360,8 +453,35 @@ impl SyncClient for ThinClient {
Ok(status) Ok(status)
} }
fn get_signature_status_with_commitment(
&self,
signature: &Signature,
commitment_config: CommitmentConfig,
) -> TransportResult<Option<transaction::Result<()>>> {
let status = self
.rpc_client()
.get_signature_status_with_commitment(&signature.to_string(), commitment_config)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("send_transaction failed with error {:?}", err),
)
})?;
Ok(status)
}
fn get_slot(&self) -> TransportResult<u64> { fn get_slot(&self) -> TransportResult<u64> {
let slot = self.rpc_client().get_slot().map_err(|err| { self.get_slot_with_commitment(CommitmentConfig::default())
}
fn get_slot_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> TransportResult<u64> {
let slot = self
.rpc_client()
.get_slot_with_commitment(commitment_config)
.map_err(|err| {
io::Error::new( io::Error::new(
io::ErrorKind::Other, io::ErrorKind::Other,
format!("send_transaction failed with error {:?}", err), format!("send_transaction failed with error {:?}", err),
@ -385,6 +505,27 @@ impl SyncClient for ThinClient {
} }
} }
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> TransportResult<u64> {
let index = self.optimizer.experiment();
let now = Instant::now();
match self
.rpc_client()
.get_transaction_count_with_commitment(commitment_config)
{
Ok(transaction_count) => {
self.optimizer.report(index, duration_as_ms(&now.elapsed()));
Ok(transaction_count)
}
Err(e) => {
self.optimizer.report(index, std::u64::MAX);
Err(e.into())
}
}
}
/// Poll the server until the signature has been confirmed by at least `min_confirmed_blocks` /// Poll the server until the signature has been confirmed by at least `min_confirmed_blocks`
fn poll_for_signature_confirmation( fn poll_for_signature_confirmation(
&self, &self,

View File

@ -29,6 +29,7 @@ use solana_sdk::{
account_utils::State, account_utils::State,
client::{AsyncClient, SyncClient}, client::{AsyncClient, SyncClient},
clock::{get_complete_segment_from_slot, get_segment_from_slot, Slot}, clock::{get_complete_segment_from_slot, get_segment_from_slot, Slot},
commitment_config::CommitmentConfig,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
message::Message, message::Message,
signature::{Keypair, KeypairUtil, Signature}, signature::{Keypair, KeypairUtil, Signature},
@ -78,6 +79,7 @@ struct ArchiverMeta {
blockhash: Hash, blockhash: Hash,
sha_state: Hash, sha_state: Hash,
num_chacha_blocks: usize, num_chacha_blocks: usize,
client_commitment: CommitmentConfig,
} }
pub(crate) fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> { pub(crate) fn sample_file(in_path: &Path, sample_offsets: &[u64]) -> io::Result<Hash> {
@ -208,6 +210,7 @@ impl Archiver {
cluster_entrypoint: ContactInfo, cluster_entrypoint: ContactInfo,
keypair: Arc<Keypair>, keypair: Arc<Keypair>,
storage_keypair: Arc<Keypair>, storage_keypair: Arc<Keypair>,
client_commitment: CommitmentConfig,
) -> Result<Self> { ) -> Result<Self> {
let exit = Arc::new(AtomicBool::new(false)); let exit = Arc::new(AtomicBool::new(false));
@ -246,7 +249,12 @@ impl Archiver {
let client = crate::gossip_service::get_client(&nodes); let client = crate::gossip_service::get_client(&nodes);
info!("Setting up mining account..."); info!("Setting up mining account...");
if let Err(e) = Self::setup_mining_account(&client, &keypair, &storage_keypair) { if let Err(e) = Self::setup_mining_account(
&client,
&keypair,
&storage_keypair,
client_commitment.clone(),
) {
//shutdown services before exiting //shutdown services before exiting
exit.store(true, Ordering::Relaxed); exit.store(true, Ordering::Relaxed);
gossip_service.join()?; gossip_service.join()?;
@ -279,6 +287,7 @@ impl Archiver {
let node_info = node.info.clone(); let node_info = node.info.clone();
let mut meta = ArchiverMeta { let mut meta = ArchiverMeta {
ledger_path: ledger_path.to_path_buf(), ledger_path: ledger_path.to_path_buf(),
client_commitment,
..ArchiverMeta::default() ..ArchiverMeta::default()
}; };
spawn(move || { spawn(move || {
@ -383,7 +392,12 @@ impl Archiver {
} }
}; };
meta.blockhash = storage_blockhash; meta.blockhash = storage_blockhash;
Self::redeem_rewards(&cluster_info, archiver_keypair, storage_keypair); Self::redeem_rewards(
&cluster_info,
archiver_keypair,
storage_keypair,
meta.client_commitment.clone(),
);
} }
exit.store(true, Ordering::Relaxed); exit.store(true, Ordering::Relaxed);
} }
@ -392,11 +406,14 @@ impl Archiver {
cluster_info: &Arc<RwLock<ClusterInfo>>, cluster_info: &Arc<RwLock<ClusterInfo>>,
archiver_keypair: &Arc<Keypair>, archiver_keypair: &Arc<Keypair>,
storage_keypair: &Arc<Keypair>, storage_keypair: &Arc<Keypair>,
client_commitment: CommitmentConfig,
) { ) {
let nodes = cluster_info.read().unwrap().tvu_peers(); let nodes = cluster_info.read().unwrap().tvu_peers();
let client = crate::gossip_service::get_client(&nodes); let client = crate::gossip_service::get_client(&nodes);
if let Ok(Some(account)) = client.get_account(&storage_keypair.pubkey()) { if let Ok(Some(account)) =
client.get_account_with_commitment(&storage_keypair.pubkey(), client_commitment.clone())
{
if let Ok(StorageContract::ArchiverStorage { validations, .. }) = account.state() { if let Ok(StorageContract::ArchiverStorage { validations, .. }) = account.state() {
if !validations.is_empty() { if !validations.is_empty() {
let ix = storage_instruction::claim_reward( let ix = storage_instruction::claim_reward(
@ -410,7 +427,10 @@ impl Archiver {
} else { } else {
info!( info!(
"collected mining rewards: Account balance {:?}", "collected mining rewards: Account balance {:?}",
client.get_balance(&archiver_keypair.pubkey()) client.get_balance_with_commitment(
&archiver_keypair.pubkey(),
client_commitment.clone()
)
); );
} }
} }
@ -432,7 +452,8 @@ impl Archiver {
blob_fetch_receiver: PacketReceiver, blob_fetch_receiver: PacketReceiver,
slot_sender: Sender<u64>, slot_sender: Sender<u64>,
) -> Result<(WindowService)> { ) -> Result<(WindowService)> {
let slots_per_segment = match Self::get_segment_config(&cluster_info) { let slots_per_segment =
match Self::get_segment_config(&cluster_info, meta.client_commitment.clone()) {
Ok(slots_per_segment) => slots_per_segment, Ok(slots_per_segment) => slots_per_segment,
Err(e) => { Err(e) => {
error!("unable to get segment size configuration, exiting..."); error!("unable to get segment size configuration, exiting...");
@ -588,13 +609,15 @@ impl Archiver {
client: &ThinClient, client: &ThinClient,
keypair: &Keypair, keypair: &Keypair,
storage_keypair: &Keypair, storage_keypair: &Keypair,
client_commitment: CommitmentConfig,
) -> Result<()> { ) -> Result<()> {
// make sure archiver has some balance // make sure archiver has some balance
info!("checking archiver keypair..."); info!("checking archiver keypair...");
if client.poll_balance_with_timeout( if client.poll_balance_with_timeout_and_commitment(
&keypair.pubkey(), &keypair.pubkey(),
&Duration::from_millis(100), &Duration::from_millis(100),
&Duration::from_secs(5), &Duration::from_secs(5),
client_commitment.clone(),
)? == 0 )? == 0
{ {
return Err( return Err(
@ -604,9 +627,11 @@ impl Archiver {
info!("checking storage account keypair..."); info!("checking storage account keypair...");
// check if the storage account exists // check if the storage account exists
let balance = client.poll_get_balance(&storage_keypair.pubkey()); let balance = client
.poll_get_balance_with_commitment(&storage_keypair.pubkey(), client_commitment.clone());
if balance.is_err() || balance.unwrap() == 0 { if balance.is_err() || balance.unwrap() == 0 {
let blockhash = match client.get_recent_blockhash() { let blockhash =
match client.get_recent_blockhash_with_commitment(client_commitment.clone()) {
Ok((blockhash, _)) => blockhash, Ok((blockhash, _)) => blockhash,
Err(_) => { Err(_) => {
return Err(Error::IO(<io::Error>::new( return Err(Error::IO(<io::Error>::new(
@ -626,7 +651,7 @@ impl Archiver {
let tx = Transaction::new_signed_instructions(&[keypair], ix, blockhash); let tx = Transaction::new_signed_instructions(&[keypair], ix, blockhash);
let signature = client.async_send_transaction(tx)?; let signature = client.async_send_transaction(tx)?;
client client
.poll_for_signature(&signature) .poll_for_signature_with_commitment(&signature, client_commitment.clone())
.map_err(|err| match err { .map_err(|err| match err {
TransportError::IoError(e) => e, TransportError::IoError(e) => e,
TransportError::TransactionError(_) => io::Error::new( TransportError::TransactionError(_) => io::Error::new(
@ -647,19 +672,26 @@ impl Archiver {
// No point if we've got no storage account... // No point if we've got no storage account...
let nodes = cluster_info.read().unwrap().tvu_peers(); let nodes = cluster_info.read().unwrap().tvu_peers();
let client = crate::gossip_service::get_client(&nodes); let client = crate::gossip_service::get_client(&nodes);
let storage_balance = client.poll_get_balance(&storage_keypair.pubkey()); let storage_balance = client.poll_get_balance_with_commitment(
&storage_keypair.pubkey(),
meta.client_commitment.clone(),
);
if storage_balance.is_err() || storage_balance.unwrap() == 0 { if storage_balance.is_err() || storage_balance.unwrap() == 0 {
error!("Unable to submit mining proof, no storage account"); error!("Unable to submit mining proof, no storage account");
return; return;
} }
// ...or no lamports for fees // ...or no lamports for fees
let balance = client.poll_get_balance(&archiver_keypair.pubkey()); let balance = client.poll_get_balance_with_commitment(
&archiver_keypair.pubkey(),
meta.client_commitment.clone(),
);
if balance.is_err() || balance.unwrap() == 0 { if balance.is_err() || balance.unwrap() == 0 {
error!("Unable to submit mining proof, insufficient Archiver Account balance"); error!("Unable to submit mining proof, insufficient Archiver Account balance");
return; return;
} }
let blockhash = match client.get_recent_blockhash() { let blockhash =
match client.get_recent_blockhash_with_commitment(meta.client_commitment.clone()) {
Ok((blockhash, _)) => blockhash, Ok((blockhash, _)) => blockhash,
Err(_) => { Err(_) => {
error!("unable to get recent blockhash, can't submit proof"); error!("unable to get recent blockhash, can't submit proof");
@ -700,7 +732,10 @@ impl Archiver {
} }
} }
fn get_segment_config(cluster_info: &Arc<RwLock<ClusterInfo>>) -> result::Result<u64, Error> { fn get_segment_config(
cluster_info: &Arc<RwLock<ClusterInfo>>,
client_commitment: CommitmentConfig,
) -> result::Result<u64, Error> {
let rpc_peers = { let rpc_peers = {
let cluster_info = cluster_info.read().unwrap(); let cluster_info = cluster_info.read().unwrap();
cluster_info.rpc_peers() cluster_info.rpc_peers()
@ -712,7 +747,12 @@ impl Archiver {
RpcClient::new_socket(rpc_peers[node_index].rpc) RpcClient::new_socket(rpc_peers[node_index].rpc)
}; };
Ok(rpc_client Ok(rpc_client
.retry_make_rpc_request(&RpcRequest::GetSlotsPerSegment, None, 0) .retry_make_rpc_request(
&RpcRequest::GetSlotsPerSegment,
None,
0,
Some(client_commitment),
)
.map_err(|err| { .map_err(|err| {
warn!("Error while making rpc request {:?}", err); warn!("Error while making rpc request {:?}", err);
Error::IO(io::Error::new(ErrorKind::Other, "rpc error")) Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))
@ -764,7 +804,7 @@ impl Archiver {
RpcClient::new_socket(rpc_peers[node_index].rpc) RpcClient::new_socket(rpc_peers[node_index].rpc)
}; };
let response = rpc_client let response = rpc_client
.retry_make_rpc_request(&RpcRequest::GetStorageTurn, None, 0) .retry_make_rpc_request(&RpcRequest::GetStorageTurn, None, 0, None)
.map_err(|err| { .map_err(|err| {
warn!("Error while making rpc request {:?}", err); warn!("Error while making rpc request {:?}", err);
Error::IO(io::Error::new(ErrorKind::Other, "rpc error")) Error::IO(io::Error::new(ErrorKind::Other, "rpc error"))

View File

@ -19,6 +19,7 @@ use solana_runtime::bank::Bank;
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
clock::Slot, clock::Slot,
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
@ -60,8 +61,18 @@ pub struct JsonRpcRequestProcessor {
} }
impl JsonRpcRequestProcessor { impl JsonRpcRequestProcessor {
fn bank(&self) -> Arc<Bank> { fn bank(&self, commitment: Option<CommitmentConfig>) -> Arc<Bank> {
self.bank_forks.read().unwrap().working_bank() debug!("RPC commitment_config: {:?}", commitment);
let r_bank_forks = self.bank_forks.read().unwrap();
if commitment.is_some() && commitment.unwrap().commitment == CommitmentLevel::Recent {
let bank = r_bank_forks.working_bank();
debug!("RPC using working_bank: {:?}", bank.slot());
bank
} else {
let slot = r_bank_forks.root();
debug!("RPC using block: {:?}", slot);
r_bank_forks.get(slot).cloned().unwrap()
}
} }
pub fn new( pub fn new(
@ -80,43 +91,62 @@ impl JsonRpcRequestProcessor {
} }
} }
pub fn get_account_info(&self, pubkey: &Pubkey) -> Result<Account> { pub fn get_account_info(
self.bank() &self,
pubkey: &Pubkey,
commitment: Option<CommitmentConfig>,
) -> Result<Account> {
self.bank(commitment)
.get_account(&pubkey) .get_account(&pubkey)
.ok_or_else(Error::invalid_request) .ok_or_else(Error::invalid_request)
} }
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> { pub fn get_minimum_balance_for_rent_exemption(
Ok(self.bank().get_minimum_balance_for_rent_exemption(data_len)) &self,
data_len: usize,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
Ok(self
.bank(commitment)
.get_minimum_balance_for_rent_exemption(data_len))
} }
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Result<Vec<(String, Account)>> { pub fn get_program_accounts(
&self,
program_id: &Pubkey,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<(String, Account)>> {
Ok(self Ok(self
.bank() .bank(commitment)
.get_program_accounts(&program_id) .get_program_accounts(&program_id)
.into_iter() .into_iter()
.map(|(pubkey, account)| (pubkey.to_string(), account)) .map(|(pubkey, account)| (pubkey.to_string(), account))
.collect()) .collect())
} }
pub fn get_inflation(&self) -> Result<Inflation> { pub fn get_inflation(&self, commitment: Option<CommitmentConfig>) -> Result<Inflation> {
Ok(self.bank().inflation()) Ok(self.bank(commitment).inflation())
} }
pub fn get_epoch_schedule(&self) -> Result<EpochSchedule> { pub fn get_epoch_schedule(&self) -> Result<EpochSchedule> {
Ok(*self.bank().epoch_schedule()) // Since epoch schedule data comes from the genesis block, any commitment level should be
// fine
Ok(*self.bank(None).epoch_schedule())
} }
pub fn get_balance(&self, pubkey: &Pubkey) -> u64 { pub fn get_balance(&self, pubkey: &Pubkey, commitment: Option<CommitmentConfig>) -> u64 {
self.bank().get_balance(&pubkey) self.bank(commitment).get_balance(&pubkey)
} }
fn get_recent_blockhash(&self) -> (String, FeeCalculator) { fn get_recent_blockhash(
let (blockhash, fee_calculator) = self.bank().confirmed_last_blockhash(); &self,
commitment: Option<CommitmentConfig>,
) -> (String, FeeCalculator) {
let (blockhash, fee_calculator) = self.bank(commitment).confirmed_last_blockhash();
(blockhash.to_string(), fee_calculator) (blockhash.to_string(), fee_calculator)
} }
fn get_block_commitment(&self, block: u64) -> (Option<BlockCommitment>, u64) { fn get_block_commitment(&self, block: Slot) -> (Option<BlockCommitment>, u64) {
let r_block_commitment = self.block_commitment_cache.read().unwrap(); let r_block_commitment = self.block_commitment_cache.read().unwrap();
( (
r_block_commitment.get_block_commitment(block).cloned(), r_block_commitment.get_block_commitment(block).cloned(),
@ -124,41 +154,36 @@ impl JsonRpcRequestProcessor {
) )
} }
pub fn get_signature_status(&self, signature: Signature) -> Option<transaction::Result<()>> {
self.get_signature_confirmation_status(signature)
.map(|x| x.1)
}
pub fn get_signature_confirmations(&self, signature: Signature) -> Option<usize> {
self.get_signature_confirmation_status(signature)
.map(|x| x.0)
}
pub fn get_signature_confirmation_status( pub fn get_signature_confirmation_status(
&self, &self,
signature: Signature, signature: Signature,
commitment: Option<CommitmentConfig>,
) -> Option<(usize, transaction::Result<()>)> { ) -> Option<(usize, transaction::Result<()>)> {
self.bank().get_signature_confirmation_status(&signature) self.bank(commitment)
.get_signature_confirmation_status(&signature)
} }
fn get_slot(&self) -> Result<u64> { fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank().slot()) Ok(self.bank(commitment).slot())
} }
fn get_slot_leader(&self) -> Result<String> { fn get_slot_leader(&self, commitment: Option<CommitmentConfig>) -> Result<String> {
Ok(self.bank().collector_id().to_string()) Ok(self.bank(commitment).collector_id().to_string())
} }
fn get_transaction_count(&self) -> Result<u64> { fn get_transaction_count(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank().transaction_count() as u64) Ok(self.bank(commitment).transaction_count() as u64)
} }
fn get_total_supply(&self) -> Result<u64> { fn get_total_supply(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank().capitalization()) Ok(self.bank(commitment).capitalization())
} }
fn get_vote_accounts(&self) -> Result<RpcVoteAccountStatus> { fn get_vote_accounts(
let bank = self.bank(); &self,
commitment: Option<CommitmentConfig>,
) -> Result<RpcVoteAccountStatus> {
let bank = self.bank(commitment);
let vote_accounts = bank.vote_accounts(); let vote_accounts = bank.vote_accounts();
let epoch_vote_accounts = bank let epoch_vote_accounts = bank
.epoch_vote_accounts(bank.get_epoch_and_slot_index(bank.slot()).0) .epoch_vote_accounts(bank.get_epoch_and_slot_index(bank.slot()).0)
@ -212,8 +237,8 @@ impl JsonRpcRequestProcessor {
)) ))
} }
fn get_slots_per_segment(&self) -> Result<u64> { fn get_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank().slots_per_segment()) Ok(self.bank(commitment).slots_per_segment())
} }
fn get_storage_pubkeys_for_slot(&self, slot: Slot) -> Result<Vec<Pubkey>> { fn get_storage_pubkeys_for_slot(&self, slot: Slot) -> Result<Vec<Pubkey>> {
@ -281,119 +306,198 @@ pub trait RpcSol {
type Metadata; type Metadata;
#[rpc(meta, name = "confirmTransaction")] #[rpc(meta, name = "confirmTransaction")]
fn confirm_transaction(&self, _: Self::Metadata, _: String) -> Result<bool>; fn confirm_transaction(
&self,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<bool>;
#[rpc(meta, name = "getAccountInfo")] #[rpc(meta, name = "getAccountInfo")]
fn get_account_info(&self, _: Self::Metadata, _: String) -> Result<Account>; fn get_account_info(
&self,
meta: Self::Metadata,
pubkey_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Account>;
#[rpc(meta, name = "getProgramAccounts")] #[rpc(meta, name = "getProgramAccounts")]
fn get_program_accounts(&self, _: Self::Metadata, _: String) -> Result<Vec<(String, Account)>>; fn get_program_accounts(
&self,
meta: Self::Metadata,
program_id_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<(String, Account)>>;
#[rpc(meta, name = "getMinimumBalanceForRentExemption")] #[rpc(meta, name = "getMinimumBalanceForRentExemption")]
fn get_minimum_balance_for_rent_exemption(&self, _: Self::Metadata, _: usize) -> Result<u64>; fn get_minimum_balance_for_rent_exemption(
&self,
meta: Self::Metadata,
data_len: usize,
commitment: Option<CommitmentConfig>,
) -> Result<u64>;
#[rpc(meta, name = "getInflation")] #[rpc(meta, name = "getInflation")]
fn get_inflation(&self, _: Self::Metadata) -> Result<Inflation>; fn get_inflation(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Inflation>;
#[rpc(meta, name = "getEpochSchedule")] #[rpc(meta, name = "getEpochSchedule")]
fn get_epoch_schedule(&self, _: Self::Metadata) -> Result<EpochSchedule>; fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule>;
#[rpc(meta, name = "getBalance")] #[rpc(meta, name = "getBalance")]
fn get_balance(&self, _: Self::Metadata, _: String) -> Result<u64>; fn get_balance(
&self,
meta: Self::Metadata,
pubkey_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<u64>;
#[rpc(meta, name = "getClusterNodes")] #[rpc(meta, name = "getClusterNodes")]
fn get_cluster_nodes(&self, _: Self::Metadata) -> Result<Vec<RpcContactInfo>>; fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
#[rpc(meta, name = "getEpochInfo")] #[rpc(meta, name = "getEpochInfo")]
fn get_epoch_info(&self, _: Self::Metadata) -> Result<RpcEpochInfo>; fn get_epoch_info(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<RpcEpochInfo>;
#[rpc(meta, name = "getBlockCommitment")] #[rpc(meta, name = "getBlockCommitment")]
fn get_block_commitment( fn get_block_commitment(
&self, &self,
_: Self::Metadata, meta: Self::Metadata,
_: u64, block: u64,
) -> Result<(Option<BlockCommitment>, u64)>; ) -> Result<(Option<BlockCommitment>, u64)>;
#[rpc(meta, name = "getGenesisBlockhash")] #[rpc(meta, name = "getGenesisBlockhash")]
fn get_genesis_blockhash(&self, _: Self::Metadata) -> Result<String>; fn get_genesis_blockhash(&self, meta: Self::Metadata) -> Result<String>;
#[rpc(meta, name = "getLeaderSchedule")] #[rpc(meta, name = "getLeaderSchedule")]
fn get_leader_schedule(&self, _: Self::Metadata) -> Result<Option<Vec<String>>>; fn get_leader_schedule(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>>;
#[rpc(meta, name = "getRecentBlockhash")] #[rpc(meta, name = "getRecentBlockhash")]
fn get_recent_blockhash(&self, _: Self::Metadata) -> Result<(String, FeeCalculator)>; fn get_recent_blockhash(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<(String, FeeCalculator)>;
#[rpc(meta, name = "getSignatureStatus")] #[rpc(meta, name = "getSignatureStatus")]
fn get_signature_status( fn get_signature_status(
&self, &self,
_: Self::Metadata, meta: Self::Metadata,
_: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>>; ) -> Result<Option<transaction::Result<()>>>;
#[rpc(meta, name = "getSlot")] #[rpc(meta, name = "getSlot")]
fn get_slot(&self, _: Self::Metadata) -> Result<u64>; fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64>;
#[rpc(meta, name = "getTransactionCount")] #[rpc(meta, name = "getTransactionCount")]
fn get_transaction_count(&self, _: Self::Metadata) -> Result<u64>; fn get_transaction_count(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64>;
#[rpc(meta, name = "getTotalSupply")] #[rpc(meta, name = "getTotalSupply")]
fn get_total_supply(&self, _: Self::Metadata) -> Result<u64>; fn get_total_supply(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64>;
#[rpc(meta, name = "requestAirdrop")] #[rpc(meta, name = "requestAirdrop")]
fn request_airdrop(&self, _: Self::Metadata, _: String, _: u64) -> Result<String>; fn request_airdrop(
&self,
meta: Self::Metadata,
pubkey_str: String,
lamports: u64,
commitment: Option<CommitmentConfig>,
) -> Result<String>;
#[rpc(meta, name = "sendTransaction")] #[rpc(meta, name = "sendTransaction")]
fn send_transaction(&self, _: Self::Metadata, _: Vec<u8>) -> Result<String>; fn send_transaction(&self, meta: Self::Metadata, data: Vec<u8>) -> Result<String>;
#[rpc(meta, name = "getSlotLeader")] #[rpc(meta, name = "getSlotLeader")]
fn get_slot_leader(&self, _: Self::Metadata) -> Result<String>; fn get_slot_leader(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<String>;
#[rpc(meta, name = "getVoteAccounts")] #[rpc(meta, name = "getVoteAccounts")]
fn get_vote_accounts(&self, _: Self::Metadata) -> Result<RpcVoteAccountStatus>; fn get_vote_accounts(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<RpcVoteAccountStatus>;
#[rpc(meta, name = "getStorageTurnRate")] #[rpc(meta, name = "getStorageTurnRate")]
fn get_storage_turn_rate(&self, _: Self::Metadata) -> Result<u64>; fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64>;
#[rpc(meta, name = "getStorageTurn")] #[rpc(meta, name = "getStorageTurn")]
fn get_storage_turn(&self, _: Self::Metadata) -> Result<(String, u64)>; fn get_storage_turn(&self, meta: Self::Metadata) -> Result<(String, u64)>;
#[rpc(meta, name = "getSlotsPerSegment")] #[rpc(meta, name = "getSlotsPerSegment")]
fn get_slots_per_segment(&self, _: Self::Metadata) -> Result<u64>; fn get_slots_per_segment(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64>;
#[rpc(meta, name = "getStoragePubkeysForSlot")] #[rpc(meta, name = "getStoragePubkeysForSlot")]
fn get_storage_pubkeys_for_slot(&self, _: Self::Metadata, _: u64) -> Result<Vec<Pubkey>>; fn get_storage_pubkeys_for_slot(&self, meta: Self::Metadata, slot: u64) -> Result<Vec<Pubkey>>;
#[rpc(meta, name = "validatorExit")] #[rpc(meta, name = "validatorExit")]
fn validator_exit(&self, _: Self::Metadata) -> Result<bool>; fn validator_exit(&self, meta: Self::Metadata) -> Result<bool>;
#[rpc(meta, name = "getNumBlocksSinceSignatureConfirmation")] #[rpc(meta, name = "getNumBlocksSinceSignatureConfirmation")]
fn get_num_blocks_since_signature_confirmation( fn get_num_blocks_since_signature_confirmation(
&self, &self,
_: Self::Metadata, meta: Self::Metadata,
_: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<usize>>; ) -> Result<Option<usize>>;
#[rpc(meta, name = "getSignatureConfirmation")] #[rpc(meta, name = "getSignatureConfirmation")]
fn get_signature_confirmation( fn get_signature_confirmation(
&self, &self,
_: Self::Metadata, meta: Self::Metadata,
_: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<(usize, transaction::Result<()>)>>; ) -> Result<Option<(usize, transaction::Result<()>)>>;
#[rpc(meta, name = "getVersion")] #[rpc(meta, name = "getVersion")]
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo>; fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
#[rpc(meta, name = "setLogFilter")] #[rpc(meta, name = "setLogFilter")]
fn set_log_filter(&self, _: Self::Metadata, _: String) -> Result<()>; fn set_log_filter(&self, _meta: Self::Metadata, filter: String) -> Result<()>;
} }
pub struct RpcSolImpl; pub struct RpcSolImpl;
impl RpcSol for RpcSolImpl { impl RpcSol for RpcSolImpl {
type Metadata = Meta; type Metadata = Meta;
fn confirm_transaction(&self, meta: Self::Metadata, id: String) -> Result<bool> { fn confirm_transaction(
debug!("confirm_transaction rpc request received: {:?}", id); &self,
self.get_signature_status(meta, id).map(|status_option| { meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<bool> {
debug!(
"confirm_transaction rpc request received: {:?}",
signature_str
);
self.get_signature_status(meta, signature_str, commitment)
.map(|status_option| {
if status_option.is_none() { if status_option.is_none() {
return false; return false;
} }
@ -401,19 +505,25 @@ impl RpcSol for RpcSolImpl {
}) })
} }
fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> { fn get_account_info(
debug!("get_account_info rpc request received: {:?}", id); &self,
let pubkey = verify_pubkey(id)?; meta: Self::Metadata,
pubkey_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Account> {
debug!("get_account_info rpc request received: {:?}", pubkey_str);
let pubkey = verify_pubkey(pubkey_str)?;
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_account_info(&pubkey) .get_account_info(&pubkey, commitment)
} }
fn get_minimum_balance_for_rent_exemption( fn get_minimum_balance_for_rent_exemption(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
data_len: usize, data_len: usize,
commitment: Option<CommitmentConfig>,
) -> Result<u64> { ) -> Result<u64> {
debug!( debug!(
"get_minimum_balance_for_rent_exemption rpc request received: {:?}", "get_minimum_balance_for_rent_exemption rpc request received: {:?}",
@ -422,29 +532,37 @@ impl RpcSol for RpcSolImpl {
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_minimum_balance_for_rent_exemption(data_len) .get_minimum_balance_for_rent_exemption(data_len, commitment)
} }
fn get_program_accounts( fn get_program_accounts(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
id: String, program_id_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<(String, Account)>> { ) -> Result<Vec<(String, Account)>> {
debug!("get_program_accounts rpc request received: {:?}", id); debug!(
let program_id = verify_pubkey(id)?; "get_program_accounts rpc request received: {:?}",
program_id_str
);
let program_id = verify_pubkey(program_id_str)?;
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_program_accounts(&program_id) .get_program_accounts(&program_id, commitment)
} }
fn get_inflation(&self, meta: Self::Metadata) -> Result<Inflation> { fn get_inflation(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Inflation> {
debug!("get_inflation rpc request received"); debug!("get_inflation rpc request received");
Ok(meta Ok(meta
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_inflation() .get_inflation(commitment)
.unwrap()) .unwrap())
} }
@ -458,10 +576,19 @@ impl RpcSol for RpcSolImpl {
.unwrap()) .unwrap())
} }
fn get_balance(&self, meta: Self::Metadata, id: String) -> Result<u64> { fn get_balance(
debug!("get_balance rpc request received: {:?}", id); &self,
let pubkey = verify_pubkey(id)?; meta: Self::Metadata,
Ok(meta.request_processor.read().unwrap().get_balance(&pubkey)) pubkey_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
debug!("get_balance rpc request received: {:?}", pubkey_str);
let pubkey = verify_pubkey(pubkey_str)?;
Ok(meta
.request_processor
.read()
.unwrap()
.get_balance(&pubkey, commitment))
} }
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> { fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> {
@ -491,8 +618,12 @@ impl RpcSol for RpcSolImpl {
.collect()) .collect())
} }
fn get_epoch_info(&self, meta: Self::Metadata) -> Result<RpcEpochInfo> { fn get_epoch_info(
let bank = meta.request_processor.read().unwrap().bank(); &self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<RpcEpochInfo> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
let epoch_schedule = bank.epoch_schedule(); let epoch_schedule = bank.epoch_schedule();
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot()); let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot());
let slot = bank.slot(); let slot = bank.slot();
@ -507,7 +638,7 @@ impl RpcSol for RpcSolImpl {
fn get_block_commitment( fn get_block_commitment(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
block: u64, block: Slot,
) -> Result<(Option<BlockCommitment>, u64)> { ) -> Result<(Option<BlockCommitment>, u64)> {
Ok(meta Ok(meta
.request_processor .request_processor
@ -521,8 +652,12 @@ impl RpcSol for RpcSolImpl {
Ok(meta.genesis_blockhash.to_string()) Ok(meta.genesis_blockhash.to_string())
} }
fn get_leader_schedule(&self, meta: Self::Metadata) -> Result<Option<Vec<String>>> { fn get_leader_schedule(
let bank = meta.request_processor.read().unwrap().bank(); &self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
Ok( Ok(
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map( solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map(
|leader_schedule| { |leader_schedule| {
@ -536,66 +671,93 @@ impl RpcSol for RpcSolImpl {
) )
} }
fn get_recent_blockhash(&self, meta: Self::Metadata) -> Result<(String, FeeCalculator)> { fn get_recent_blockhash(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<(String, FeeCalculator)> {
debug!("get_recent_blockhash rpc request received"); debug!("get_recent_blockhash rpc request received");
Ok(meta Ok(meta
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_recent_blockhash()) .get_recent_blockhash(commitment))
} }
fn get_signature_status( fn get_signature_status(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
id: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>> { ) -> Result<Option<transaction::Result<()>>> {
self.get_signature_confirmation(meta, id) self.get_signature_confirmation(meta, signature_str, commitment)
.map(|res| res.map(|x| x.1)) .map(|res| res.map(|x| x.1))
} }
fn get_slot(&self, meta: Self::Metadata) -> Result<u64> { fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
meta.request_processor.read().unwrap().get_slot() meta.request_processor.read().unwrap().get_slot(commitment)
} }
fn get_num_blocks_since_signature_confirmation( fn get_num_blocks_since_signature_confirmation(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
id: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<usize>> { ) -> Result<Option<usize>> {
self.get_signature_confirmation(meta, id) self.get_signature_confirmation(meta, signature_str, commitment)
.map(|res| res.map(|x| x.0)) .map(|res| res.map(|x| x.0))
} }
fn get_signature_confirmation( fn get_signature_confirmation(
&self, &self,
meta: Self::Metadata, meta: Self::Metadata,
id: String, signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<(usize, transaction::Result<()>)>> { ) -> Result<Option<(usize, transaction::Result<()>)>> {
debug!("get_signature_confirmation rpc request received: {:?}", id); debug!(
let signature = verify_signature(&id)?; "get_signature_confirmation rpc request received: {:?}",
signature_str
);
let signature = verify_signature(&signature_str)?;
Ok(meta Ok(meta
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_signature_confirmation_status(signature)) .get_signature_confirmation_status(signature, commitment))
} }
fn get_transaction_count(&self, meta: Self::Metadata) -> Result<u64> { fn get_transaction_count(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
debug!("get_transaction_count rpc request received"); debug!("get_transaction_count rpc request received");
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_transaction_count() .get_transaction_count(commitment)
} }
fn get_total_supply(&self, meta: Self::Metadata) -> Result<u64> { fn get_total_supply(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
debug!("get_total_supply rpc request received"); debug!("get_total_supply rpc request received");
meta.request_processor.read().unwrap().get_total_supply() meta.request_processor
.read()
.unwrap()
.get_total_supply(commitment)
} }
fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result<String> { fn request_airdrop(
trace!("request_airdrop id={} lamports={}", id, lamports); &self,
meta: Self::Metadata,
pubkey_str: String,
lamports: u64,
commitment: Option<CommitmentConfig>,
) -> Result<String> {
trace!("request_airdrop id={} lamports={}", pubkey_str, lamports);
let drone_addr = meta let drone_addr = meta
.request_processor .request_processor
@ -604,13 +766,13 @@ impl RpcSol for RpcSolImpl {
.config .config
.drone_addr .drone_addr
.ok_or_else(Error::invalid_request)?; .ok_or_else(Error::invalid_request)?;
let pubkey = verify_pubkey(id)?; let pubkey = verify_pubkey(pubkey_str)?;
let blockhash = meta let blockhash = meta
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.bank() .bank(commitment.clone())
.confirmed_last_blockhash() .confirmed_last_blockhash()
.0; .0;
let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash) let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash)
@ -641,7 +803,8 @@ impl RpcSol for RpcSolImpl {
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_signature_status(signature); .get_signature_confirmation_status(signature, commitment.clone())
.map(|x| x.1);
if signature_status == Some(Ok(())) { if signature_status == Some(Ok(())) {
info!("airdrop signature ok"); info!("airdrop signature ok");
@ -689,12 +852,26 @@ impl RpcSol for RpcSolImpl {
Ok(signature) Ok(signature)
} }
fn get_slot_leader(&self, meta: Self::Metadata) -> Result<String> { fn get_slot_leader(
meta.request_processor.read().unwrap().get_slot_leader() &self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<String> {
meta.request_processor
.read()
.unwrap()
.get_slot_leader(commitment)
} }
fn get_vote_accounts(&self, meta: Self::Metadata) -> Result<RpcVoteAccountStatus> { fn get_vote_accounts(
meta.request_processor.read().unwrap().get_vote_accounts() &self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<RpcVoteAccountStatus> {
meta.request_processor
.read()
.unwrap()
.get_vote_accounts(commitment)
} }
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64> { fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64> {
@ -708,11 +885,15 @@ impl RpcSol for RpcSolImpl {
meta.request_processor.read().unwrap().get_storage_turn() meta.request_processor.read().unwrap().get_storage_turn()
} }
fn get_slots_per_segment(&self, meta: Self::Metadata) -> Result<u64> { fn get_slots_per_segment(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
meta.request_processor meta.request_processor
.read() .read()
.unwrap() .unwrap()
.get_slots_per_segment() .get_slots_per_segment(commitment)
} }
fn get_storage_pubkeys_for_slot( fn get_storage_pubkeys_for_slot(
@ -736,7 +917,7 @@ impl RpcSol for RpcSolImpl {
}) })
} }
fn set_log_filter(&self, _: Self::Metadata, filter: String) -> Result<()> { fn set_log_filter(&self, _meta: Self::Metadata, filter: String) -> Result<()> {
solana_logger::setup_with_filter(&filter); solana_logger::setup_with_filter(&filter);
Ok(()) Ok(())
} }
@ -863,7 +1044,7 @@ pub mod tests {
}) })
.join() .join()
.unwrap(); .unwrap();
assert_eq!(request_processor.get_transaction_count().unwrap(), 1); assert_eq!(request_processor.get_transaction_count(None).unwrap(), 1);
} }
#[test] #[test]

View File

@ -221,7 +221,7 @@ mod tests {
.request_processor .request_processor
.read() .read()
.unwrap() .unwrap()
.get_balance(&mint_keypair.pubkey()) .get_balance(&mint_keypair.pubkey(), None)
); );
rpc_service.exit(); rpc_service.exit();
rpc_service.join().unwrap(); rpc_service.join().unwrap();

View File

@ -511,7 +511,7 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
let GenesisBlockInfo { let GenesisBlockInfo {
mut genesis_block, mut genesis_block,
mint_keypair, mint_keypair,
.. voting_keypair,
} = create_genesis_block_with_leader(10_000, &contact_info.id, 42); } = create_genesis_block_with_leader(10_000, &contact_info.id, 42);
genesis_block genesis_block
.native_instruction_processors .native_instruction_processors
@ -522,14 +522,14 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block); let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block);
let voting_keypair = Arc::new(Keypair::new()); let leader_voting_keypair = Arc::new(voting_keypair);
let storage_keypair = Arc::new(Keypair::new()); let storage_keypair = Arc::new(Keypair::new());
let node = Validator::new( let node = Validator::new(
node, node,
&node_keypair, &node_keypair,
&ledger_path, &ledger_path,
&voting_keypair.pubkey(), &leader_voting_keypair.pubkey(),
&voting_keypair, &leader_voting_keypair,
&storage_keypair, &storage_keypair,
None, None,
true, true,

View File

@ -1,9 +1,9 @@
use rand::{thread_rng, Rng};
use solana_client::thin_client::create_client;
/// Cluster independant integration tests /// Cluster independant integration tests
/// ///
/// All tests must start from an entry point and a funding keypair and /// All tests must start from an entry point and a funding keypair and
/// discover the rest of the network. /// discover the rest of the network.
use rand::{thread_rng, Rng};
use solana_client::thin_client::create_client;
use solana_core::{ use solana_core::{
cluster_info::VALIDATOR_PORT_RANGE, consensus::VOTE_THRESHOLD_DEPTH, contact_info::ContactInfo, cluster_info::VALIDATOR_PORT_RANGE, consensus::VOTE_THRESHOLD_DEPTH, contact_info::ContactInfo,
gossip_service::discover_cluster, gossip_service::discover_cluster,
@ -15,6 +15,7 @@ use solana_ledger::{
use solana_sdk::{ use solana_sdk::{
client::SyncClient, client::SyncClient,
clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, NUM_CONSECUTIVE_LEADER_SLOTS}, clock::{Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, NUM_CONSECUTIVE_LEADER_SLOTS},
commitment_config::CommitmentConfig,
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH, epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
hash::Hash, hash::Hash,
poh_config::PohConfig, poh_config::PohConfig,
@ -49,10 +50,12 @@ pub fn spend_and_verify_all_nodes<S: ::std::hash::BuildHasher>(
let random_keypair = Keypair::new(); let random_keypair = Keypair::new();
let client = create_client(ingress_node.client_facing_addr(), VALIDATOR_PORT_RANGE); let client = create_client(ingress_node.client_facing_addr(), VALIDATOR_PORT_RANGE);
let bal = client let bal = client
.poll_get_balance(&funding_keypair.pubkey()) .poll_get_balance_with_commitment(&funding_keypair.pubkey(), CommitmentConfig::recent())
.expect("balance in source"); .expect("balance in source");
assert!(bal > 0); assert!(bal > 0);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap();
let mut transaction = let mut transaction =
system_transaction::transfer(&funding_keypair, &random_keypair.pubkey(), 1, blockhash); system_transaction::transfer(&funding_keypair, &random_keypair.pubkey(), 1, blockhash);
let confs = VOTE_THRESHOLD_DEPTH + 1; let confs = VOTE_THRESHOLD_DEPTH + 1;
@ -75,7 +78,9 @@ pub fn verify_balances<S: ::std::hash::BuildHasher>(
) { ) {
let client = create_client(node.client_facing_addr(), VALIDATOR_PORT_RANGE); let client = create_client(node.client_facing_addr(), VALIDATOR_PORT_RANGE);
for (pk, b) in expected_balances { for (pk, b) in expected_balances {
let bal = client.poll_get_balance(&pk).expect("balance in source"); let bal = client
.poll_get_balance_with_commitment(&pk, CommitmentConfig::recent())
.expect("balance in source");
assert_eq!(bal, b); assert_eq!(bal, b);
} }
} }
@ -91,10 +96,12 @@ pub fn send_many_transactions(
for _ in 0..num_txs { for _ in 0..num_txs {
let random_keypair = Keypair::new(); let random_keypair = Keypair::new();
let bal = client let bal = client
.poll_get_balance(&funding_keypair.pubkey()) .poll_get_balance_with_commitment(&funding_keypair.pubkey(), CommitmentConfig::recent())
.expect("balance in source"); .expect("balance in source");
assert!(bal > 0); assert!(bal > 0);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap();
let transfer_amount = thread_rng().gen_range(1, max_tokens_per_transfer); let transfer_amount = thread_rng().gen_range(1, max_tokens_per_transfer);
let mut transaction = system_transaction::transfer( let mut transaction = system_transaction::transfer(
@ -188,7 +195,7 @@ pub fn kill_entry_and_spend_and_verify_rest(
for ingress_node in &cluster_nodes { for ingress_node in &cluster_nodes {
client client
.poll_get_balance(&ingress_node.id) .poll_get_balance_with_commitment(&ingress_node.id, CommitmentConfig::recent())
.unwrap_or_else(|err| panic!("Node {} has no balance: {}", ingress_node.id, err)); .unwrap_or_else(|err| panic!("Node {} has no balance: {}", ingress_node.id, err));
} }
@ -212,7 +219,7 @@ pub fn kill_entry_and_spend_and_verify_rest(
let client = create_client(ingress_node.client_facing_addr(), VALIDATOR_PORT_RANGE); let client = create_client(ingress_node.client_facing_addr(), VALIDATOR_PORT_RANGE);
let balance = client let balance = client
.poll_get_balance(&funding_keypair.pubkey()) .poll_get_balance_with_commitment(&funding_keypair.pubkey(), CommitmentConfig::recent())
.expect("balance in source"); .expect("balance in source");
assert_ne!(balance, 0); assert_ne!(balance, 0);
@ -225,7 +232,9 @@ pub fn kill_entry_and_spend_and_verify_rest(
} }
let random_keypair = Keypair::new(); let random_keypair = Keypair::new();
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap();
let mut transaction = system_transaction::transfer( let mut transaction = system_transaction::transfer(
&funding_keypair, &funding_keypair,
&random_keypair.pubkey(), &random_keypair.pubkey(),

View File

@ -13,6 +13,7 @@ use solana_ledger::blocktree::create_new_tmp_ledger;
use solana_sdk::{ use solana_sdk::{
client::SyncClient, client::SyncClient,
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT}, clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_SLOTS_PER_SEGMENT, DEFAULT_TICKS_PER_SLOT},
commitment_config::CommitmentConfig,
epoch_schedule::EpochSchedule, epoch_schedule::EpochSchedule,
genesis_block::{GenesisBlock, OperatingMode}, genesis_block::{GenesisBlock, OperatingMode},
message::Message, message::Message,
@ -386,6 +387,7 @@ impl LocalCluster {
self.entry_point_info.clone(), self.entry_point_info.clone(),
archiver_keypair, archiver_keypair,
storage_keypair, storage_keypair,
CommitmentConfig::recent(),
) )
.unwrap_or_else(|err| panic!("Archiver::new() failed: {:?}", err)); .unwrap_or_else(|err| panic!("Archiver::new() failed: {:?}", err));
@ -424,7 +426,9 @@ impl LocalCluster {
lamports: u64, lamports: u64,
) -> u64 { ) -> u64 {
trace!("getting leader blockhash"); trace!("getting leader blockhash");
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap(); let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap();
let mut tx = let mut tx =
system_transaction::transfer(&source_keypair, dest_pubkey, lamports, blockhash); system_transaction::transfer(&source_keypair, dest_pubkey, lamports, blockhash);
info!( info!(
@ -437,7 +441,11 @@ impl LocalCluster {
.retry_transfer(&source_keypair, &mut tx, 10) .retry_transfer(&source_keypair, &mut tx, 10)
.expect("client transfer"); .expect("client transfer");
client client
.wait_for_balance(dest_pubkey, Some(lamports)) .wait_for_balance_with_commitment(
dest_pubkey,
Some(lamports),
CommitmentConfig::recent(),
)
.expect("get balance") .expect("get balance")
} }
@ -453,7 +461,11 @@ impl LocalCluster {
let stake_account_pubkey = stake_account_keypair.pubkey(); let stake_account_pubkey = stake_account_keypair.pubkey();
// Create the vote account if necessary // Create the vote account if necessary
if client.poll_get_balance(&vote_account_pubkey).unwrap_or(0) == 0 { if client
.poll_get_balance_with_commitment(&vote_account_pubkey, CommitmentConfig::recent())
.unwrap_or(0)
== 0
{
// 1) Create vote account // 1) Create vote account
let mut transaction = Transaction::new_signed_instructions( let mut transaction = Transaction::new_signed_instructions(
@ -469,13 +481,20 @@ impl LocalCluster {
}, },
amount, amount,
), ),
client.get_recent_blockhash().unwrap().0, client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap()
.0,
); );
client client
.retry_transfer(&from_account, &mut transaction, 10) .retry_transfer(&from_account, &mut transaction, 10)
.expect("fund vote"); .expect("fund vote");
client client
.wait_for_balance(&vote_account_pubkey, Some(amount)) .wait_for_balance_with_commitment(
&vote_account_pubkey,
Some(amount),
CommitmentConfig::recent(),
)
.expect("get balance"); .expect("get balance");
let mut transaction = Transaction::new_signed_instructions( let mut transaction = Transaction::new_signed_instructions(
@ -487,7 +506,10 @@ impl LocalCluster {
&StakeAuthorized::auto(&stake_account_pubkey), &StakeAuthorized::auto(&stake_account_pubkey),
amount, amount,
), ),
client.get_recent_blockhash().unwrap().0, client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap()
.0,
); );
client client
@ -499,7 +521,11 @@ impl LocalCluster {
) )
.expect("delegate stake"); .expect("delegate stake");
client client
.wait_for_balance(&stake_account_pubkey, Some(amount)) .wait_for_balance_with_commitment(
&stake_account_pubkey,
Some(amount),
CommitmentConfig::recent(),
)
.expect("get balance"); .expect("get balance");
} else { } else {
warn!( warn!(
@ -509,8 +535,8 @@ impl LocalCluster {
} }
info!("Checking for vote account registration of {}", node_pubkey); info!("Checking for vote account registration of {}", node_pubkey);
match ( match (
client.get_account(&stake_account_pubkey), client.get_account_with_commitment(&stake_account_pubkey, CommitmentConfig::recent()),
client.get_account(&vote_account_pubkey), client.get_account_with_commitment(&vote_account_pubkey, CommitmentConfig::recent()),
) { ) {
(Ok(Some(stake_account)), Ok(Some(vote_account))) => { (Ok(Some(stake_account)), Ok(Some(vote_account))) => {
match ( match (
@ -568,7 +594,10 @@ impl LocalCluster {
Some(&from_keypair.pubkey()), Some(&from_keypair.pubkey()),
); );
let signer_keys = vec![from_keypair.as_ref()]; let signer_keys = vec![from_keypair.as_ref()];
let blockhash = client.get_recent_blockhash().unwrap().0; let blockhash = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap()
.0;
let mut transaction = Transaction::new(&signer_keys, message, blockhash); let mut transaction = Transaction::new(&signer_keys, message, blockhash);
client client
.retry_transfer(&from_keypair, &mut transaction, 10) .retry_transfer(&from_keypair, &mut transaction, 10)

View File

@ -1,17 +1,24 @@
use crate::local_cluster::{ClusterConfig, LocalCluster}; use crate::local_cluster::{ClusterConfig, LocalCluster};
use serial_test_derive::serial; use serial_test_derive::serial;
use solana_client::thin_client::create_client; use solana_client::thin_client::create_client;
use solana_core::archiver::Archiver; use solana_core::{
use solana_core::cluster_info::{ClusterInfo, Node, VALIDATOR_PORT_RANGE}; archiver::Archiver,
use solana_core::contact_info::ContactInfo; cluster_info::{ClusterInfo, Node, VALIDATOR_PORT_RANGE},
use solana_core::gossip_service::discover_cluster; contact_info::ContactInfo,
use solana_core::storage_stage::SLOTS_PER_TURN_TEST; gossip_service::discover_cluster,
use solana_core::validator::ValidatorConfig; storage_stage::SLOTS_PER_TURN_TEST,
validator::ValidatorConfig,
};
use solana_ledger::blocktree::{create_new_tmp_ledger, get_tmp_ledger_path, Blocktree}; use solana_ledger::blocktree::{create_new_tmp_ledger, get_tmp_ledger_path, Blocktree};
use solana_sdk::genesis_block::create_genesis_block; use solana_sdk::{
use solana_sdk::signature::{Keypair, KeypairUtil}; commitment_config::CommitmentConfig,
use std::fs::remove_dir_all; genesis_block::create_genesis_block,
use std::sync::{Arc, RwLock}; signature::{Keypair, KeypairUtil},
};
use std::{
fs::remove_dir_all,
sync::{Arc, RwLock},
};
/// Start the cluster with the given configuration and wait till the archivers are discovered /// Start the cluster with the given configuration and wait till the archivers are discovered
/// Then download blobs from one of them. /// Then download blobs from one of them.
@ -99,6 +106,7 @@ fn test_archiver_startup_leader_hang() {
leader_info, leader_info,
archiver_keypair, archiver_keypair,
storage_keypair, storage_keypair,
CommitmentConfig::recent(),
); );
assert!(archiver_res.is_err()); assert!(archiver_res.is_err());
@ -134,6 +142,7 @@ fn test_archiver_startup_ledger_hang() {
cluster.entry_point_info.clone(), cluster.entry_point_info.clone(),
bad_keys, bad_keys,
storage_keypair, storage_keypair,
CommitmentConfig::recent(),
); );
assert!(archiver_res.is_err()); assert!(archiver_res.is_err());
@ -168,7 +177,10 @@ fn test_account_setup() {
cluster.archiver_infos.iter().for_each(|(_, value)| { cluster.archiver_infos.iter().for_each(|(_, value)| {
assert_eq!( assert_eq!(
client client
.poll_get_balance(&value.archiver_storage_pubkey) .poll_get_balance_with_commitment(
&value.archiver_storage_pubkey,
CommitmentConfig::recent()
)
.unwrap(), .unwrap(),
1 1
); );

View File

@ -15,14 +15,15 @@ use solana_runtime::accounts_db::AccountsDB;
use solana_sdk::{ use solana_sdk::{
client::SyncClient, client::SyncClient,
clock, clock,
commitment_config::CommitmentConfig,
epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH}, epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH},
genesis_block::OperatingMode, genesis_block::OperatingMode,
poh_config::PohConfig, poh_config::PohConfig,
}; };
use std::path::{Path, PathBuf};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fs, fs,
path::{Path, PathBuf},
thread::sleep, thread::sleep,
time::Duration, time::Duration,
}; };
@ -329,7 +330,12 @@ fn test_softlaunch_operating_mode() {
.iter() .iter()
{ {
assert_eq!( assert_eq!(
(program_id, client.get_account(program_id).unwrap()), (
program_id,
client
.get_account_with_commitment(program_id, CommitmentConfig::recent())
.unwrap()
),
(program_id, None) (program_id, None)
); );
} }
@ -460,7 +466,7 @@ fn test_snapshots_blocktree_floor() {
let target_slot = slot_floor + 40; let target_slot = slot_floor + 40;
while current_slot <= target_slot { while current_slot <= target_slot {
trace!("current_slot: {}", current_slot); trace!("current_slot: {}", current_slot);
if let Ok(slot) = validator_client.get_slot() { if let Ok(slot) = validator_client.get_slot_with_commitment(CommitmentConfig::recent()) {
current_slot = slot; current_slot = slot;
} else { } else {
continue; continue;
@ -751,7 +757,7 @@ fn run_repairman_catchup(num_repairmen: u64) {
let target_slot = (num_warmup_epochs) * num_slots_per_epoch + 1; let target_slot = (num_warmup_epochs) * num_slots_per_epoch + 1;
while current_slot <= target_slot { while current_slot <= target_slot {
trace!("current_slot: {}", current_slot); trace!("current_slot: {}", current_slot);
if let Ok(slot) = repairee_client.get_slot() { if let Ok(slot) = repairee_client.get_slot_with_commitment(CommitmentConfig::recent()) {
current_slot = slot; current_slot = slot;
} else { } else {
continue; continue;
@ -765,7 +771,9 @@ fn wait_for_next_snapshot<P: AsRef<Path>>(cluster: &LocalCluster, tar: P) {
let client = cluster let client = cluster
.get_validator_client(&cluster.entry_point_info.id) .get_validator_client(&cluster.entry_point_info.id)
.unwrap(); .unwrap();
let last_slot = client.get_slot().expect("Couldn't get slot"); let last_slot = client
.get_slot_with_commitment(CommitmentConfig::recent())
.expect("Couldn't get slot");
// Wait for a snapshot for a bank >= last_slot to be made so we know that the snapshot // Wait for a snapshot for a bank >= last_slot to be made so we know that the snapshot
// must include the transactions just pushed // must include the transactions just pushed

View File

@ -1,22 +1,27 @@
use crate::bank::Bank; use crate::bank::Bank;
use solana_sdk::account::Account; use solana_sdk::{
use solana_sdk::client::{AsyncClient, Client, SyncClient}; account::Account,
use solana_sdk::fee_calculator::FeeCalculator; client::{AsyncClient, Client, SyncClient},
use solana_sdk::hash::Hash; commitment_config::CommitmentConfig,
use solana_sdk::instruction::Instruction; fee_calculator::FeeCalculator,
use solana_sdk::message::Message; hash::Hash,
use solana_sdk::pubkey::Pubkey; instruction::Instruction,
use solana_sdk::signature::Signature; message::Message,
use solana_sdk::signature::{Keypair, KeypairUtil}; pubkey::Pubkey,
use solana_sdk::system_instruction; signature::{Keypair, KeypairUtil, Signature},
use solana_sdk::transaction::{self, Transaction}; system_instruction,
use solana_sdk::transport::{Result, TransportError}; transaction::{self, Transaction},
use std::io; transport::{Result, TransportError},
use std::sync::mpsc::{channel, Receiver, Sender}; };
use std::sync::Arc; use std::{
use std::sync::Mutex; io,
use std::thread::{sleep, Builder}; sync::{
use std::time::{Duration, Instant}; mpsc::{channel, Receiver, Sender},
Arc, Mutex,
},
thread::{sleep, Builder},
time::{Duration, Instant},
};
pub struct BankClient { pub struct BankClient {
bank: Arc<Bank>, bank: Arc<Bank>,
@ -100,14 +105,37 @@ impl SyncClient for BankClient {
Ok(self.bank.get_account(pubkey)) Ok(self.bank.get_account(pubkey))
} }
fn get_account_with_commitment(
&self,
pubkey: &Pubkey,
_commitment_config: CommitmentConfig,
) -> Result<Option<Account>> {
Ok(self.bank.get_account(pubkey))
}
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> { fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
Ok(self.bank.get_balance(pubkey)) Ok(self.bank.get_balance(pubkey))
} }
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
_commitment_config: CommitmentConfig,
) -> Result<u64> {
Ok(self.bank.get_balance(pubkey))
}
fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> { fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> {
Ok(self.bank.last_blockhash_with_fee_calculator()) Ok(self.bank.last_blockhash_with_fee_calculator())
} }
fn get_recent_blockhash_with_commitment(
&self,
_commitment_config: CommitmentConfig,
) -> Result<(Hash, FeeCalculator)> {
Ok(self.bank.last_blockhash_with_fee_calculator())
}
fn get_signature_status( fn get_signature_status(
&self, &self,
signature: &Signature, signature: &Signature,
@ -115,14 +143,33 @@ impl SyncClient for BankClient {
Ok(self.bank.get_signature_status(signature)) Ok(self.bank.get_signature_status(signature))
} }
fn get_signature_status_with_commitment(
&self,
signature: &Signature,
_commitment_config: CommitmentConfig,
) -> Result<Option<transaction::Result<()>>> {
Ok(self.bank.get_signature_status(signature))
}
fn get_slot(&self) -> Result<u64> { fn get_slot(&self) -> Result<u64> {
Ok(self.bank.slot()) Ok(self.bank.slot())
} }
fn get_slot_with_commitment(&self, _commitment_config: CommitmentConfig) -> Result<u64> {
Ok(self.bank.slot())
}
fn get_transaction_count(&self) -> Result<u64> { fn get_transaction_count(&self) -> Result<u64> {
Ok(self.bank.transaction_count()) Ok(self.bank.transaction_count())
} }
fn get_transaction_count_with_commitment(
&self,
_commitment_config: CommitmentConfig,
) -> Result<u64> {
Ok(self.bank.transaction_count())
}
fn poll_for_signature_confirmation( fn poll_for_signature_confirmation(
&self, &self,
signature: &Signature, signature: &Signature,

View File

@ -10,6 +10,7 @@
use crate::{ use crate::{
account::Account, account::Account,
clock::Slot, clock::Slot,
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator, fee_calculator::FeeCalculator,
hash::Hash, hash::Hash,
instruction::Instruction, instruction::Instruction,
@ -44,24 +45,60 @@ pub trait SyncClient {
/// Get an account or None if not found. /// Get an account or None if not found.
fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>>; fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>>;
/// Get an account or None if not found. Uses explicit commitment configuration.
fn get_account_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<Option<Account>>;
/// Get account balance or 0 if not found. /// Get account balance or 0 if not found.
fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>; fn get_balance(&self, pubkey: &Pubkey) -> Result<u64>;
/// Get account balance or 0 if not found. Uses explicit commitment configuration.
fn get_balance_with_commitment(
&self,
pubkey: &Pubkey,
commitment_config: CommitmentConfig,
) -> Result<u64>;
/// Get recent blockhash /// Get recent blockhash
fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)>; fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)>;
/// Get recent blockhash. Uses explicit commitment configuration.
fn get_recent_blockhash_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<(Hash, FeeCalculator)>;
/// Get signature status. /// Get signature status.
fn get_signature_status( fn get_signature_status(
&self, &self,
signature: &Signature, signature: &Signature,
) -> Result<Option<transaction::Result<()>>>; ) -> Result<Option<transaction::Result<()>>>;
/// Get signature status. Uses explicit commitment configuration.
fn get_signature_status_with_commitment(
&self,
signature: &Signature,
commitment_config: CommitmentConfig,
) -> Result<Option<transaction::Result<()>>>;
/// Get last known slot /// Get last known slot
fn get_slot(&self) -> Result<Slot>; fn get_slot(&self) -> Result<Slot>;
/// Get last known slot. Uses explicit commitment configuration.
fn get_slot_with_commitment(&self, commitment_config: CommitmentConfig) -> Result<u64>;
/// Get transaction count /// Get transaction count
fn get_transaction_count(&self) -> Result<u64>; fn get_transaction_count(&self) -> Result<u64>;
/// Get transaction count. Uses explicit commitment configuration.
fn get_transaction_count_with_commitment(
&self,
commitment_config: CommitmentConfig,
) -> Result<u64>;
/// Poll until the signature has been confirmed by at least `min_confirmed_blocks` /// Poll until the signature has been confirmed by at least `min_confirmed_blocks`
fn poll_for_signature_confirmation( fn poll_for_signature_confirmation(
&self, &self,

View File

@ -0,0 +1,36 @@
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CommitmentConfig {
pub commitment: CommitmentLevel,
}
impl Default for CommitmentConfig {
fn default() -> Self {
CommitmentConfig {
commitment: CommitmentLevel::Max,
}
}
}
impl CommitmentConfig {
pub fn recent() -> Self {
Self {
commitment: CommitmentLevel::Recent,
}
}
pub fn ok(&self) -> Option<Self> {
if self == &Self::default() {
None
} else {
Some(self.clone())
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum CommitmentLevel {
Max,
Recent,
}

View File

@ -35,6 +35,8 @@ pub mod bank_hash;
#[cfg(not(feature = "program"))] #[cfg(not(feature = "program"))]
pub mod client; pub mod client;
#[cfg(not(feature = "program"))] #[cfg(not(feature = "program"))]
pub mod commitment_config;
#[cfg(not(feature = "program"))]
pub mod genesis_block; pub mod genesis_block;
#[cfg(not(feature = "program"))] #[cfg(not(feature = "program"))]
pub mod packet; pub mod packet;