Clean up RPCClient retry handling: only retry on 429, after a little sleep (#10182)
This commit is contained in:
parent
c7cdbc98e5
commit
4779858dd4
|
@ -4,8 +4,7 @@ use crate::{
|
||||||
rpc_sender::RpcSender,
|
rpc_sender::RpcSender,
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
use reqwest::{self, header::CONTENT_TYPE};
|
use reqwest::{self, header::CONTENT_TYPE, StatusCode};
|
||||||
use solana_sdk::clock::{DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT};
|
|
||||||
use std::{thread::sleep, time::Duration};
|
use std::{thread::sleep, time::Duration};
|
||||||
|
|
||||||
pub struct HttpSender {
|
pub struct HttpSender {
|
||||||
|
@ -29,17 +28,13 @@ impl HttpSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcSender for HttpSender {
|
impl RpcSender for HttpSender {
|
||||||
fn send(
|
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
|
||||||
&self,
|
|
||||||
request: RpcRequest,
|
|
||||||
params: serde_json::Value,
|
|
||||||
mut retries: usize,
|
|
||||||
) -> Result<serde_json::Value> {
|
|
||||||
// Concurrent requests are not supported so reuse the same request id for all requests
|
// Concurrent requests are not supported so reuse the same request id for all requests
|
||||||
let request_id = 1;
|
let request_id = 1;
|
||||||
|
|
||||||
let request_json = request.build_request_json(request_id, params);
|
let request_json = request.build_request_json(request_id, params);
|
||||||
|
|
||||||
|
let mut too_many_requests_retries = 5;
|
||||||
loop {
|
loop {
|
||||||
match self
|
match self
|
||||||
.client
|
.client
|
||||||
|
@ -50,6 +45,19 @@ impl RpcSender for HttpSender {
|
||||||
{
|
{
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
if !response.status().is_success() {
|
if !response.status().is_success() {
|
||||||
|
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
||||||
|
&& too_many_requests_retries > 0
|
||||||
|
{
|
||||||
|
too_many_requests_retries -= 1;
|
||||||
|
debug!(
|
||||||
|
"Server responded with {:?}, {} retries left",
|
||||||
|
response, too_many_requests_retries
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sleep for 500ms to give the server a break
|
||||||
|
sleep(Duration::from_millis(500));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return Err(response.error_for_status().unwrap_err().into());
|
return Err(response.error_for_status().unwrap_err().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,17 +71,8 @@ impl RpcSender for HttpSender {
|
||||||
}
|
}
|
||||||
return Ok(json["result"].clone());
|
return Ok(json["result"].clone());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(err) => {
|
||||||
info!("{:?} failed, {} retries left: {:?}", request, retries, e);
|
return Err(err.into());
|
||||||
if retries == 0 {
|
|
||||||
return Err(e.into());
|
|
||||||
}
|
|
||||||
retries -= 1;
|
|
||||||
|
|
||||||
// Sleep for approximately half a slot
|
|
||||||
sleep(Duration::from_millis(
|
|
||||||
500 * DEFAULT_TICKS_PER_SLOT / DEFAULT_TICKS_PER_SECOND,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,7 @@ impl MockSender {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcSender for MockSender {
|
impl RpcSender for MockSender {
|
||||||
fn send(
|
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
|
||||||
&self,
|
|
||||||
request: RpcRequest,
|
|
||||||
params: serde_json::Value,
|
|
||||||
_retries: usize,
|
|
||||||
) -> Result<serde_json::Value> {
|
|
||||||
if let Some(value) = self.mocks.write().unwrap().remove(&request) {
|
if let Some(value) = self.mocks.write().unwrap().remove(&request) {
|
||||||
return Ok(value);
|
return Ok(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ impl RpcClient {
|
||||||
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
let serialized_encoded = bs58::encode(serialize(transaction).unwrap()).into_string();
|
||||||
|
|
||||||
let signature_base58_str: String =
|
let signature_base58_str: String =
|
||||||
self.send(RpcRequest::SendTransaction, json!([serialized_encoded]), 5)?;
|
self.send(RpcRequest::SendTransaction, json!([serialized_encoded]))?;
|
||||||
|
|
||||||
let signature = signature_base58_str
|
let signature = signature_base58_str
|
||||||
.parse::<Signature>()
|
.parse::<Signature>()
|
||||||
|
@ -127,7 +127,6 @@ impl RpcClient {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::SimulateTransaction,
|
RpcRequest::SimulateTransaction,
|
||||||
json!([serialized_encoded, { "sigVerify": sig_verify }]),
|
json!([serialized_encoded, { "sigVerify": sig_verify }]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +142,7 @@ impl RpcClient {
|
||||||
signatures: &[Signature],
|
signatures: &[Signature],
|
||||||
) -> RpcResult<Vec<Option<TransactionStatus>>> {
|
) -> RpcResult<Vec<Option<TransactionStatus>>> {
|
||||||
let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
|
let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
|
||||||
self.send(RpcRequest::GetSignatureStatuses, json!([signatures]), 5)
|
self.send(RpcRequest::GetSignatureStatuses, json!([signatures]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_signature_status_with_commitment(
|
pub fn get_signature_status_with_commitment(
|
||||||
|
@ -154,7 +153,6 @@ impl RpcClient {
|
||||||
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
||||||
RpcRequest::GetSignatureStatuses,
|
RpcRequest::GetSignatureStatuses,
|
||||||
json!([[signature.to_string()]]),
|
json!([[signature.to_string()]]),
|
||||||
5,
|
|
||||||
)?;
|
)?;
|
||||||
Ok(result.value[0]
|
Ok(result.value[0]
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -173,7 +171,6 @@ impl RpcClient {
|
||||||
json!([[signature.to_string()], {
|
json!([[signature.to_string()], {
|
||||||
"searchTransactionHistory": search_transaction_history
|
"searchTransactionHistory": search_transaction_history
|
||||||
}]),
|
}]),
|
||||||
5,
|
|
||||||
)?;
|
)?;
|
||||||
Ok(result.value[0]
|
Ok(result.value[0]
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -189,14 +186,14 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<Slot> {
|
) -> ClientResult<Slot> {
|
||||||
self.send(RpcRequest::GetSlot, json!([commitment_config]), 0)
|
self.send(RpcRequest::GetSlot, json!([commitment_config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn supply_with_commitment(
|
pub fn supply_with_commitment(
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> RpcResult<RpcSupply> {
|
) -> RpcResult<RpcSupply> {
|
||||||
self.send(RpcRequest::GetSupply, json!([commitment_config]), 0)
|
self.send(RpcRequest::GetSupply, json!([commitment_config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn total_supply(&self) -> ClientResult<u64> {
|
pub fn total_supply(&self) -> ClientResult<u64> {
|
||||||
|
@ -207,14 +204,14 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<u64> {
|
) -> ClientResult<u64> {
|
||||||
self.send(RpcRequest::GetTotalSupply, json!([commitment_config]), 0)
|
self.send(RpcRequest::GetTotalSupply, json!([commitment_config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_largest_accounts_with_config(
|
pub fn get_largest_accounts_with_config(
|
||||||
&self,
|
&self,
|
||||||
config: RpcLargestAccountsConfig,
|
config: RpcLargestAccountsConfig,
|
||||||
) -> RpcResult<Vec<RpcAccountBalance>> {
|
) -> RpcResult<Vec<RpcAccountBalance>> {
|
||||||
self.send(RpcRequest::GetLargestAccounts, json!([config]), 0)
|
self.send(RpcRequest::GetLargestAccounts, json!([config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
|
pub fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
|
||||||
|
@ -225,11 +222,11 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<RpcVoteAccountStatus> {
|
) -> ClientResult<RpcVoteAccountStatus> {
|
||||||
self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]), 0)
|
self.send(RpcRequest::GetVoteAccounts, json!([commitment_config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
|
pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
|
||||||
self.send(RpcRequest::GetClusterNodes, Value::Null, 0)
|
self.send(RpcRequest::GetClusterNodes, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
pub fn get_confirmed_block(&self, slot: Slot) -> ClientResult<ConfirmedBlock> {
|
||||||
|
@ -241,7 +238,7 @@ impl RpcClient {
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
encoding: TransactionEncoding,
|
encoding: TransactionEncoding,
|
||||||
) -> ClientResult<ConfirmedBlock> {
|
) -> ClientResult<ConfirmedBlock> {
|
||||||
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]), 0)
|
self.send(RpcRequest::GetConfirmedBlock, json!([slot, encoding]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_confirmed_blocks(
|
pub fn get_confirmed_blocks(
|
||||||
|
@ -252,7 +249,6 @@ impl RpcClient {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetConfirmedBlocks,
|
RpcRequest::GetConfirmedBlocks,
|
||||||
json!([start_slot, end_slot]),
|
json!([start_slot, end_slot]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +261,6 @@ impl RpcClient {
|
||||||
let signatures_base58_str: Vec<String> = self.send(
|
let signatures_base58_str: Vec<String> = self.send(
|
||||||
RpcRequest::GetConfirmedSignaturesForAddress,
|
RpcRequest::GetConfirmedSignaturesForAddress,
|
||||||
json!([address.to_string(), start_slot, end_slot]),
|
json!([address.to_string(), start_slot, end_slot]),
|
||||||
0,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut signatures = vec![];
|
let mut signatures = vec![];
|
||||||
|
@ -287,13 +282,12 @@ impl RpcClient {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetConfirmedTransaction,
|
RpcRequest::GetConfirmedTransaction,
|
||||||
json!([signature.to_string(), encoding]),
|
json!([signature.to_string(), encoding]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
|
pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
|
||||||
let request = RpcRequest::GetBlockTime;
|
let request = RpcRequest::GetBlockTime;
|
||||||
let response = self.sender.send(request, json!([slot]), 0);
|
let response = self.sender.send(request, json!([slot]));
|
||||||
|
|
||||||
response
|
response
|
||||||
.map(|result_json| {
|
.map(|result_json| {
|
||||||
|
@ -316,7 +310,7 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<EpochInfo> {
|
) -> ClientResult<EpochInfo> {
|
||||||
self.send(RpcRequest::GetEpochInfo, json!([commitment_config]), 0)
|
self.send(RpcRequest::GetEpochInfo, json!([commitment_config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_leader_schedule(
|
pub fn get_leader_schedule(
|
||||||
|
@ -334,16 +328,15 @@ impl RpcClient {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetLeaderSchedule,
|
RpcRequest::GetLeaderSchedule,
|
||||||
json!([slot, commitment_config]),
|
json!([slot, commitment_config]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
|
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
|
||||||
self.send(RpcRequest::GetEpochSchedule, Value::Null, 0)
|
self.send(RpcRequest::GetEpochSchedule, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_identity(&self) -> ClientResult<Pubkey> {
|
pub fn get_identity(&self) -> ClientResult<Pubkey> {
|
||||||
let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null, 0)?;
|
let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null)?;
|
||||||
|
|
||||||
rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
|
rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
|
||||||
ClientError::new_with_request(
|
ClientError::new_with_request(
|
||||||
|
@ -354,15 +347,15 @@ impl RpcClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_inflation(&self) -> ClientResult<Inflation> {
|
pub fn get_inflation(&self) -> ClientResult<Inflation> {
|
||||||
self.send(RpcRequest::GetInflation, Value::Null, 0)
|
self.send(RpcRequest::GetInflation, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_version(&self) -> ClientResult<RpcVersionInfo> {
|
pub fn get_version(&self) -> ClientResult<RpcVersionInfo> {
|
||||||
self.send(RpcRequest::GetVersion, Value::Null, 0)
|
self.send(RpcRequest::GetVersion, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
|
pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
|
||||||
self.send(RpcRequest::MinimumLedgerSlot, Value::Null, 0)
|
self.send(RpcRequest::MinimumLedgerSlot, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_and_confirm_transaction(
|
pub fn send_and_confirm_transaction(
|
||||||
|
@ -525,7 +518,6 @@ impl RpcClient {
|
||||||
let response = self.sender.send(
|
let response = self.sender.send(
|
||||||
RpcRequest::GetAccountInfo,
|
RpcRequest::GetAccountInfo,
|
||||||
json!([pubkey.to_string(), commitment_config]),
|
json!([pubkey.to_string(), commitment_config]),
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
response
|
response
|
||||||
|
@ -562,7 +554,7 @@ impl RpcClient {
|
||||||
let request = RpcRequest::GetMinimumBalanceForRentExemption;
|
let request = RpcRequest::GetMinimumBalanceForRentExemption;
|
||||||
let minimum_balance_json = self
|
let minimum_balance_json = self
|
||||||
.sender
|
.sender
|
||||||
.send(request, json!([data_len]), 0)
|
.send(request, json!([data_len]))
|
||||||
.map_err(|err| err.into_with_request(request))?;
|
.map_err(|err| err.into_with_request(request))?;
|
||||||
|
|
||||||
let minimum_balance: u64 = serde_json::from_value(minimum_balance_json)
|
let minimum_balance: u64 = serde_json::from_value(minimum_balance_json)
|
||||||
|
@ -590,16 +582,12 @@ impl RpcClient {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetBalance,
|
RpcRequest::GetBalance,
|
||||||
json!([pubkey.to_string(), commitment_config]),
|
json!([pubkey.to_string(), commitment_config]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> {
|
pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> {
|
||||||
let accounts: Vec<RpcKeyedAccount> = self.send(
|
let accounts: Vec<RpcKeyedAccount> =
|
||||||
RpcRequest::GetProgramAccounts,
|
self.send(RpcRequest::GetProgramAccounts, json!([pubkey.to_string()]))?;
|
||||||
json!([pubkey.to_string()]),
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new();
|
let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::new();
|
||||||
for RpcKeyedAccount { pubkey, account } in accounts.into_iter() {
|
for RpcKeyedAccount { pubkey, account } in accounts.into_iter() {
|
||||||
let pubkey = pubkey.parse().map_err(|_| {
|
let pubkey = pubkey.parse().map_err(|_| {
|
||||||
|
@ -622,11 +610,7 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<u64> {
|
) -> ClientResult<u64> {
|
||||||
self.send(
|
self.send(RpcRequest::GetTransactionCount, json!([commitment_config]))
|
||||||
RpcRequest::GetTransactionCount,
|
|
||||||
json!([commitment_config]),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> {
|
pub fn get_recent_blockhash(&self) -> ClientResult<(Hash, FeeCalculator)> {
|
||||||
|
@ -649,7 +633,6 @@ impl RpcClient {
|
||||||
} = self.send::<Response<RpcBlockhashFeeCalculator>>(
|
} = self.send::<Response<RpcBlockhashFeeCalculator>>(
|
||||||
RpcRequest::GetRecentBlockhash,
|
RpcRequest::GetRecentBlockhash,
|
||||||
json!([commitment_config]),
|
json!([commitment_config]),
|
||||||
0,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let blockhash = blockhash.parse().map_err(|_| {
|
let blockhash = blockhash.parse().map_err(|_| {
|
||||||
|
@ -671,7 +654,6 @@ impl RpcClient {
|
||||||
let Response { value, .. } = self.send::<Response<Option<RpcFeeCalculator>>>(
|
let Response { value, .. } = self.send::<Response<Option<RpcFeeCalculator>>>(
|
||||||
RpcRequest::GetFeeCalculatorForBlockhash,
|
RpcRequest::GetFeeCalculatorForBlockhash,
|
||||||
json!([blockhash.to_string()]),
|
json!([blockhash.to_string()]),
|
||||||
0,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(value.map(|rf| rf.fee_calculator))
|
Ok(value.map(|rf| rf.fee_calculator))
|
||||||
|
@ -681,11 +663,8 @@ impl RpcClient {
|
||||||
let Response {
|
let Response {
|
||||||
context,
|
context,
|
||||||
value: RpcFeeRateGovernor { fee_rate_governor },
|
value: RpcFeeRateGovernor { fee_rate_governor },
|
||||||
} = self.send::<Response<RpcFeeRateGovernor>>(
|
} =
|
||||||
RpcRequest::GetFeeRateGovernor,
|
self.send::<Response<RpcFeeRateGovernor>>(RpcRequest::GetFeeRateGovernor, Value::Null)?;
|
||||||
Value::Null,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
context,
|
context,
|
||||||
|
@ -720,7 +699,7 @@ impl RpcClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_genesis_hash(&self) -> ClientResult<Hash> {
|
pub fn get_genesis_hash(&self) -> ClientResult<Hash> {
|
||||||
let hash_str: String = self.send(RpcRequest::GetGenesisHash, Value::Null, 0)?;
|
let hash_str: String = self.send(RpcRequest::GetGenesisHash, Value::Null)?;
|
||||||
let hash = hash_str.parse().map_err(|_| {
|
let hash = hash_str.parse().map_err(|_| {
|
||||||
ClientError::new_with_request(
|
ClientError::new_with_request(
|
||||||
RpcError::ParseError("Hash".to_string()).into(),
|
RpcError::ParseError("Hash".to_string()).into(),
|
||||||
|
@ -916,7 +895,6 @@ impl RpcClient {
|
||||||
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
let result: Response<Vec<Option<TransactionStatus>>> = self.send(
|
||||||
RpcRequest::GetSignatureStatuses,
|
RpcRequest::GetSignatureStatuses,
|
||||||
json!([[signature.to_string()]]),
|
json!([[signature.to_string()]]),
|
||||||
5,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let confirmations = result.value[0]
|
let confirmations = result.value[0]
|
||||||
|
@ -1028,17 +1006,17 @@ impl RpcClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validator_exit(&self) -> ClientResult<bool> {
|
pub fn validator_exit(&self) -> ClientResult<bool> {
|
||||||
self.send(RpcRequest::ValidatorExit, Value::Null, 0)
|
self.send(RpcRequest::ValidatorExit, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send<T>(&self, request: RpcRequest, params: Value, retries: usize) -> ClientResult<T>
|
pub fn send<T>(&self, request: RpcRequest, params: Value) -> ClientResult<T>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
assert!(params.is_array() || params.is_null());
|
assert!(params.is_array() || params.is_null());
|
||||||
let response = self
|
let response = self
|
||||||
.sender
|
.sender
|
||||||
.send(request, params, retries)
|
.send(request, params)
|
||||||
.map_err(|err| err.into_with_request(request))?;
|
.map_err(|err| err.into_with_request(request))?;
|
||||||
serde_json::from_value(response)
|
serde_json::from_value(response)
|
||||||
.map_err(|err| ClientError::new_with_request(err.into(), request))
|
.map_err(|err| ClientError::new_with_request(err.into(), request))
|
||||||
|
@ -1114,62 +1092,21 @@ mod tests {
|
||||||
.send(
|
.send(
|
||||||
RpcRequest::GetBalance,
|
RpcRequest::GetBalance,
|
||||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
|
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
|
||||||
0,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(balance, 50);
|
assert_eq!(balance, 50);
|
||||||
|
|
||||||
let blockhash: String = rpc_client
|
let blockhash: String = rpc_client
|
||||||
.send(RpcRequest::GetRecentBlockhash, Value::Null, 0)
|
.send(RpcRequest::GetRecentBlockhash, Value::Null)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(blockhash, "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
|
assert_eq!(blockhash, "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
|
||||||
|
|
||||||
// Send erroneous parameter
|
// Send erroneous parameter
|
||||||
let blockhash: ClientResult<String> =
|
let blockhash: ClientResult<String> =
|
||||||
rpc_client.send(RpcRequest::GetRecentBlockhash, json!(["parameter"]), 0);
|
rpc_client.send(RpcRequest::GetRecentBlockhash, json!(["parameter"]));
|
||||||
assert_eq!(blockhash.is_err(), true);
|
assert_eq!(blockhash.is_err(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_retry_send() {
|
|
||||||
solana_logger::setup();
|
|
||||||
let (sender, receiver) = channel();
|
|
||||||
thread::spawn(move || {
|
|
||||||
// 1. Pick a random port
|
|
||||||
// 2. Tell the sender to start using it
|
|
||||||
// 3. Delay for 1.5 seconds before starting the server to ensure the sender will fail
|
|
||||||
// and need to retry
|
|
||||||
let rpc_addr: SocketAddr = "0.0.0.0:4242".parse().unwrap();
|
|
||||||
sender.send(rpc_addr.clone()).unwrap();
|
|
||||||
sleep(Duration::from_millis(1500));
|
|
||||||
|
|
||||||
let mut io = IoHandler::default();
|
|
||||||
io.add_method("getBalance", move |_params: Params| {
|
|
||||||
Ok(Value::Number(Number::from(5)))
|
|
||||||
});
|
|
||||||
let server = ServerBuilder::new(io)
|
|
||||||
.threads(1)
|
|
||||||
.cors(DomainsValidation::AllowOnly(vec![
|
|
||||||
AccessControlAllowOrigin::Any,
|
|
||||||
]))
|
|
||||||
.start_http(&rpc_addr)
|
|
||||||
.expect("Unable to start RPC server");
|
|
||||||
server.wait();
|
|
||||||
});
|
|
||||||
|
|
||||||
let rpc_addr = receiver.recv().unwrap();
|
|
||||||
let rpc_client = RpcClient::new_socket(rpc_addr);
|
|
||||||
|
|
||||||
let balance: u64 = rpc_client
|
|
||||||
.send(
|
|
||||||
RpcRequest::GetBalance,
|
|
||||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhw"]),
|
|
||||||
10,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(balance, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_send_transaction() {
|
fn test_send_transaction() {
|
||||||
let rpc_client = RpcClient::new_mock("succeeds".to_string());
|
let rpc_client = RpcClient::new_mock("succeeds".to_string());
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
use crate::{client_error::Result, rpc_request::RpcRequest};
|
use crate::{client_error::Result, rpc_request::RpcRequest};
|
||||||
|
|
||||||
pub trait RpcSender {
|
pub trait RpcSender {
|
||||||
fn send(
|
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value>;
|
||||||
&self,
|
|
||||||
request: RpcRequest,
|
|
||||||
params: serde_json::Value,
|
|
||||||
retries: usize,
|
|
||||||
) -> Result<serde_json::Value>;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue