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

* Name anonymous parameters for clarity

* Add CommitmentConfig to select bank for rpc

* Add commitment information to jsonrpc docs

* Update send_and_confirm retries as per commitment defaults

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

* Use _with_commitment methods to speed local_cluster tests

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

* Restore solana ping speed

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

View File

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