diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index c5b906595..a6e9d2c9d 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -443,10 +443,9 @@ impl RpcClient { &self, signature: &Signature, min_confirmed_blocks: usize, - ) -> io::Result<()> { + ) -> io::Result { let mut now = Instant::now(); let mut confirmed_blocks = 0; - let mut wait_time = 15; loop { let response = self.get_num_blocks_since_signature_confirmation(signature); match response { @@ -461,12 +460,6 @@ impl RpcClient { ); now = Instant::now(); confirmed_blocks = count; - // If the signature has been confirmed once, wait extra while reconfirming it - // One confirmation means the transaction has been seen by the network, so - // next confirmation (for a higher block count) should come through. - // Returning an error prematurely will cause a valid transaction to be deemed - // as failure. - wait_time = 30; } if count >= min_confirmed_blocks { break; @@ -476,7 +469,7 @@ impl RpcClient { debug!("check_confirmations request failed: {:?}", err); } }; - if now.elapsed().as_secs() > wait_time { + if now.elapsed().as_secs() > 15 { info!( "signature {} confirmed {} out of {} failed after {} ms", signature, @@ -484,12 +477,16 @@ impl RpcClient { min_confirmed_blocks, now.elapsed().as_millis() ); - // TODO: Return a better error. - return Err(io::Error::new(io::ErrorKind::Other, "signature not found")); + if confirmed_blocks > 0 { + return Ok(confirmed_blocks); + } else { + // TODO: Return a better error. + return Err(io::Error::new(io::ErrorKind::Other, "signature not found")); + } } sleep(Duration::from_secs(1)); } - Ok(()) + Ok(confirmed_blocks) } pub fn get_num_blocks_since_signature_confirmation( diff --git a/client/src/thin_client.rs b/client/src/thin_client.rs index 2eb0aded1..c4f6b1e63 100644 --- a/client/src/thin_client.rs +++ b/client/src/thin_client.rs @@ -203,26 +203,38 @@ impl ThinClient { keypairs: &[&Keypair], transaction: &mut Transaction, tries: usize, - min_confirmed_blocks: usize, + pending_confirmations: usize, ) -> io::Result { for x in 0..tries { let now = Instant::now(); let mut buf = vec![0; serialized_size(&transaction).unwrap() as usize]; let mut wr = std::io::Cursor::new(&mut buf[..]); + let mut num_confirmed = 0; + let mut wait_time = MAX_PROCESSING_AGE; serialize_into(&mut wr, &transaction) .expect("serialize Transaction in pub fn transfer_signed"); // resend the same transaction until the transaction has no chance of succeeding - while now.elapsed().as_secs() < MAX_PROCESSING_AGE as u64 { - self.transactions_socket - .send_to(&buf[..], &self.transactions_addr())?; - if self - .poll_for_signature_confirmation( - &transaction.signatures[0], - min_confirmed_blocks, - ) - .is_ok() - { - return Ok(transaction.signatures[0]); + while now.elapsed().as_secs() < wait_time as u64 { + if num_confirmed == 0 { + // Send the transaction if there has been no confirmation (e.g. the first time) + self.transactions_socket + .send_to(&buf[..], &self.transactions_addr())?; + } + + if let Ok(confirmed_blocks) = self.poll_for_signature_confirmation( + &transaction.signatures[0], + pending_confirmations, + ) { + num_confirmed = confirmed_blocks; + if confirmed_blocks >= pending_confirmations { + return Ok(transaction.signatures[0]); + } + // Since network has seen the transaction, wait longer to receive + // all pending confirmations. Resending the transaction could result into + // extra transaction fees + wait_time = wait_time.max( + MAX_PROCESSING_AGE * pending_confirmations.saturating_sub(num_confirmed), + ); } } info!( @@ -385,7 +397,7 @@ impl SyncClient for ThinClient { &self, signature: &Signature, min_confirmed_blocks: usize, - ) -> TransportResult<()> { + ) -> TransportResult { Ok(self .rpc_client() .poll_for_signature_confirmation(signature, min_confirmed_blocks)?) diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index a6ea0e7a2..95400e74e 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -127,7 +127,7 @@ impl SyncClient for BankClient { &self, signature: &Signature, min_confirmed_blocks: usize, - ) -> Result<()> { + ) -> Result { let mut now = Instant::now(); let mut confirmed_blocks = 0; loop { @@ -152,7 +152,7 @@ impl SyncClient for BankClient { } sleep(Duration::from_millis(250)); } - Ok(()) + Ok(confirmed_blocks) } fn poll_for_signature(&self, signature: &Signature) -> Result<()> { diff --git a/sdk/src/client.rs b/sdk/src/client.rs index 92e1ad6ad..67e6586fb 100644 --- a/sdk/src/client.rs +++ b/sdk/src/client.rs @@ -64,7 +64,7 @@ pub trait SyncClient { &self, signature: &Signature, min_confirmed_blocks: usize, - ) -> Result<()>; + ) -> Result; /// Poll to confirm a transaction. fn poll_for_signature(&self, signature: &Signature) -> Result<()>;