Add parameter to allow setting max-retries for SendTransaction rpc (#19387)

* Add parameter to cap rpc send retries for a tx

* Add parameter to docs
This commit is contained in:
Tyera Eulberg 2021-08-24 22:44:13 -06:00 committed by GitHub
parent d559426373
commit 7482861f4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 3 deletions

View File

@ -167,6 +167,7 @@ impl Banks for BanksServer {
serialize(&transaction).unwrap(), serialize(&transaction).unwrap(),
last_valid_block_height, last_valid_block_height,
None, None,
None,
); );
self.transaction_sender.send(info).unwrap(); self.transaction_sender.send(info).unwrap();
} }
@ -257,6 +258,7 @@ impl Banks for BanksServer {
serialize(&transaction).unwrap(), serialize(&transaction).unwrap(),
last_valid_block_height, last_valid_block_height,
None, None,
None,
); );
self.transaction_sender.send(info).unwrap(); self.transaction_sender.send(info).unwrap();
self.poll_signature_status(&signature, blockhash, last_valid_block_height, commitment) self.poll_signature_status(&signature, blockhash, last_valid_block_height, commitment)

View File

@ -21,6 +21,7 @@ pub struct RpcSendTransactionConfig {
pub skip_preflight: bool, pub skip_preflight: bool,
pub preflight_commitment: Option<CommitmentLevel>, pub preflight_commitment: Option<CommitmentLevel>,
pub encoding: Option<UiTransactionEncoding>, pub encoding: Option<UiTransactionEncoding>,
pub max_retries: Option<usize>,
} }
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]

View File

@ -3246,6 +3246,8 @@ submission.
- `skipPreflight: <bool>` - if true, skip the preflight transaction checks (default: false) - `skipPreflight: <bool>` - if true, skip the preflight transaction checks (default: false)
- `preflightCommitment: <string>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to use for preflight (default: `"finalized"`). - `preflightCommitment: <string>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) level to use for preflight (default: `"finalized"`).
- `encoding: <string>` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`). - `encoding: <string>` - (optional) Encoding used for the transaction data. Either `"base58"` (*slow*, **DEPRECATED**), or `"base64"`. (default: `"base58"`).
- `maxRetries: <usize>` - (optional) Maximum number of times for the RPC node to retry sending the transaction to the leader.
If this parameter not provided, the RPC node will retry the transaction until it is finalized or until the blockhash expires.
#### Results: #### Results:

View File

@ -2216,12 +2216,14 @@ fn _send_transaction(
wire_transaction: Vec<u8>, wire_transaction: Vec<u8>,
last_valid_block_height: u64, last_valid_block_height: u64,
durable_nonce_info: Option<(Pubkey, Hash)>, durable_nonce_info: Option<(Pubkey, Hash)>,
max_retries: Option<usize>,
) -> Result<String> { ) -> Result<String> {
let transaction_info = TransactionInfo::new( let transaction_info = TransactionInfo::new(
signature, signature,
wire_transaction, wire_transaction,
last_valid_block_height, last_valid_block_height,
durable_nonce_info, durable_nonce_info,
max_retries,
); );
meta.transaction_sender meta.transaction_sender
.lock() .lock()
@ -3291,6 +3293,7 @@ pub mod rpc_full {
wire_transaction, wire_transaction,
last_valid_block_height, last_valid_block_height,
None, None,
None,
) )
} }
@ -3390,6 +3393,7 @@ pub mod rpc_full {
wire_transaction, wire_transaction,
last_valid_block_height, last_valid_block_height,
durable_nonce_info, durable_nonce_info,
config.max_retries,
) )
} }

View File

@ -28,6 +28,8 @@ pub struct TransactionInfo {
pub wire_transaction: Vec<u8>, pub wire_transaction: Vec<u8>,
pub last_valid_block_height: u64, pub last_valid_block_height: u64,
pub durable_nonce_info: Option<(Pubkey, Hash)>, pub durable_nonce_info: Option<(Pubkey, Hash)>,
pub max_retries: Option<usize>,
retries: usize,
} }
impl TransactionInfo { impl TransactionInfo {
@ -36,12 +38,15 @@ impl TransactionInfo {
wire_transaction: Vec<u8>, wire_transaction: Vec<u8>,
last_valid_block_height: u64, last_valid_block_height: u64,
durable_nonce_info: Option<(Pubkey, Hash)>, durable_nonce_info: Option<(Pubkey, Hash)>,
max_retries: Option<usize>,
) -> Self { ) -> Self {
Self { Self {
signature, signature,
wire_transaction, wire_transaction,
last_valid_block_height, last_valid_block_height,
durable_nonce_info, durable_nonce_info,
max_retries,
retries: 0,
} }
} }
} }
@ -51,6 +56,7 @@ struct ProcessTransactionsResult {
rooted: u64, rooted: u64,
expired: u64, expired: u64,
retried: u64, retried: u64,
max_retries_elapsed: u64,
failed: u64, failed: u64,
retained: u64, retained: u64,
} }
@ -173,7 +179,7 @@ impl SendTransactionService {
) -> ProcessTransactionsResult { ) -> ProcessTransactionsResult {
let mut result = ProcessTransactionsResult::default(); let mut result = ProcessTransactionsResult::default();
transactions.retain(|signature, transaction_info| { transactions.retain(|signature, mut transaction_info| {
if transaction_info.durable_nonce_info.is_some() { if transaction_info.durable_nonce_info.is_some() {
inc_new_counter_info!("send_transaction_service-nonced", 1); inc_new_counter_info!("send_transaction_service-nonced", 1);
} }
@ -200,6 +206,14 @@ impl SendTransactionService {
inc_new_counter_info!("send_transaction_service-expired", 1); inc_new_counter_info!("send_transaction_service-expired", 1);
return false; return false;
} }
if let Some(max_retries) = transaction_info.max_retries {
if transaction_info.retries >= max_retries {
info!("Dropping transaction due to max retries: {}", signature);
result.max_retries_elapsed += 1;
inc_new_counter_info!("send_transaction_service-max_retries", 1);
return false;
}
}
match working_bank.get_signature_status_slot(signature) { match working_bank.get_signature_status_slot(signature) {
None => { None => {
@ -207,6 +221,7 @@ impl SendTransactionService {
// dropped or landed in another fork. Re-send it // dropped or landed in another fork. Re-send it
info!("Retrying transaction: {}", signature); info!("Retrying transaction: {}", signature);
result.retried += 1; result.retried += 1;
transaction_info.retries += 1;
inc_new_counter_info!("send_transaction_service-retry", 1); inc_new_counter_info!("send_transaction_service-retry", 1);
let addresses = leader_info let addresses = leader_info
.as_ref() .as_ref()
@ -339,6 +354,7 @@ mod test {
vec![], vec![],
root_bank.block_height() - 1, root_bank.block_height() - 1,
None, None,
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -362,7 +378,13 @@ mod test {
info!("Rooted transactions are dropped..."); info!("Rooted transactions are dropped...");
transactions.insert( transactions.insert(
rooted_signature, rooted_signature,
TransactionInfo::new(rooted_signature, vec![], working_bank.block_height(), None), TransactionInfo::new(
rooted_signature,
vec![],
working_bank.block_height(),
None,
None,
),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
&working_bank, &working_bank,
@ -385,7 +407,13 @@ mod test {
info!("Failed transactions are dropped..."); info!("Failed transactions are dropped...");
transactions.insert( transactions.insert(
failed_signature, failed_signature,
TransactionInfo::new(failed_signature, vec![], working_bank.block_height(), None), TransactionInfo::new(
failed_signature,
vec![],
working_bank.block_height(),
None,
None,
),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
&working_bank, &working_bank,
@ -413,6 +441,7 @@ mod test {
vec![], vec![],
working_bank.block_height(), working_bank.block_height(),
None, None,
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -442,6 +471,7 @@ mod test {
vec![], vec![],
working_bank.block_height(), working_bank.block_height(),
None, None,
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -461,6 +491,64 @@ mod test {
..ProcessTransactionsResult::default() ..ProcessTransactionsResult::default()
} }
); );
transactions.clear();
info!("Transactions are only retried until max_retries");
transactions.insert(
Signature::new(&[1; 64]),
TransactionInfo::new(
Signature::default(),
vec![],
working_bank.block_height(),
None,
Some(0),
),
);
transactions.insert(
Signature::new(&[2; 64]),
TransactionInfo::new(
Signature::default(),
vec![],
working_bank.block_height(),
None,
Some(1),
),
);
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
&working_bank,
&root_bank,
&send_socket,
&tpu_address,
&mut transactions,
&None,
leader_forward_count,
);
assert_eq!(transactions.len(), 1);
assert_eq!(
result,
ProcessTransactionsResult {
retried: 1,
max_retries_elapsed: 1,
..ProcessTransactionsResult::default()
}
);
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
&working_bank,
&root_bank,
&send_socket,
&tpu_address,
&mut transactions,
&None,
leader_forward_count,
);
assert!(transactions.is_empty());
assert_eq!(
result,
ProcessTransactionsResult {
max_retries_elapsed: 1,
..ProcessTransactionsResult::default()
}
);
} }
#[test] #[test]
@ -521,6 +609,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, durable_nonce)), Some((nonce_address, durable_nonce)),
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -548,6 +637,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, Hash::new_unique())), Some((nonce_address, Hash::new_unique())),
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -577,6 +667,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, Hash::new_unique())), Some((nonce_address, Hash::new_unique())),
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -604,6 +695,7 @@ mod test {
vec![], vec![],
root_bank.block_height() - 1, root_bank.block_height() - 1,
Some((nonce_address, durable_nonce)), Some((nonce_address, durable_nonce)),
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -632,6 +724,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, Hash::new_unique())), // runtime should advance nonce on failed transactions Some((nonce_address, Hash::new_unique())), // runtime should advance nonce on failed transactions
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -660,6 +753,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, Hash::new_unique())), // runtime advances nonce when transaction lands Some((nonce_address, Hash::new_unique())), // runtime advances nonce when transaction lands
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
@ -689,6 +783,7 @@ mod test {
vec![], vec![],
last_valid_block_height, last_valid_block_height,
Some((nonce_address, durable_nonce)), Some((nonce_address, durable_nonce)),
None,
), ),
); );
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(