Retry durable-nonce transactions (#14308)

* Retry durable-nonce transactions

* Add metric to track durable-nonce txs in queue

* Populate send-tx-service initial addresses with tpu_address if empty (primarily for testing)

* Reinstate last_valid_slot check for durable-nonce txs; use arbitrary future slot
This commit is contained in:
Tyera Eulberg
2020-12-29 09:48:43 -07:00
committed by GitHub
parent 3a1e01cced
commit 3f10fb993b
2 changed files with 375 additions and 51 deletions

View File

@ -46,7 +46,7 @@ use solana_runtime::{
use solana_sdk::{
account::Account,
account_utils::StateMut,
clock::{Slot, UnixTimestamp},
clock::{Slot, UnixTimestamp, MAX_RECENT_BLOCKHASHES},
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_info::EpochInfo,
epoch_schedule::EpochSchedule,
@ -1875,12 +1875,18 @@ fn _send_transaction(
transaction: Transaction,
wire_transaction: Vec<u8>,
last_valid_slot: Slot,
durable_nonce_info: Option<(Pubkey, Hash)>,
) -> Result<String> {
if transaction.signatures.is_empty() {
return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
}
let signature = transaction.signatures[0];
let transaction_info = TransactionInfo::new(signature, wire_transaction, last_valid_slot);
let transaction_info = TransactionInfo::new(
signature,
wire_transaction,
last_valid_slot,
durable_nonce_info,
);
meta.transaction_sender
.lock()
.unwrap()
@ -2309,7 +2315,7 @@ impl RpcSol for RpcSolImpl {
Error::internal_error()
})?;
_send_transaction(meta, transaction, wire_transaction, last_valid_slot)
_send_transaction(meta, transaction, wire_transaction, last_valid_slot, None)
}
fn send_transaction(
@ -2328,10 +2334,23 @@ impl RpcSol for RpcSolImpl {
.map(|commitment| CommitmentConfig { commitment });
let preflight_bank = &*meta.bank(preflight_commitment);
let last_valid_slot = preflight_bank
let mut last_valid_slot = preflight_bank
.get_blockhash_last_valid_slot(&transaction.message.recent_blockhash)
.unwrap_or(0);
let durable_nonce_info = solana_sdk::transaction::uses_durable_nonce(&transaction)
.and_then(|nonce_ix| {
solana_sdk::transaction::get_nonce_pubkey_from_instruction(&nonce_ix, &transaction)
})
.map(|&pubkey| (pubkey, transaction.message.recent_blockhash));
if durable_nonce_info.is_some() {
// While it uses a defined constant, this last_valid_slot value is chosen arbitrarily.
// It provides a fallback timeout for durable-nonce transaction retries in case of
// malicious packing of the retry queue. Durable-nonce transactions are otherwise
// retried until the nonce is advanced.
last_valid_slot = preflight_bank.slot() + MAX_RECENT_BLOCKHASHES as u64;
}
if !config.skip_preflight {
if let Err(e) = verify_transaction(&transaction) {
return Err(e);
@ -2352,7 +2371,13 @@ impl RpcSol for RpcSolImpl {
}
}
_send_transaction(meta, transaction, wire_transaction, last_valid_slot)
_send_transaction(
meta,
transaction,
wire_transaction,
last_valid_slot,
durable_nonce_info,
)
}
fn simulate_transaction(