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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 console::style;
use solana_core::archiver::Archiver;
use solana_core::cluster_info::{Node, VALIDATOR_PORT_RANGE};
use solana_core::contact_info::ContactInfo;
use solana_sdk::signature::{read_keypair_file, Keypair, KeypairUtil};
use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::exit;
use std::sync::Arc;
use solana_core::{
archiver::Archiver,
cluster_info::{Node, VALIDATOR_PORT_RANGE},
contact_info::ContactInfo,
};
use solana_sdk::{
commitment_config::CommitmentConfig,
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.
fn is_keypair(string: String) -> Result<(), String> {
@ -118,6 +120,7 @@ fn main() {
entrypoint_info,
Arc::new(keypair),
Arc::new(storage_keypair),
CommitmentConfig::recent(),
)
.unwrap();

View File

@ -8,31 +8,35 @@ use rayon::prelude::*;
use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_core::gen_keys::GenKeys;
use solana_drone::drone::request_airdrop_transaction;
use solana_exchange_api::exchange_instruction;
use solana_exchange_api::exchange_state::*;
use solana_exchange_api::id;
use solana_exchange_api::{exchange_instruction, exchange_state::*, id};
use solana_genesis::Base64Account;
use solana_metrics::datapoint_info;
use solana_sdk::client::Client;
use solana_sdk::client::SyncClient;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::timing::{duration_as_ms, duration_as_s};
use solana_sdk::transaction::Transaction;
use solana_sdk::{system_instruction, system_program};
use std::cmp;
use std::collections::{HashMap, VecDeque};
use std::fs::File;
use std::io::prelude::*;
use std::mem;
use std::net::SocketAddr;
use std::path::Path;
use std::process::exit;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, RwLock};
use std::thread::{sleep, Builder};
use std::time::{Duration, Instant};
use solana_sdk::{
client::{Client, SyncClient},
commitment_config::CommitmentConfig,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
timing::{duration_as_ms, duration_as_s},
transaction::Transaction,
{system_instruction, system_program},
};
use std::{
cmp,
collections::{HashMap, VecDeque},
fs::File,
io::prelude::*,
mem,
net::SocketAddr,
path::Path,
process::exit,
sync::{
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...
// Assume 4MB network buffers, and 512 byte packets
@ -380,7 +384,10 @@ fn swapper<T>(
let mut tries = 0;
let mut trade_index = 0;
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)
== 0
{
@ -434,7 +441,7 @@ fn swapper<T>(
account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash");
let to_swap_txs: Vec<_> = to_swap
.par_iter()
@ -562,7 +569,7 @@ fn trader<T>(
account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash");
trades.chunks(chunk_size).for_each(|chunk| {
@ -638,7 +645,9 @@ where
T: SyncClient + ?Sized,
{
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 {
Ok(_) => {
return true;
@ -659,12 +668,15 @@ fn verify_funding_transfer<T: SyncClient + ?Sized>(
) -> bool {
if verify_transaction(client, tx) {
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;
}
}
}
false
}
@ -742,8 +754,9 @@ pub fn fund_keys(client: &dyn Client, source: &Keypair, dests: &[Arc<Keypair>],
to_fund_txs.len(),
);
let (blockhash, _fee_calculator) =
client.get_recent_blockhash().expect("blockhash");
let (blockhash, _fee_calculator) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("blockhash");
to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
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.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());
}
@ -819,7 +836,7 @@ pub fn create_token_accounts(client: &dyn Client, signers: &[Arc<Keypair>], acco
let mut retries = 0;
while !to_create_txs.is_empty() {
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash");
to_create_txs.par_iter_mut().for_each(|(k, tx)| {
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![];
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)
}
}
@ -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) {
let balance = client.get_balance(&id.pubkey());
let balance = client.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent());
let balance = balance.unwrap_or(0);
if balance >= amount {
return;
@ -938,19 +959,26 @@ pub fn airdrop_lamports(client: &dyn Client, drone_addr: &SocketAddr, id: &Keypa
let mut tries = 0;
loop {
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.expect("Failed to get blockhash");
match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap();
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;
}
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;
}
}

View File

@ -1,5 +1,3 @@
use solana_metrics;
use crate::cli::Config;
use log::*;
use rayon::prelude::*;
@ -9,10 +7,11 @@ use solana_drone::drone::request_airdrop_transaction;
#[cfg(feature = "move")]
use solana_librapay_api::{create_genesis, upload_mint_program, upload_payment_program};
use solana_measure::measure::Measure;
use solana_metrics::datapoint_debug;
use solana_metrics::{self, datapoint_debug};
use solana_sdk::{
client::Client,
clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, MAX_PROCESSING_AGE},
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
@ -55,7 +54,7 @@ type LibraKeys = (Keypair, Pubkey, Pubkey, Vec<Keypair>);
fn get_recent_blockhash<T: Client>(client: &T) -> (Hash, FeeCalculator) {
loop {
match client.get_recent_blockhash() {
match client.get_recent_blockhash_with_commitment(CommitmentConfig::recent()) {
Ok((blockhash, fee_calculator)) => return (blockhash, fee_calculator),
Err(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 {
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;
}
}
@ -666,10 +669,12 @@ pub fn airdrop_lamports<T: Client>(
}
};
let current_balance = client.get_balance(&id.pubkey()).unwrap_or_else(|e| {
info!("airdrop error {}", e);
starting_balance
});
let current_balance = client
.get_balance_with_commitment(&id.pubkey(), CommitmentConfig::recent())
.unwrap_or_else(|e| {
info!("airdrop error {}", e);
starting_balance
});
info!("current balance {}...", current_balance);
metrics_submit_lamport_balance(current_balance);
@ -815,7 +820,11 @@ fn fund_move_keys<T: Client>(
let create_len = 8;
let mut funding_time = Measure::start("funding_time");
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.
break;
}
@ -853,7 +862,9 @@ fn fund_move_keys<T: Client>(
client.send_message(&[funding_key], tx.message).unwrap();
let mut balance = 0;
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 {
balance = balance_;
break;
@ -1078,7 +1089,12 @@ mod tests {
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, false).unwrap();
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();
let max_fee = client
.get_recent_blockhash()
.get_recent_blockhash_with_commitment(CommitmentConfig::recent())
.unwrap()
.1
.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.
* 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
### confirmTransaction
@ -91,6 +109,7 @@ Returns a transaction receipt
#### Results:
* `boolean` - Transaction status, true if Transaction is confirmed
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Example:
@ -109,6 +128,7 @@ Returns all information associated with the account of provided Pubkey
#### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -136,6 +156,7 @@ Returns the balance of the account of provided Pubkey
#### Parameters:
* `string` - Pubkey of account to query, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -212,7 +233,7 @@ Returns information about the current epoch
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -288,7 +309,7 @@ Returns the leader schedule for the current epoch
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -311,6 +332,7 @@ Returns minimum balance required to make account rent exempt.
#### Parameters:
* `integer` - account data length, as unsigned integer
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -333,6 +355,7 @@ Returns the current number of blocks since signature has been confirmed.
#### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -355,6 +378,7 @@ Returns all accounts owned by the provided program Pubkey
#### Parameters:
* `string` - Pubkey of program, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -382,7 +406,7 @@ Returns a recent block hash from the ledger, and a fee schedule that can be used
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -408,6 +432,7 @@ Returns the status of a given signature. This method is similar to [confirmTrans
#### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -432,7 +457,7 @@ Returns the current slot the node is processing
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -454,7 +479,7 @@ Returns the current slot leader
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -476,7 +501,7 @@ Returns the current storage segment size in terms of slots
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -542,7 +567,7 @@ Returns the current Transaction count from the ledger
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Results:
@ -569,6 +594,7 @@ None
#### Results:
* `integer` - Total supply, as unsigned 64-bit integer
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### Example:
@ -609,7 +635,7 @@ Returns the account info and associated stake for all the voting accounts in the
#### Parameters:
None
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
#### 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
* `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:

View File

@ -364,7 +364,7 @@ while [[ $iteration -le $iterations ]]; do
echo "--- Wallet sanity ($iteration)"
(
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
iteration=$((iteration + 1))

View File

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

View File

@ -11,11 +11,14 @@ use serde_derive::{Deserialize, Serialize};
use serde_json::{Map, Value};
use solana_client::rpc_client::RpcClient;
use solana_config_api::{config_instruction, get_config_data, ConfigKeys, ConfigState};
use solana_sdk::account::Account;
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::transaction::Transaction;
use solana_sdk::{
account::Account,
commitment_config::CommitmentConfig,
message::Message,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
transaction::Transaction,
};
use std::error;
pub const MAX_SHORT_FIELD_LENGTH: usize = 70;
@ -297,7 +300,9 @@ pub fn process_set_validator_info(
};
// 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 (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_client::rpc_client::RpcClient;
use solana_client::rpc_request::RpcRequest;
use solana_core::validator::new_validator_for_tests;
use solana_drone::drone::run_local_drone;
use solana_sdk::bpf_loader;
use std::fs::{remove_dir_all, File};
use std::io::Read;
use std::path::PathBuf;
use std::sync::mpsc::channel;
use solana_sdk::{bpf_loader, commitment_config::CommitmentConfig, pubkey::Pubkey};
use std::{
fs::{remove_dir_all, File},
io::Read,
path::PathBuf,
str::FromStr,
sync::mpsc::channel,
};
#[test]
fn test_cli_deploy_program() {
@ -56,35 +58,20 @@ fn test_cli_deploy_program() {
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let params = json!([program_id_str]);
let account_info = rpc_client
.retry_make_rpc_request(&RpcRequest::GetAccountInfo, Some(params), 0)
let account = rpc_client
.get_account_with_commitment(&program_id, CommitmentConfig::recent())
.unwrap();
let account_info_obj = account_info.as_object().unwrap();
assert_eq!(
account_info_obj.get("lamports").unwrap().as_u64().unwrap(),
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
);
assert_eq!(account.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account.owner, bpf_loader::id());
assert_eq!(account.executable, true);
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
assert_eq!(
account_info_obj.get("data").unwrap().as_array().unwrap(),
&elf
);
assert_eq!(account.data, elf);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,8 @@
use serde_json::{json, Value};
use solana_sdk::clock::{Epoch, Slot};
use solana_sdk::{
clock::{Epoch, Slot},
commitment_config::CommitmentConfig,
};
use std::{error, fmt};
#[derive(Serialize, Deserialize, Clone, Debug)]
@ -83,7 +86,12 @@ pub enum 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 method = match self {
RpcRequest::ConfirmTransaction => "confirmTransaction",
@ -123,7 +131,13 @@ impl RpcRequest {
"method": method,
});
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
}
@ -154,45 +168,65 @@ impl error::Error for RpcError {
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::commitment_config::CommitmentLevel;
#[test]
fn test_build_request_json() {
let test_request = RpcRequest::GetAccountInfo;
let addr = json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]);
let request = test_request.build_request_json(1, Some(addr.clone()));
let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
let request = test_request.build_request_json(1, Some(addr.clone()), None);
assert_eq!(request["method"], "getAccountInfo");
assert_eq!(request["params"], addr,);
assert_eq!(request["params"], json!([addr]));
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");
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");
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");
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");
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");
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");
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");
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");
}
#[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 bincode::{serialize_into, serialized_size};
use log::*;
use solana_sdk::account::Account;
use solana_sdk::client::{AsyncClient, Client, SyncClient};
use solana_sdk::clock::MAX_PROCESSING_AGE;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::Hash;
use solana_sdk::instruction::Instruction;
use solana_sdk::message::Message;
use solana_sdk::packet::PACKET_DATA_SIZE;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
use solana_sdk::system_instruction;
use solana_sdk::timing::duration_as_ms;
use solana_sdk::transaction::{self, Transaction};
use solana_sdk::transport::Result as TransportResult;
use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::RwLock;
use std::time::{Duration, Instant};
use solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
clock::MAX_PROCESSING_AGE,
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
instruction::Instruction,
message::Message,
packet::PACKET_DATA_SIZE,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature},
system_instruction,
timing::duration_as_ms,
transaction::{self, Transaction},
transport::Result as TransportResult,
};
use std::{
io,
net::{SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
RwLock,
},
time::{Duration, Instant},
};
struct ClientOptimizer {
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(
&self,
pubkey: &Pubkey,
polling_frequency: &Duration,
timeout: &Duration,
) -> io::Result<u64> {
self.rpc_client()
.poll_balance_with_timeout(pubkey, polling_frequency, timeout)
self.rpc_client().poll_balance_with_timeout_and_commitment(
pubkey,
polling_frequency,
timeout,
CommitmentConfig::default(),
)
}
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> {
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
@ -323,15 +386,45 @@ impl SyncClient for ThinClient {
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> {
let balance = self.rpc_client().get_balance(pubkey)?;
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)> {
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 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 {
Ok(recent_blockhash) => {
self.optimizer.report(index, duration_as_ms(&now.elapsed()));
@ -360,13 +453,40 @@ impl SyncClient for ThinClient {
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> {
let slot = self.rpc_client().get_slot().map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("send_transaction failed with error {:?}", 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::ErrorKind::Other,
format!("send_transaction failed with error {:?}", err),
)
})?;
Ok(slot)
}
@ -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`
fn poll_for_signature_confirmation(
&self,

View File

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

View File

@ -19,6 +19,7 @@ use solana_runtime::bank::Bank;
use solana_sdk::{
account::Account,
clock::Slot,
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_schedule::EpochSchedule,
fee_calculator::FeeCalculator,
hash::Hash,
@ -60,8 +61,18 @@ pub struct JsonRpcRequestProcessor {
}
impl JsonRpcRequestProcessor {
fn bank(&self) -> Arc<Bank> {
self.bank_forks.read().unwrap().working_bank()
fn bank(&self, commitment: Option<CommitmentConfig>) -> Arc<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(
@ -80,43 +91,62 @@ impl JsonRpcRequestProcessor {
}
}
pub fn get_account_info(&self, pubkey: &Pubkey) -> Result<Account> {
self.bank()
pub fn get_account_info(
&self,
pubkey: &Pubkey,
commitment: Option<CommitmentConfig>,
) -> Result<Account> {
self.bank(commitment)
.get_account(&pubkey)
.ok_or_else(Error::invalid_request)
}
pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
Ok(self.bank().get_minimum_balance_for_rent_exemption(data_len))
pub fn get_minimum_balance_for_rent_exemption(
&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
.bank()
.bank(commitment)
.get_program_accounts(&program_id)
.into_iter()
.map(|(pubkey, account)| (pubkey.to_string(), account))
.collect())
}
pub fn get_inflation(&self) -> Result<Inflation> {
Ok(self.bank().inflation())
pub fn get_inflation(&self, commitment: Option<CommitmentConfig>) -> Result<Inflation> {
Ok(self.bank(commitment).inflation())
}
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 {
self.bank().get_balance(&pubkey)
pub fn get_balance(&self, pubkey: &Pubkey, commitment: Option<CommitmentConfig>) -> u64 {
self.bank(commitment).get_balance(&pubkey)
}
fn get_recent_blockhash(&self) -> (String, FeeCalculator) {
let (blockhash, fee_calculator) = self.bank().confirmed_last_blockhash();
fn get_recent_blockhash(
&self,
commitment: Option<CommitmentConfig>,
) -> (String, FeeCalculator) {
let (blockhash, fee_calculator) = self.bank(commitment).confirmed_last_blockhash();
(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();
(
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(
&self,
signature: Signature,
commitment: Option<CommitmentConfig>,
) -> 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> {
Ok(self.bank().slot())
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank(commitment).slot())
}
fn get_slot_leader(&self) -> Result<String> {
Ok(self.bank().collector_id().to_string())
fn get_slot_leader(&self, commitment: Option<CommitmentConfig>) -> Result<String> {
Ok(self.bank(commitment).collector_id().to_string())
}
fn get_transaction_count(&self) -> Result<u64> {
Ok(self.bank().transaction_count() as u64)
fn get_transaction_count(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank(commitment).transaction_count() as u64)
}
fn get_total_supply(&self) -> Result<u64> {
Ok(self.bank().capitalization())
fn get_total_supply(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank(commitment).capitalization())
}
fn get_vote_accounts(&self) -> Result<RpcVoteAccountStatus> {
let bank = self.bank();
fn get_vote_accounts(
&self,
commitment: Option<CommitmentConfig>,
) -> Result<RpcVoteAccountStatus> {
let bank = self.bank(commitment);
let vote_accounts = bank.vote_accounts();
let epoch_vote_accounts = bank
.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> {
Ok(self.bank().slots_per_segment())
fn get_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
Ok(self.bank(commitment).slots_per_segment())
}
fn get_storage_pubkeys_for_slot(&self, slot: Slot) -> Result<Vec<Pubkey>> {
@ -281,139 +306,224 @@ pub trait RpcSol {
type Metadata;
#[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")]
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")]
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")]
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")]
fn get_inflation(&self, _: Self::Metadata) -> Result<Inflation>;
fn get_inflation(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Inflation>;
#[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")]
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")]
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")]
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")]
fn get_block_commitment(
&self,
_: Self::Metadata,
_: u64,
meta: Self::Metadata,
block: u64,
) -> Result<(Option<BlockCommitment>, u64)>;
#[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")]
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")]
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")]
fn get_signature_status(
&self,
_: Self::Metadata,
_: String,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<transaction::Result<()>>>;
#[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")]
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")]
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")]
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")]
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")]
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")]
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")]
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")]
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")]
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")]
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")]
fn validator_exit(&self, _: Self::Metadata) -> Result<bool>;
fn validator_exit(&self, meta: Self::Metadata) -> Result<bool>;
#[rpc(meta, name = "getNumBlocksSinceSignatureConfirmation")]
fn get_num_blocks_since_signature_confirmation(
&self,
_: Self::Metadata,
_: String,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<usize>>;
#[rpc(meta, name = "getSignatureConfirmation")]
fn get_signature_confirmation(
&self,
_: Self::Metadata,
_: String,
meta: Self::Metadata,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<(usize, transaction::Result<()>)>>;
#[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")]
fn set_log_filter(&self, _: Self::Metadata, _: String) -> Result<()>;
fn set_log_filter(&self, _meta: Self::Metadata, filter: String) -> Result<()>;
}
pub struct RpcSolImpl;
impl RpcSol for RpcSolImpl {
type Metadata = Meta;
fn confirm_transaction(&self, meta: Self::Metadata, id: String) -> Result<bool> {
debug!("confirm_transaction rpc request received: {:?}", id);
self.get_signature_status(meta, id).map(|status_option| {
if status_option.is_none() {
return false;
}
status_option.unwrap().is_ok()
})
fn confirm_transaction(
&self,
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() {
return false;
}
status_option.unwrap().is_ok()
})
}
fn get_account_info(&self, meta: Self::Metadata, id: String) -> Result<Account> {
debug!("get_account_info rpc request received: {:?}", id);
let pubkey = verify_pubkey(id)?;
fn get_account_info(
&self,
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
.read()
.unwrap()
.get_account_info(&pubkey)
.get_account_info(&pubkey, commitment)
}
fn get_minimum_balance_for_rent_exemption(
&self,
meta: Self::Metadata,
data_len: usize,
commitment: Option<CommitmentConfig>,
) -> Result<u64> {
debug!(
"get_minimum_balance_for_rent_exemption rpc request received: {:?}",
@ -422,29 +532,37 @@ impl RpcSol for RpcSolImpl {
meta.request_processor
.read()
.unwrap()
.get_minimum_balance_for_rent_exemption(data_len)
.get_minimum_balance_for_rent_exemption(data_len, commitment)
}
fn get_program_accounts(
&self,
meta: Self::Metadata,
id: String,
program_id_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Vec<(String, Account)>> {
debug!("get_program_accounts rpc request received: {:?}", id);
let program_id = verify_pubkey(id)?;
debug!(
"get_program_accounts rpc request received: {:?}",
program_id_str
);
let program_id = verify_pubkey(program_id_str)?;
meta.request_processor
.read()
.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");
Ok(meta
.request_processor
.read()
.unwrap()
.get_inflation()
.get_inflation(commitment)
.unwrap())
}
@ -458,10 +576,19 @@ impl RpcSol for RpcSolImpl {
.unwrap())
}
fn get_balance(&self, meta: Self::Metadata, id: String) -> Result<u64> {
debug!("get_balance rpc request received: {:?}", id);
let pubkey = verify_pubkey(id)?;
Ok(meta.request_processor.read().unwrap().get_balance(&pubkey))
fn get_balance(
&self,
meta: Self::Metadata,
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>> {
@ -491,8 +618,12 @@ impl RpcSol for RpcSolImpl {
.collect())
}
fn get_epoch_info(&self, meta: Self::Metadata) -> Result<RpcEpochInfo> {
let bank = meta.request_processor.read().unwrap().bank();
fn get_epoch_info(
&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, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot());
let slot = bank.slot();
@ -507,7 +638,7 @@ impl RpcSol for RpcSolImpl {
fn get_block_commitment(
&self,
meta: Self::Metadata,
block: u64,
block: Slot,
) -> Result<(Option<BlockCommitment>, u64)> {
Ok(meta
.request_processor
@ -521,8 +652,12 @@ impl RpcSol for RpcSolImpl {
Ok(meta.genesis_blockhash.to_string())
}
fn get_leader_schedule(&self, meta: Self::Metadata) -> Result<Option<Vec<String>>> {
let bank = meta.request_processor.read().unwrap().bank();
fn get_leader_schedule(
&self,
meta: Self::Metadata,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
Ok(
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map(
|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");
Ok(meta
.request_processor
.read()
.unwrap()
.get_recent_blockhash())
.get_recent_blockhash(commitment))
}
fn get_signature_status(
&self,
meta: Self::Metadata,
id: String,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> 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))
}
fn get_slot(&self, meta: Self::Metadata) -> Result<u64> {
meta.request_processor.read().unwrap().get_slot()
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
meta.request_processor.read().unwrap().get_slot(commitment)
}
fn get_num_blocks_since_signature_confirmation(
&self,
meta: Self::Metadata,
id: String,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<usize>> {
self.get_signature_confirmation(meta, id)
self.get_signature_confirmation(meta, signature_str, commitment)
.map(|res| res.map(|x| x.0))
}
fn get_signature_confirmation(
&self,
meta: Self::Metadata,
id: String,
signature_str: String,
commitment: Option<CommitmentConfig>,
) -> Result<Option<(usize, transaction::Result<()>)>> {
debug!("get_signature_confirmation rpc request received: {:?}", id);
let signature = verify_signature(&id)?;
debug!(
"get_signature_confirmation rpc request received: {:?}",
signature_str
);
let signature = verify_signature(&signature_str)?;
Ok(meta
.request_processor
.read()
.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");
meta.request_processor
.read()
.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");
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> {
trace!("request_airdrop id={} lamports={}", id, lamports);
fn request_airdrop(
&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
.request_processor
@ -604,13 +766,13 @@ impl RpcSol for RpcSolImpl {
.config
.drone_addr
.ok_or_else(Error::invalid_request)?;
let pubkey = verify_pubkey(id)?;
let pubkey = verify_pubkey(pubkey_str)?;
let blockhash = meta
.request_processor
.read()
.unwrap()
.bank()
.bank(commitment.clone())
.confirmed_last_blockhash()
.0;
let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash)
@ -641,7 +803,8 @@ impl RpcSol for RpcSolImpl {
.request_processor
.read()
.unwrap()
.get_signature_status(signature);
.get_signature_confirmation_status(signature, commitment.clone())
.map(|x| x.1);
if signature_status == Some(Ok(())) {
info!("airdrop signature ok");
@ -689,12 +852,26 @@ impl RpcSol for RpcSolImpl {
Ok(signature)
}
fn get_slot_leader(&self, meta: Self::Metadata) -> Result<String> {
meta.request_processor.read().unwrap().get_slot_leader()
fn 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> {
meta.request_processor.read().unwrap().get_vote_accounts()
fn 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> {
@ -708,11 +885,15 @@ impl RpcSol for RpcSolImpl {
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
.read()
.unwrap()
.get_slots_per_segment()
.get_slots_per_segment(commitment)
}
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);
Ok(())
}
@ -863,7 +1044,7 @@ pub mod tests {
})
.join()
.unwrap();
assert_eq!(request_processor.get_transaction_count().unwrap(), 1);
assert_eq!(request_processor.get_transaction_count(None).unwrap(), 1);
}
#[test]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,14 +15,15 @@ use solana_runtime::accounts_db::AccountsDB;
use solana_sdk::{
client::SyncClient,
clock,
commitment_config::CommitmentConfig,
epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH},
genesis_block::OperatingMode,
poh_config::PohConfig,
};
use std::path::{Path, PathBuf};
use std::{
collections::{HashMap, HashSet},
fs,
path::{Path, PathBuf},
thread::sleep,
time::Duration,
};
@ -329,7 +330,12 @@ fn test_softlaunch_operating_mode() {
.iter()
{
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)
);
}
@ -460,7 +466,7 @@ fn test_snapshots_blocktree_floor() {
let target_slot = slot_floor + 40;
while current_slot <= target_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;
} else {
continue;
@ -751,7 +757,7 @@ fn run_repairman_catchup(num_repairmen: u64) {
let target_slot = (num_warmup_epochs) * num_slots_per_epoch + 1;
while current_slot <= target_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;
} else {
continue;
@ -765,7 +771,9 @@ fn wait_for_next_snapshot<P: AsRef<Path>>(cluster: &LocalCluster, tar: P) {
let client = cluster
.get_validator_client(&cluster.entry_point_info.id)
.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
// must include the transactions just pushed

View File

@ -1,22 +1,27 @@
use crate::bank::Bank;
use solana_sdk::account::Account;
use solana_sdk::client::{AsyncClient, Client, SyncClient};
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::hash::Hash;
use solana_sdk::instruction::Instruction;
use solana_sdk::message::Message;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Signature;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use solana_sdk::transaction::{self, Transaction};
use solana_sdk::transport::{Result, TransportError};
use std::io;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Arc;
use std::sync::Mutex;
use std::thread::{sleep, Builder};
use std::time::{Duration, Instant};
use solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil, Signature},
system_instruction,
transaction::{self, Transaction},
transport::{Result, TransportError},
};
use std::{
io,
sync::{
mpsc::{channel, Receiver, Sender},
Arc, Mutex,
},
thread::{sleep, Builder},
time::{Duration, Instant},
};
pub struct BankClient {
bank: Arc<Bank>,
@ -100,14 +105,37 @@ impl SyncClient for BankClient {
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> {
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)> {
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(
&self,
signature: &Signature,
@ -115,14 +143,33 @@ impl SyncClient for BankClient {
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> {
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> {
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(
&self,
signature: &Signature,

View File

@ -10,6 +10,7 @@
use crate::{
account::Account,
clock::Slot,
commitment_config::CommitmentConfig,
fee_calculator::FeeCalculator,
hash::Hash,
instruction::Instruction,
@ -44,24 +45,60 @@ pub trait SyncClient {
/// Get an account or None if not found.
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.
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
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.
fn get_signature_status(
&self,
signature: &Signature,
) -> 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
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
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`
fn poll_for_signature_confirmation(
&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"))]
pub mod client;
#[cfg(not(feature = "program"))]
pub mod commitment_config;
#[cfg(not(feature = "program"))]
pub mod genesis_block;
#[cfg(not(feature = "program"))]
pub mod packet;