alloy_evm/
error.rs

1//! Abstraction over EVM errors.
2
3use core::{any::Any, error::Error};
4use revm::context_interface::result::{EVMError, InvalidTransaction};
5
6/// Abstraction over transaction validation error.
7pub trait InvalidTxError: Error + Send + Sync + Any + 'static {
8    /// Returns whether the error cause by transaction having a nonce lower than expected.
9    fn is_nonce_too_low(&self) -> bool;
10
11    /// Returns the underlying [`InvalidTransaction`] if any.
12    ///
13    /// This is primarily used for error conversions, e.g. for rpc responses.
14    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction>;
15}
16
17impl InvalidTxError for InvalidTransaction {
18    fn is_nonce_too_low(&self) -> bool {
19        matches!(self, Self::NonceTooLow { .. })
20    }
21
22    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction> {
23        Some(self)
24    }
25}
26
27/// Abstraction over errors that can occur during EVM execution.
28///
29/// It's assumed that errors can occur either because of an invalid transaction, meaning that other
30/// transaction might still result in successful execution, or because of a general EVM
31/// misconfiguration.
32///
33/// If caller occurs a error different from [`EvmError::InvalidTransaction`], it should most likely
34/// be treated as fatal error flagging some EVM misconfiguration.
35pub trait EvmError: Sized + Error + Send + Sync + 'static {
36    /// Errors which might occur as a result of an invalid transaction. i.e unrelated to general EVM
37    /// configuration.
38    type InvalidTransaction: InvalidTxError;
39
40    /// Returns the [`EvmError::InvalidTransaction`] if the error is an invalid transaction error.
41    fn as_invalid_tx_err(&self) -> Option<&Self::InvalidTransaction>;
42
43    /// Attempts to convert the error into [`EvmError::InvalidTransaction`].
44    fn try_into_invalid_tx_err(self) -> Result<Self::InvalidTransaction, Self>;
45
46    /// Returns `true` if the error is an invalid transaction error.
47    fn is_invalid_tx_err(&self) -> bool {
48        self.as_invalid_tx_err().is_some()
49    }
50}
51
52impl<DBError, TxError> EvmError for EVMError<DBError, TxError>
53where
54    DBError: Error + Send + Sync + 'static,
55    TxError: InvalidTxError,
56{
57    type InvalidTransaction = TxError;
58
59    fn as_invalid_tx_err(&self) -> Option<&Self::InvalidTransaction> {
60        match self {
61            Self::Transaction(err) => Some(err),
62            _ => None,
63        }
64    }
65
66    fn try_into_invalid_tx_err(self) -> Result<Self::InvalidTransaction, Self> {
67        match self {
68            Self::Transaction(err) => Ok(err),
69            err => Err(err),
70        }
71    }
72}
73
74#[cfg(feature = "op")]
75impl InvalidTxError for op_revm::OpTransactionError {
76    fn is_nonce_too_low(&self) -> bool {
77        matches!(self, Self::Base(tx) if tx.is_nonce_too_low())
78    }
79
80    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction> {
81        match self {
82            Self::Base(tx) => Some(tx),
83            _ => None,
84        }
85    }
86}