Fix issue in polling for transaction signatures (#4923)
- Specifically if multiple confirmation for the signature is requested
This commit is contained in:
@ -443,10 +443,9 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
min_confirmed_blocks: usize,
|
min_confirmed_blocks: usize,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<usize> {
|
||||||
let mut now = Instant::now();
|
let mut now = Instant::now();
|
||||||
let mut confirmed_blocks = 0;
|
let mut confirmed_blocks = 0;
|
||||||
let mut wait_time = 15;
|
|
||||||
loop {
|
loop {
|
||||||
let response = self.get_num_blocks_since_signature_confirmation(signature);
|
let response = self.get_num_blocks_since_signature_confirmation(signature);
|
||||||
match response {
|
match response {
|
||||||
@ -461,12 +460,6 @@ impl RpcClient {
|
|||||||
);
|
);
|
||||||
now = Instant::now();
|
now = Instant::now();
|
||||||
confirmed_blocks = count;
|
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 {
|
if count >= min_confirmed_blocks {
|
||||||
break;
|
break;
|
||||||
@ -476,7 +469,7 @@ impl RpcClient {
|
|||||||
debug!("check_confirmations request failed: {:?}", err);
|
debug!("check_confirmations request failed: {:?}", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if now.elapsed().as_secs() > wait_time {
|
if now.elapsed().as_secs() > 15 {
|
||||||
info!(
|
info!(
|
||||||
"signature {} confirmed {} out of {} failed after {} ms",
|
"signature {} confirmed {} out of {} failed after {} ms",
|
||||||
signature,
|
signature,
|
||||||
@ -484,12 +477,16 @@ impl RpcClient {
|
|||||||
min_confirmed_blocks,
|
min_confirmed_blocks,
|
||||||
now.elapsed().as_millis()
|
now.elapsed().as_millis()
|
||||||
);
|
);
|
||||||
// TODO: Return a better error.
|
if confirmed_blocks > 0 {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "signature not found"));
|
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));
|
sleep(Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(confirmed_blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_num_blocks_since_signature_confirmation(
|
pub fn get_num_blocks_since_signature_confirmation(
|
||||||
|
@ -203,26 +203,38 @@ impl ThinClient {
|
|||||||
keypairs: &[&Keypair],
|
keypairs: &[&Keypair],
|
||||||
transaction: &mut Transaction,
|
transaction: &mut Transaction,
|
||||||
tries: usize,
|
tries: usize,
|
||||||
min_confirmed_blocks: usize,
|
pending_confirmations: usize,
|
||||||
) -> io::Result<Signature> {
|
) -> io::Result<Signature> {
|
||||||
for x in 0..tries {
|
for x in 0..tries {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let mut buf = vec![0; serialized_size(&transaction).unwrap() as usize];
|
let mut buf = vec![0; serialized_size(&transaction).unwrap() as usize];
|
||||||
let mut wr = std::io::Cursor::new(&mut buf[..]);
|
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)
|
serialize_into(&mut wr, &transaction)
|
||||||
.expect("serialize Transaction in pub fn transfer_signed");
|
.expect("serialize Transaction in pub fn transfer_signed");
|
||||||
// resend the same transaction until the transaction has no chance of succeeding
|
// resend the same transaction until the transaction has no chance of succeeding
|
||||||
while now.elapsed().as_secs() < MAX_PROCESSING_AGE as u64 {
|
while now.elapsed().as_secs() < wait_time as u64 {
|
||||||
self.transactions_socket
|
if num_confirmed == 0 {
|
||||||
.send_to(&buf[..], &self.transactions_addr())?;
|
// Send the transaction if there has been no confirmation (e.g. the first time)
|
||||||
if self
|
self.transactions_socket
|
||||||
.poll_for_signature_confirmation(
|
.send_to(&buf[..], &self.transactions_addr())?;
|
||||||
&transaction.signatures[0],
|
}
|
||||||
min_confirmed_blocks,
|
|
||||||
)
|
if let Ok(confirmed_blocks) = self.poll_for_signature_confirmation(
|
||||||
.is_ok()
|
&transaction.signatures[0],
|
||||||
{
|
pending_confirmations,
|
||||||
return Ok(transaction.signatures[0]);
|
) {
|
||||||
|
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!(
|
info!(
|
||||||
@ -385,7 +397,7 @@ impl SyncClient for ThinClient {
|
|||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
min_confirmed_blocks: usize,
|
min_confirmed_blocks: usize,
|
||||||
) -> TransportResult<()> {
|
) -> TransportResult<usize> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.rpc_client()
|
.rpc_client()
|
||||||
.poll_for_signature_confirmation(signature, min_confirmed_blocks)?)
|
.poll_for_signature_confirmation(signature, min_confirmed_blocks)?)
|
||||||
|
@ -127,7 +127,7 @@ impl SyncClient for BankClient {
|
|||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
min_confirmed_blocks: usize,
|
min_confirmed_blocks: usize,
|
||||||
) -> Result<()> {
|
) -> Result<usize> {
|
||||||
let mut now = Instant::now();
|
let mut now = Instant::now();
|
||||||
let mut confirmed_blocks = 0;
|
let mut confirmed_blocks = 0;
|
||||||
loop {
|
loop {
|
||||||
@ -152,7 +152,7 @@ impl SyncClient for BankClient {
|
|||||||
}
|
}
|
||||||
sleep(Duration::from_millis(250));
|
sleep(Duration::from_millis(250));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(confirmed_blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_for_signature(&self, signature: &Signature) -> Result<()> {
|
fn poll_for_signature(&self, signature: &Signature) -> Result<()> {
|
||||||
|
@ -64,7 +64,7 @@ pub trait SyncClient {
|
|||||||
&self,
|
&self,
|
||||||
signature: &Signature,
|
signature: &Signature,
|
||||||
min_confirmed_blocks: usize,
|
min_confirmed_blocks: usize,
|
||||||
) -> Result<()>;
|
) -> Result<usize>;
|
||||||
|
|
||||||
/// Poll to confirm a transaction.
|
/// Poll to confirm a transaction.
|
||||||
fn poll_for_signature(&self, signature: &Signature) -> Result<()>;
|
fn poll_for_signature(&self, signature: &Signature) -> Result<()>;
|
||||||
|
Reference in New Issue
Block a user