From a98f7a3dc5b35a97a8c0a7e45f01e803dd9b8d1b Mon Sep 17 00:00:00 2001 From: Hai Nguyen Quang Date: Sun, 25 Aug 2024 20:03:04 +0700 Subject: [PATCH] perf: better retry strategy for premature nonce --- src/vm.rs | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/vm.rs b/src/vm.rs index 19971252..2aa79a8a 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -376,10 +376,9 @@ impl<'a, S: Storage, C: PevmChain> Database for VmDb<'a, S, C> { if location_hash == self.from_hash && self.tx.nonce.is_some_and(|nonce| nonce != account.nonce) { - if self.tx_idx > 0 { - // TODO: Better retry strategy -- immediately, to the - // closest sender tx, to the missing sender tx, etc. - return Err(ReadError::Blocking(self.tx_idx - 1)); + if let Some(prev_tx_idx) = self.vm.prev_tx_from_sender(self.tx_idx, &self.tx.caller) + { + return Err(ReadError::Blocking(prev_tx_idx)); } else { return Err(ReadError::InvalidNonce(self.tx_idx)); } @@ -525,6 +524,13 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> { } } + #[inline(always)] + fn prev_tx_from_sender(&self, tx_idx: TxIdx, sender: &Address) -> Option { + (0..tx_idx) + .rev() + .find(|&i| &unsafe { self.txs.get_unchecked(i) }.caller == sender) + } + // Execute a transaction. This can read from memory but cannot modify any state. // A successful execution returns: // - A write-set consisting of memory locations and their updated values. @@ -698,17 +704,24 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> { // Since this retry is safe for syncing canonical blocks but can deadlock // on new or faulty blocks. We can skip the transaction for new blocks and // error out after a number of tries for the latter. - if tx_version.tx_idx > 0 - && matches!( + if tx_version.tx_idx > 0 { + if matches!( err, EVMError::Transaction(InvalidTransaction::LackOfFundForMaxFee { .. }) - | EVMError::Transaction(InvalidTransaction::NonceTooHigh { .. }) - ) - { - Err(VmExecutionError::Blocking(tx_version.tx_idx - 1)) - } else { - Err(VmExecutionError::ExecutionError(err)) + ) { + return Err(VmExecutionError::Blocking(tx_version.tx_idx - 1)); + } else if matches!( + err, + EVMError::Transaction(InvalidTransaction::NonceTooHigh { .. }) + ) { + if let Some(prev_tx_idx) = + self.prev_tx_from_sender(tx_version.tx_idx, &tx.caller) + { + return Err(VmExecutionError::Blocking(prev_tx_idx)); + } + } } + Err(VmExecutionError::ExecutionError(err)) } } }