reth_optimism_rpc/
error.rs1use alloy_json_rpc::ErrorPayload;
4use alloy_primitives::Bytes;
5use alloy_rpc_types_eth::{error::EthRpcErrorCode, BlockError};
6use alloy_transport::{RpcError, TransportErrorKind};
7use jsonrpsee_types::error::{INTERNAL_ERROR_CODE, INVALID_PARAMS_CODE};
8use op_revm::{OpHaltReason, OpTransactionError};
9use reth_evm::execute::ProviderError;
10use reth_optimism_evm::OpBlockExecutionError;
11use reth_rpc_eth_api::{AsEthApiError, EthTxEnvError, TransactionConversionError};
12use reth_rpc_eth_types::{
13 error::api::{FromEvmHalt, FromRevert},
14 EthApiError,
15};
16use reth_rpc_server_types::result::{internal_rpc_err, rpc_err};
17use revm::context_interface::result::{EVMError, InvalidTransaction};
18use std::{convert::Infallible, fmt::Display};
19
20#[derive(Debug, thiserror::Error)]
22pub enum OpEthApiError {
23 #[error(transparent)]
25 Eth(#[from] EthApiError),
26 #[error(transparent)]
28 Evm(#[from] OpBlockExecutionError),
29 #[error("failed to calculate l1 gas fee")]
31 L1BlockFeeError,
32 #[error("failed to calculate l1 gas used")]
34 L1BlockGasError,
35 #[error(transparent)]
37 InvalidTransaction(#[from] OpInvalidTransactionError),
38 #[error(transparent)]
40 Sequencer(#[from] SequencerClientError),
41}
42
43impl AsEthApiError for OpEthApiError {
44 fn as_err(&self) -> Option<&EthApiError> {
45 match self {
46 Self::Eth(err) => Some(err),
47 _ => None,
48 }
49 }
50}
51
52impl From<OpEthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
53 fn from(err: OpEthApiError) -> Self {
54 match err {
55 OpEthApiError::Eth(err) => err.into(),
56 OpEthApiError::InvalidTransaction(err) => err.into(),
57 OpEthApiError::Evm(_) |
58 OpEthApiError::L1BlockFeeError |
59 OpEthApiError::L1BlockGasError => internal_rpc_err(err.to_string()),
60 OpEthApiError::Sequencer(err) => err.into(),
61 }
62 }
63}
64
65#[derive(thiserror::Error, Debug)]
67pub enum OpInvalidTransactionError {
68 #[error("no system transactions allowed after regolith")]
70 DepositSystemTxPostRegolith,
71 #[error("deposit transaction halted after regolith")]
73 HaltedDepositPostRegolith,
74 #[error("missing enveloped transaction bytes")]
76 MissingEnvelopedTx,
77 #[error(transparent)]
79 TxConditionalErr(#[from] TxConditionalErr),
80}
81
82impl From<OpInvalidTransactionError> for jsonrpsee_types::error::ErrorObject<'static> {
83 fn from(err: OpInvalidTransactionError) -> Self {
84 match err {
85 OpInvalidTransactionError::DepositSystemTxPostRegolith |
86 OpInvalidTransactionError::HaltedDepositPostRegolith |
87 OpInvalidTransactionError::MissingEnvelopedTx => {
88 rpc_err(EthRpcErrorCode::TransactionRejected.code(), err.to_string(), None)
89 }
90 OpInvalidTransactionError::TxConditionalErr(_) => err.into(),
91 }
92 }
93}
94
95impl TryFrom<OpTransactionError> for OpInvalidTransactionError {
96 type Error = InvalidTransaction;
97
98 fn try_from(err: OpTransactionError) -> Result<Self, Self::Error> {
99 match err {
100 OpTransactionError::DepositSystemTxPostRegolith => {
101 Ok(Self::DepositSystemTxPostRegolith)
102 }
103 OpTransactionError::HaltedDepositPostRegolith => Ok(Self::HaltedDepositPostRegolith),
104 OpTransactionError::MissingEnvelopedTx => Ok(Self::MissingEnvelopedTx),
105 OpTransactionError::Base(err) => Err(err),
106 }
107 }
108}
109
110#[derive(Debug, thiserror::Error)]
112pub enum TxConditionalErr {
113 #[error("conditional cost exceeded maximum allowed")]
115 ConditionalCostExceeded,
116 #[error("invalid conditional parameters")]
118 InvalidCondition,
119 #[error("internal error: {0}")]
121 Internal(String),
122 #[error("storage value mismatch")]
124 StorageValueMismatch,
125 #[error("storage root mismatch")]
127 StorageRootMismatch,
128}
129
130impl TxConditionalErr {
131 pub fn internal<E: Display>(err: E) -> Self {
133 Self::Internal(err.to_string())
134 }
135}
136
137impl From<TxConditionalErr> for jsonrpsee_types::error::ErrorObject<'static> {
138 fn from(err: TxConditionalErr) -> Self {
139 let code = match &err {
140 TxConditionalErr::Internal(_) => INTERNAL_ERROR_CODE,
141 _ => INVALID_PARAMS_CODE,
142 };
143
144 jsonrpsee_types::error::ErrorObject::owned(code, err.to_string(), None::<String>)
145 }
146}
147
148#[derive(Debug, thiserror::Error)]
150pub enum SequencerClientError {
151 #[error(transparent)]
153 HttpError(#[from] RpcError<TransportErrorKind>),
154}
155
156impl From<SequencerClientError> for jsonrpsee_types::error::ErrorObject<'static> {
157 fn from(err: SequencerClientError) -> Self {
158 match err {
159 SequencerClientError::HttpError(RpcError::ErrorResp(ErrorPayload {
160 code,
161 message,
162 data,
163 })) => jsonrpsee_types::error::ErrorObject::owned(code as i32, message, data),
164 err => jsonrpsee_types::error::ErrorObject::owned(
165 INTERNAL_ERROR_CODE,
166 err.to_string(),
167 None::<String>,
168 ),
169 }
170 }
171}
172
173impl<T> From<EVMError<T, OpTransactionError>> for OpEthApiError
174where
175 T: Into<EthApiError>,
176{
177 fn from(error: EVMError<T, OpTransactionError>) -> Self {
178 match error {
179 EVMError::Transaction(err) => match err.try_into() {
180 Ok(err) => Self::InvalidTransaction(err),
181 Err(err) => Self::Eth(EthApiError::InvalidTransaction(err.into())),
182 },
183 EVMError::Database(err) => Self::Eth(err.into()),
184 EVMError::Header(err) => Self::Eth(err.into()),
185 EVMError::Custom(err) => Self::Eth(EthApiError::EvmCustom(err)),
186 }
187 }
188}
189
190impl FromEvmHalt<OpHaltReason> for OpEthApiError {
191 fn from_evm_halt(halt: OpHaltReason, gas_limit: u64) -> Self {
192 match halt {
193 OpHaltReason::FailedDeposit => {
194 OpInvalidTransactionError::HaltedDepositPostRegolith.into()
195 }
196 OpHaltReason::Base(halt) => EthApiError::from_evm_halt(halt, gas_limit).into(),
197 }
198 }
199}
200
201impl FromRevert for OpEthApiError {
202 fn from_revert(output: Bytes) -> Self {
203 Self::Eth(EthApiError::from_revert(output))
204 }
205}
206
207impl From<TransactionConversionError> for OpEthApiError {
208 fn from(value: TransactionConversionError) -> Self {
209 Self::Eth(EthApiError::from(value))
210 }
211}
212
213impl From<EthTxEnvError> for OpEthApiError {
214 fn from(value: EthTxEnvError) -> Self {
215 Self::Eth(EthApiError::from(value))
216 }
217}
218
219impl From<ProviderError> for OpEthApiError {
220 fn from(value: ProviderError) -> Self {
221 Self::Eth(EthApiError::from(value))
222 }
223}
224
225impl From<BlockError> for OpEthApiError {
226 fn from(value: BlockError) -> Self {
227 Self::Eth(EthApiError::from(value))
228 }
229}
230
231impl From<Infallible> for OpEthApiError {
232 fn from(value: Infallible) -> Self {
233 match value {}
234 }
235}