From 8bbd403285cd87527cf30700d4a13fc74bf5fb52 Mon Sep 17 00:00:00 2001 From: Panagiotis Ganelis <50522617+PanGan21@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:09:33 +0300 Subject: [PATCH] fix: improve nonce too low error (#10711) --- crates/primitives/src/transaction/error.rs | 9 ++++++-- crates/rpc/rpc-eth-types/src/error.rs | 24 +++++++++++++++------ crates/transaction-pool/src/error.rs | 4 ++-- crates/transaction-pool/src/validate/eth.rs | 7 ++++-- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/crates/primitives/src/transaction/error.rs b/crates/primitives/src/transaction/error.rs index 2f3ffc5f8..ed63f2f5a 100644 --- a/crates/primitives/src/transaction/error.rs +++ b/crates/primitives/src/transaction/error.rs @@ -12,8 +12,13 @@ pub enum InvalidTransactionError { /// The nonce is lower than the account's nonce, or there is a nonce gap present. /// /// This is a consensus error. - #[display("transaction nonce is not consistent")] - NonceNotConsistent, + #[display("transaction nonce is not consistent: next nonce {state}, tx nonce {tx}")] + NonceNotConsistent { + /// The nonce of the transaction. + tx: u64, + /// The current state of the nonce in the local chain. + state: u64, + }, /// The transaction is before Spurious Dragon and has a chain ID. #[display("transactions before Spurious Dragon should not have a chain ID")] OldLegacyChainId, diff --git a/crates/rpc/rpc-eth-types/src/error.rs b/crates/rpc/rpc-eth-types/src/error.rs index 74fc15ffe..d1c234e25 100644 --- a/crates/rpc/rpc-eth-types/src/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -15,7 +15,7 @@ use reth_transaction_pool::error::{ Eip4844PoolTransactionError, InvalidPoolTransactionError, PoolError, PoolErrorKind, PoolTransactionError, }; -use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError}; +use revm::primitives::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, OutOfGasError}; use revm_inspectors::tracing::MuxError; use tracing::error; @@ -236,7 +236,12 @@ where { fn from(err: EVMError) -> Self { match err { - EVMError::Transaction(err) => RpcInvalidTransactionError::from(err).into(), + EVMError::Transaction(invalid_tx) => match invalid_tx { + InvalidTransaction::NonceTooLow { tx, state } => { + Self::InvalidTransaction(RpcInvalidTransactionError::NonceTooLow { tx, state }) + } + _ => RpcInvalidTransactionError::from(invalid_tx).into(), + }, EVMError::Header(InvalidHeader::PrevrandaoNotSet) => Self::PrevrandaoNotSet, EVMError::Header(InvalidHeader::ExcessBlobGasNotSet) => Self::ExcessBlobGasNotSet, EVMError::Database(err) => err.into(), @@ -263,8 +268,13 @@ where #[derive(thiserror::Error, Debug)] pub enum RpcInvalidTransactionError { /// returned if the nonce of a transaction is lower than the one present in the local chain. - #[error("nonce too low")] - NonceTooLow, + #[error("nonce too low: next nonce {state}, tx nonce {tx}")] + NonceTooLow { + /// The nonce of the transaction. + tx: u64, + /// The current state of the nonce in the local chain. + state: u64, + }, /// returned if the nonce of a transaction is higher than the next one expected based on the /// local chain. #[error("nonce too high")] @@ -456,7 +466,7 @@ impl From for RpcInvalidTransactionError { InvalidTransaction::NonceOverflowInTransaction => Self::NonceMaxValue, InvalidTransaction::CreateInitCodeSizeLimit => Self::MaxInitCodeSizeExceeded, InvalidTransaction::NonceTooHigh { .. } => Self::NonceTooHigh, - InvalidTransaction::NonceTooLow { .. } => Self::NonceTooLow, + InvalidTransaction::NonceTooLow { tx, state } => Self::NonceTooLow { tx, state }, InvalidTransaction::AccessListNotSupported => Self::AccessListNotSupported, InvalidTransaction::MaxFeePerBlobGasNotSupported => Self::MaxFeePerBlobGasNotSupported, InvalidTransaction::BlobVersionedHashesNotSupported => { @@ -494,7 +504,9 @@ impl From for RpcInvalidTransactionErr // txpool (e.g. `eth_sendRawTransaction`) to their corresponding RPC match err { InvalidTransactionError::InsufficientFunds { .. } => Self::InsufficientFunds, - InvalidTransactionError::NonceNotConsistent => Self::NonceTooLow, + InvalidTransactionError::NonceNotConsistent { tx, state } => { + Self::NonceTooLow { tx, state } + } InvalidTransactionError::OldLegacyChainId => { // Note: this should be unreachable since Spurious Dragon now enabled Self::OldLegacyChainId diff --git a/crates/transaction-pool/src/error.rs b/crates/transaction-pool/src/error.rs index 606b50559..a9dcf9293 100644 --- a/crates/transaction-pool/src/error.rs +++ b/crates/transaction-pool/src/error.rs @@ -225,7 +225,7 @@ impl InvalidPoolTransactionError { // intentionally caused by the sender match err { InvalidTransactionError::InsufficientFunds { .. } | - InvalidTransactionError::NonceNotConsistent => { + InvalidTransactionError::NonceNotConsistent { .. } => { // transaction could just have arrived late/early false } @@ -294,7 +294,7 @@ impl InvalidPoolTransactionError { /// Returns `true` if an import failed due to nonce gap. pub const fn is_nonce_gap(&self) -> bool { - matches!(self, Self::Consensus(InvalidTransactionError::NonceNotConsistent)) || + matches!(self, Self::Consensus(InvalidTransactionError::NonceNotConsistent { .. })) || matches!(self, Self::Eip4844(Eip4844PoolTransactionError::Eip4844NonceGap)) } } diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index baa306f7c..1455e91f7 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -359,11 +359,14 @@ where } } + let tx_nonce = transaction.nonce(); + // Checks for nonce - if transaction.nonce() < account.nonce { + if tx_nonce < account.nonce { return TransactionValidationOutcome::Invalid( transaction, - InvalidTransactionError::NonceNotConsistent.into(), + InvalidTransactionError::NonceNotConsistent { tx: tx_nonce, state: account.nonce } + .into(), ) }