From 8dd5ec6fbdd6a5c94cc192889c2ed5fc02c8c8ac Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 06:28:11 +0000 Subject: [PATCH] refactor(rpc_client): const number of retries for send and confirm transaction (#18390) (#18427) * refactor(rpc_client): simplfy send and confirm transaction flow * chore: configurable num of retries for send and confirm (cherry picked from commit 70234dfdf4bab7c3451e6eceb3e93d2e4feefe03) Co-authored-by: hrls --- client/src/rpc_client.rs | 86 +++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 3ea8cdd75d..05223bd929 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -1012,49 +1012,55 @@ impl RpcClient { &self, transaction: &Transaction, ) -> ClientResult { - let signature = self.send_transaction(transaction)?; - let recent_blockhash = if uses_durable_nonce(transaction).is_some() { - self.get_recent_blockhash_with_commitment(CommitmentConfig::processed())? - .value - .0 - } else { - transaction.message.recent_blockhash - }; - let status = loop { - let status = self.get_signature_status(&signature)?; - if status.is_none() { - if self - .get_fee_calculator_for_blockhash_with_commitment( - &recent_blockhash, - CommitmentConfig::processed(), - )? - .value - .is_none() - { - break status; - } + const SEND_RETRIES: usize = 1; + const GET_STATUS_RETRIES: usize = usize::MAX; + + 'sending: for _ in 0..SEND_RETRIES { + let signature = self.send_transaction(transaction)?; + + let recent_blockhash = if uses_durable_nonce(transaction).is_some() { + let (recent_blockhash, ..) = self + .get_recent_blockhash_with_commitment(CommitmentConfig::processed())? + .value; + recent_blockhash } else { - break status; + transaction.message.recent_blockhash + }; + + for status_retry in 0..GET_STATUS_RETRIES { + match self.get_signature_status(&signature)? { + Some(Ok(_)) => return Ok(signature), + Some(Err(e)) => return Err(e.into()), + None => { + let fee_calculator = self + .get_fee_calculator_for_blockhash_with_commitment( + &recent_blockhash, + CommitmentConfig::processed(), + )? + .value; + if fee_calculator.is_none() { + // Block hash is not found by some reason + break 'sending; + } else if cfg!(not(test)) + // Ignore sleep at last step. + && status_retry < GET_STATUS_RETRIES + { + // Retry twice a second + sleep(Duration::from_millis(500)); + continue; + } + } + } } - if cfg!(not(test)) { - // Retry twice a second - sleep(Duration::from_millis(500)); - } - }; - if let Some(result) = status { - match result { - Ok(_) => Ok(signature), - Err(err) => Err(err.into()), - } - } else { - Err(RpcError::ForUser( - "unable to confirm transaction. \ - This can happen in situations such as transaction expiration \ - and insufficient fee-payer funds" - .to_string(), - ) - .into()) } + + Err(RpcError::ForUser( + "unable to confirm transaction. \ + This can happen in situations such as transaction expiration \ + and insufficient fee-payer funds" + .to_string(), + ) + .into()) } /// Note that `get_account` returns `Err(..)` if the account does not exist whereas