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::NonceMaxValue => Some(EthSimulateError::NonceMaxValue),
89 RpcInvalidTransactionError::FeeCapTooLow => {
90 Some(EthSimulateError::BaseFeePerGasTooLow)
91 }
92 RpcInvalidTransactionError::GasTooLow => Some(EthSimulateError::IntrinsicGasTooLow),
93 RpcInvalidTransactionError::InsufficientFunds { cost, balance } => {
94 Some(EthSimulateError::InsufficientFunds { cost: *cost, balance: *balance })
95 }
96 RpcInvalidTransactionError::SenderNoEOA => Some(EthSimulateError::SenderNotEOA),
97 RpcInvalidTransactionError::MaxInitCodeSizeExceeded => {
98 Some(EthSimulateError::MaxInitCodeSizeExceeded)
99 }
100 _ => None,
101 },
102 _ => None,
103 }
104 }
105}
106
107impl AsEthApiError for EthApiError {
108 fn as_err(&self) -> Option<&EthApiError> {
109 Some(self)
110 }
111}
112
113pub trait FromEvmError<Evm: ConfigureEvm>:
115 From<EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>>
116 + FromEvmHalt<HaltReasonFor<Evm>>
117 + FromRevert
118{
119 fn from_evm_err(err: EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>) -> Self {
121 err.into()
122 }
123
124 fn ensure_success(result: ExecutionResult<HaltReasonFor<Evm>>) -> Result<Bytes, Self> {
126 match result {
127 ExecutionResult::Success { output, .. } => Ok(output.into_data()),
128 ExecutionResult::Revert { output, .. } => Err(Self::from_revert(output)),
129 ExecutionResult::Halt { reason, gas, .. } => {
130 Err(Self::from_evm_halt(reason, gas.tx_gas_used()))
131 }
132 }
133 }
134}
135
136impl<T, Evm> FromEvmError<Evm> for T
137where
138 T: From<EvmErrorFor<Evm, EvmDatabaseError<ProviderError>>>
139 + FromEvmHalt<HaltReasonFor<Evm>>
140 + FromRevert,
141 Evm: ConfigureEvm,
142{
143}
144
145pub trait FromEvmHalt<Halt> {
147 fn from_evm_halt(halt: Halt, gas_limit: u64) -> Self;
149}
150
151impl FromEvmHalt<HaltReason> for EthApiError {
152 fn from_evm_halt(halt: HaltReason, gas_limit: u64) -> Self {
153 RpcInvalidTransactionError::halt(halt, gas_limit).into()
154 }
155}
156
157pub trait FromRevert {
159 fn from_revert(output: Bytes) -> Self;
163}
164
165impl FromRevert for EthApiError {
166 fn from_revert(output: Bytes) -> Self {
167 RpcInvalidTransactionError::Revert(RevertError::new(output)).into()
168 }
169}