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(),
last_valid_block_height,
None,
None,
);
self.transaction_sender.send(info).unwrap();
}
@ -257,6 +258,7 @@ impl Banks for BanksServer {
serialize(&transaction).unwrap(),
last_valid_block_height,
None,
None,
);
self.transaction_sender.send(info).unwrap();
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 preflight_commitment: Option<CommitmentLevel>,
pub encoding: Option<UiTransactionEncoding>,
pub max_retries: Option<usize>,
}
#[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)
- `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"`).
- `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:

View File

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

View File

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