reth_rpc_eth_types/error/
api.rs1use crate::{simulate::EthSimulateError, EthApiError, RevertError};
5use alloy_primitives::Bytes;
6use reth_errors::ProviderError;
7use reth_evm::{ConfigureEvm, EvmErrorFor, HaltReasonFor};
8use reth_revm::db::bal::EvmDatabaseError;
9use revm::{context::result::ExecutionResult, context_interface::result::HaltReason};
10
11use super::RpcInvalidTransactionError;
12
13pub trait FromEthApiError: From<EthApiError> {
15 fn from_eth_err<E>(err: E) -> Self
17 where
18 EthApiError: From<E>;
19}
20
21impl<T> FromEthApiError for T
22where
23 T: From<EthApiError>,
24{
25 fn from_eth_err<E>(err: E) -> Self
26 where
27 EthApiError: From<E>,
28 {
29 T::from(EthApiError::from(err))
30 }
31}
32
33pub trait IntoEthApiError: Into<EthApiError> {
35 fn into_eth_err<E>(self) -> E
37 where
38 E: FromEthApiError;
39}
40
41impl<T> IntoEthApiError for T
42where
43 EthApiError: From<T>,
44{
45 fn into_eth_err<E>(self) -> E
46 where
47 E: FromEthApiError,
48 {
49 E::from_eth_err(self)
50 }
51}
52
53pub trait AsEthApiError {
55 fn as_err(&self) -> Option<&EthApiError>;
58
59 fn is_gas_too_high(&self) -> bool {
62 if let Some(err) = self.as_err() {
63 return err.is_gas_too_high()
64 }
65
66 false
67 }
68
69 fn is_gas_too_low(&self) -> bool {
72 if let Some(err) = self.as_err() {
73 return err.is_gas_too_low()
74 }
75
76 false
77 }
78
79 fn as_simulate_error(&self) -> Option<EthSimulateError> {
81 let err = self.as_err()?;
82 match err {
83 EthApiError::InvalidTransaction(tx_err) => match tx_err {
84 RpcInvalidTransactionError::NonceTooLow { tx, state } => {
85 Some(EthSimulateError::NonceTooLow { tx: *tx, state: *state })
86 }
87 RpcInvalidTransactionError::NonceTooHigh => Some(EthSimulateError::NonceTooHigh),
88 RpcInvalidTransactionError::FeeCapTooLow => {
89 Some(EthSimulateError::BaseFeePerGasTooLow)
90 }
91 RpcInvalidTransactionError::GasTooLow => Some(EthSimulateError::IntrinsicGasTooLow),
92 RpcInvalidTransactionError::InsufficientFunds { cost, balance } => {
93 Some(EthSimulateError::InsufficientFunds { cost: *cost, balance: *balance })
94 }
95 RpcInvalidTransactionError::SenderNoEOA => Some(EthSimulateError::SenderNotEOA),
96 RpcInvalidTransactionError::MaxInitCodeSizeExceeded => {
97 Some(EthSimulateError::MaxInitCodeSizeExceeded)
98 }
99 _ => None,
100 },
101 _ => None,
102 }
103 }
104}
105
106impl AsEthApiError for EthApiError {
107 fn as_err(&self) -> Option<&EthApiError> {
108 Some(self)
109 }
110}
111
112pub trait FromEvmError<Evm: ConfigureEvm>:
114 From<EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>>
115 + FromEvmHalt<HaltReasonFor<Evm>>
116 + FromRevert
117{
118 fn from_evm_err(err: EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>) -> Self {
120 err.into()
121 }
122
123 fn ensure_success(result: ExecutionResult<HaltReasonFor<Evm>>) -> Result<Bytes, Self> {
125 match result {
126 ExecutionResult::Success { output, .. } => Ok(output.into_data()),
127 ExecutionResult::Revert { output, .. } => Err(Self::from_revert(output)),
128 ExecutionResult::Halt { reason, gas_used } => {
129 Err(Self::from_evm_halt(reason, gas_used))
130 }
131 }
132 }
133}
134
135impl<T, Evm> FromEvmError<Evm> for T
136where
137 T: From<EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>>
138 + FromEvmHalt<HaltReasonFor<Evm>>
139 + FromRevert,
140 Evm: ConfigureEvm,
141{
142}
143
144pub trait FromEvmHalt<Halt> {
146 fn from_evm_halt(halt: Halt, gas_limit: u64) -> Self;
148}
149
150impl FromEvmHalt<HaltReason> for EthApiError {
151 fn from_evm_halt(halt: HaltReason, gas_limit: u64) -> Self {
152 RpcInvalidTransactionError::halt(halt, gas_limit).into()
153 }
154}
155
156pub trait FromRevert {
158 fn from_revert(output: Bytes) -> Self;
162}
163
164impl FromRevert for EthApiError {
165 fn from_revert(output: Bytes) -> Self {
166 RpcInvalidTransactionError::Revert(RevertError::new(output)).into()
167 }
168}