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:
parent
d559426373
commit
7482861f4b
|
@ -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)
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
Loading…
Reference in New Issue