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

* 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

(cherry picked from commit 7482861f4b)

# Conflicts:
#	banks-server/src/banks_server.rs
#	core/src/rpc.rs
#	core/src/send_transaction_service.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
This commit is contained in:
mergify[bot]
2021-08-25 16:47:47 +00:00
committed by GitHub
parent 45e3cd373b
commit 2825f82bee
4 changed files with 118 additions and 7 deletions

View File

@@ -2163,6 +2163,7 @@ fn _send_transaction(
wire_transaction: Vec<u8>,
last_valid_slot: Slot,
durable_nonce_info: Option<(Pubkey, Hash)>,
max_retries: Option<usize>,
) -> Result<String> {
if transaction.signatures.is_empty() {
return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
@@ -2173,6 +2174,7 @@ fn _send_transaction(
wire_transaction,
last_valid_slot,
durable_nonce_info,
max_retries,
);
meta.transaction_sender
.lock()
@@ -3112,7 +3114,14 @@ pub mod rpc_full {
Error::internal_error()
})?;
_send_transaction(meta, transaction, wire_transaction, last_valid_slot, None)
_send_transaction(
meta,
transaction,
wire_transaction,
last_valid_slot,
None,
None,
)
}
fn send_transaction(
@@ -3204,6 +3213,7 @@ pub mod rpc_full {
wire_transaction,
last_valid_slot,
durable_nonce_info,
config.max_retries,
)
}

View File

@@ -35,6 +35,8 @@ pub struct TransactionInfo {
pub wire_transaction: Vec<u8>,
pub last_valid_slot: Slot,
pub durable_nonce_info: Option<(Pubkey, Hash)>,
pub max_retries: Option<usize>,
retries: usize,
}
impl TransactionInfo {
@@ -43,12 +45,15 @@ impl TransactionInfo {
wire_transaction: Vec<u8>,
last_valid_slot: Slot,
durable_nonce_info: Option<(Pubkey, Hash)>,
max_retries: Option<usize>,
) -> Self {
Self {
signature,
wire_transaction,
last_valid_slot,
durable_nonce_info,
max_retries,
retries: 0,
}
}
}
@@ -100,6 +105,7 @@ struct ProcessTransactionsResult {
rooted: u64,
expired: u64,
retried: u64,
max_retries_elapsed: u64,
failed: u64,
retained: u64,
}
@@ -222,7 +228,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);
}
@@ -249,6 +255,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 => {
@@ -256,6 +270,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()
@@ -387,7 +402,13 @@ mod test {
info!("Expired transactions are dropped...");
transactions.insert(
Signature::default(),
TransactionInfo::new(Signature::default(), vec![], root_bank.slot() - 1, None),
TransactionInfo::new(
Signature::default(),
vec![],
root_bank.slot() - 1,
None,
None,
),
);
let result = SendTransactionService::process_transactions(
&working_bank,
@@ -410,7 +431,7 @@ mod test {
info!("Rooted transactions are dropped...");
transactions.insert(
rooted_signature,
TransactionInfo::new(rooted_signature, vec![], working_bank.slot(), None),
TransactionInfo::new(rooted_signature, vec![], working_bank.slot(), None, None),
);
let result = SendTransactionService::process_transactions(
&working_bank,
@@ -433,7 +454,7 @@ mod test {
info!("Failed transactions are dropped...");
transactions.insert(
failed_signature,
TransactionInfo::new(failed_signature, vec![], working_bank.slot(), None),
TransactionInfo::new(failed_signature, vec![], working_bank.slot(), None, None),
);
let result = SendTransactionService::process_transactions(
&working_bank,
@@ -456,7 +477,13 @@ mod test {
info!("Non-rooted transactions are kept...");
transactions.insert(
non_rooted_signature,
TransactionInfo::new(non_rooted_signature, vec![], working_bank.slot(), None),
TransactionInfo::new(
non_rooted_signature,
vec![],
working_bank.slot(),
None,
None,
),
);
let result = SendTransactionService::process_transactions(
&working_bank,
@@ -480,7 +507,13 @@ mod test {
info!("Unknown transactions are retried...");
transactions.insert(
Signature::default(),
TransactionInfo::new(Signature::default(), vec![], working_bank.slot(), None),
TransactionInfo::new(
Signature::default(),
vec![],
working_bank.slot(),
None,
None,
),
);
let result = SendTransactionService::process_transactions(
&working_bank,
@@ -499,6 +532,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.slot(),
None,
Some(0),
),
);
transactions.insert(
Signature::new(&[2; 64]),
TransactionInfo::new(
Signature::default(),
vec![],
working_bank.slot(),
None,
Some(1),
),
);
let result = SendTransactionService::process_transactions(
&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(
&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]
@@ -559,6 +650,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, durable_nonce)),
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -586,6 +678,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, Hash::new_unique())),
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -615,6 +708,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, Hash::new_unique())),
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -642,6 +736,7 @@ mod test {
vec![],
root_bank.slot() - 1,
Some((nonce_address, durable_nonce)),
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -670,6 +765,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, Hash::new_unique())), // runtime should advance nonce on failed transactions
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -698,6 +794,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, Hash::new_unique())), // runtime advances nonce when transaction lands
None,
),
);
let result = SendTransactionService::process_transactions(
@@ -727,6 +824,7 @@ mod test {
vec![],
last_valid_slot,
Some((nonce_address, durable_nonce)),
None,
),
);
let result = SendTransactionService::process_transactions(