Skip to content

Commit

Permalink
perf: better retry strategy for premature nonce
Browse files Browse the repository at this point in the history
  • Loading branch information
hai-rise committed Aug 28, 2024
1 parent d48fae9 commit d4ec878
Showing 1 changed file with 24 additions and 13 deletions.
37 changes: 24 additions & 13 deletions src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,8 @@ impl<'a, S: Storage, C: PevmChain> Database for VmDb<'a, S, C> {
// Check sender nonce
account.nonce += nonce_addition;
if location_hash == self.from_hash && account.nonce != self.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::BlockingIndex(self.tx_idx - 1));
if let Some(prev_tx_idx) = self.vm.get_prev_sender(*self.tx_idx, self.from) {
return Err(ReadError::BlockingIndex(prev_tx_idx));
} else {
return Err(ReadError::InvalidNonce);
}
Expand Down Expand Up @@ -503,6 +501,13 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> {
self.hasher.hash_one(MemoryLocation::Basic(*address))
}

#[inline(always)]
fn get_prev_sender(&self, tx_idx: TxIdx, sender: &Address) -> Option<TxIdx> {
(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.
Expand Down Expand Up @@ -669,19 +674,25 @@ 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 { .. })
)
{
VmExecutionResult::ReadError {
blocking_tx_idx: tx_version.tx_idx - 1,
) {
return VmExecutionResult::ReadError {
blocking_tx_idx: tx_version.tx_idx - 1,
};
} else if matches!(
err,
EVMError::Transaction(InvalidTransaction::NonceTooHigh { .. })
) {
if let Some(blocking_tx_idx) = self.get_prev_sender(tx_version.tx_idx, from)
{
return VmExecutionResult::ReadError { blocking_tx_idx };
}
}
} else {
VmExecutionResult::ExecutionError(err)
}
VmExecutionResult::ExecutionError(err)
}
}
}
Expand Down

0 comments on commit d4ec878

Please sign in to comment.