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        self.as_invalid_tx_err()
11            .is_some_and(|err| matches!(err, InvalidTransaction::NonceTooLow { .. }))
12    }
13
14    /// Returns whether the error is due to the transaction gas limit being higher than allowed.
15    fn is_gas_limit_too_high(&self) -> bool {
16        self.as_invalid_tx_err().is_some_and(|err| {
17            matches!(
18                err,
19                InvalidTransaction::TxGasLimitGreaterThanCap { .. }
20                    | InvalidTransaction::CallerGasLimitMoreThanBlock
21            )
22        })
23    }
24
25    /// Returns whether the error is due to the transaction gas limit being lower than required.
26    fn is_gas_limit_too_low(&self) -> bool {
27        self.as_invalid_tx_err().is_some_and(|err| {
28            matches!(
29                err,
30                InvalidTransaction::CallGasCostMoreThanGasLimit { .. }
31                    | InvalidTransaction::GasFloorMoreThanGasLimit { .. }
32            )
33        })
34    }
35
36    /// Returns the underlying [`InvalidTransaction`] if any.
37    ///
38    /// This is primarily used for error conversions, e.g. for rpc responses.
39    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction>;
40}
41
42impl InvalidTxError for InvalidTransaction {
43    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction> {
44        Some(self)
45    }
46}
47
48/// Abstraction over errors that can occur during EVM execution.
49///
50/// It's assumed that errors can occur either because of an invalid transaction, meaning that other
51/// transaction might still result in successful execution, or because of a general EVM
52/// misconfiguration.
53///
54/// If caller occurs a error different from [`EvmError::InvalidTransaction`], it should most likely
55/// be treated as fatal error flagging some EVM misconfiguration.
56pub trait EvmError: Sized + Error + Send + Sync + 'static {
57    /// Errors which might occur as a result of an invalid transaction. i.e unrelated to general EVM
58    /// configuration.
59    type InvalidTransaction: InvalidTxError;
60
61    /// Returns the [`EvmError::InvalidTransaction`] if the error is an invalid transaction error.
62    fn as_invalid_tx_err(&self) -> Option<&Self::InvalidTransaction>;
63
64    /// Attempts to convert the error into [`EvmError::InvalidTransaction`].
65    fn try_into_invalid_tx_err(self) -> Result<Self::InvalidTransaction, Self>;
66
67    /// Returns `true` if the error is an invalid transaction error.
68    fn is_invalid_tx_err(&self) -> bool {
69        self.as_invalid_tx_err().is_some()
70    }
71}
72
73impl<DBError, TxError> EvmError for EVMError<DBError, TxError>
74where
75    DBError: Error + Send + Sync + 'static,
76    TxError: InvalidTxError,
77{
78    type InvalidTransaction = TxError;
79
80    fn as_invalid_tx_err(&self) -> Option<&Self::InvalidTransaction> {
81        match self {
82            Self::Transaction(err) => Some(err),
83            _ => None,
84        }
85    }
86
87    fn try_into_invalid_tx_err(self) -> Result<Self::InvalidTransaction, Self> {
88        match self {
89            Self::Transaction(err) => Ok(err),
90            err => Err(err),
91        }
92    }
93}
94
95#[cfg(feature = "op")]
96impl InvalidTxError for op_revm::OpTransactionError {
97    fn as_invalid_tx_err(&self) -> Option<&InvalidTransaction> {
98        match self {
99            Self::Base(tx) => Some(tx),
100            _ => None,
101        }
102    }
103}