reth_optimism_rpc/
error.rs
1use alloy_rpc_types_eth::{error::EthRpcErrorCode, BlockError};
4use jsonrpsee_types::error::{INTERNAL_ERROR_CODE, INVALID_PARAMS_CODE};
5use op_revm::{OpHaltReason, OpTransactionError};
6use reth_optimism_evm::OpBlockExecutionError;
7use reth_rpc_eth_api::AsEthApiError;
8use reth_rpc_eth_types::{error::api::FromEvmHalt, EthApiError};
9use reth_rpc_server_types::result::{internal_rpc_err, rpc_err};
10use revm::context_interface::result::{EVMError, InvalidTransaction};
11use std::fmt::Display;
12
13#[derive(Debug, thiserror::Error)]
15pub enum OpEthApiError {
16 #[error(transparent)]
18 Eth(#[from] EthApiError),
19 #[error(transparent)]
21 Evm(#[from] OpBlockExecutionError),
22 #[error("failed to calculate l1 gas fee")]
24 L1BlockFeeError,
25 #[error("failed to calculate l1 gas used")]
27 L1BlockGasError,
28 #[error(transparent)]
30 InvalidTransaction(#[from] OpInvalidTransactionError),
31 #[error(transparent)]
33 Sequencer(#[from] SequencerClientError),
34}
35
36impl AsEthApiError for OpEthApiError {
37 fn as_err(&self) -> Option<&EthApiError> {
38 match self {
39 Self::Eth(err) => Some(err),
40 _ => None,
41 }
42 }
43}
44
45impl From<OpEthApiError> for jsonrpsee_types::error::ErrorObject<'static> {
46 fn from(err: OpEthApiError) -> Self {
47 match err {
48 OpEthApiError::Eth(err) => err.into(),
49 OpEthApiError::InvalidTransaction(err) => err.into(),
50 OpEthApiError::Evm(_) |
51 OpEthApiError::L1BlockFeeError |
52 OpEthApiError::L1BlockGasError => internal_rpc_err(err.to_string()),
53 OpEthApiError::Sequencer(err) => err.into(),
54 }
55 }
56}
57
58#[derive(thiserror::Error, Debug)]
60pub enum OpInvalidTransactionError {
61 #[error("no system transactions allowed after regolith")]
63 DepositSystemTxPostRegolith,
64 #[error("deposit transaction halted after regolith")]
66 HaltedDepositPostRegolith,
67 #[error(transparent)]
69 TxConditionalErr(#[from] TxConditionalErr),
70}
71
72impl From<OpInvalidTransactionError> for jsonrpsee_types::error::ErrorObject<'static> {
73 fn from(err: OpInvalidTransactionError) -> Self {
74 match err {
75 OpInvalidTransactionError::DepositSystemTxPostRegolith |
76 OpInvalidTransactionError::HaltedDepositPostRegolith => {
77 rpc_err(EthRpcErrorCode::TransactionRejected.code(), err.to_string(), None)
78 }
79 OpInvalidTransactionError::TxConditionalErr(_) => err.into(),
80 }
81 }
82}
83
84impl TryFrom<OpTransactionError> for OpInvalidTransactionError {
85 type Error = InvalidTransaction;
86
87 fn try_from(err: OpTransactionError) -> Result<Self, Self::Error> {
88 match err {
89 OpTransactionError::DepositSystemTxPostRegolith => {
90 Ok(Self::DepositSystemTxPostRegolith)
91 }
92 OpTransactionError::HaltedDepositPostRegolith => Ok(Self::HaltedDepositPostRegolith),
93 OpTransactionError::Base(err) => Err(err),
94 }
95 }
96}
97
98#[derive(Debug, thiserror::Error)]
100pub enum TxConditionalErr {
101 #[error("conditional cost exceeded maximum allowed")]
103 ConditionalCostExceeded,
104 #[error("invalid conditional parameters")]
106 InvalidCondition,
107 #[error("internal error: {0}")]
109 Internal(String),
110 #[error("storage value mismatch")]
112 StorageValueMismatch,
113 #[error("storage root mismatch")]
115 StorageRootMismatch,
116}
117
118impl TxConditionalErr {
119 pub fn internal<E: Display>(err: E) -> Self {
121 Self::Internal(err.to_string())
122 }
123}
124
125impl From<TxConditionalErr> for jsonrpsee_types::error::ErrorObject<'static> {
126 fn from(err: TxConditionalErr) -> Self {
127 let code = match &err {
128 TxConditionalErr::Internal(_) => INTERNAL_ERROR_CODE,
129 _ => INVALID_PARAMS_CODE,
130 };
131
132 jsonrpsee_types::error::ErrorObject::owned(code, err.to_string(), None::<String>)
133 }
134}
135
136#[derive(Debug, thiserror::Error)]
138pub enum SequencerClientError {
139 #[error(transparent)]
141 HttpError(#[from] reqwest::Error),
142 #[error("invalid sequencer transaction")]
144 InvalidSequencerTransaction,
145}
146
147impl From<SequencerClientError> for jsonrpsee_types::error::ErrorObject<'static> {
148 fn from(err: SequencerClientError) -> Self {
149 jsonrpsee_types::error::ErrorObject::owned(
150 INTERNAL_ERROR_CODE,
151 err.to_string(),
152 None::<String>,
153 )
154 }
155}
156
157impl From<BlockError> for OpEthApiError {
158 fn from(error: BlockError) -> Self {
159 Self::Eth(error.into())
160 }
161}
162
163impl<T> From<EVMError<T, OpTransactionError>> for OpEthApiError
164where
165 T: Into<EthApiError>,
166{
167 fn from(error: EVMError<T, OpTransactionError>) -> Self {
168 match error {
169 EVMError::Transaction(err) => match err.try_into() {
170 Ok(err) => Self::InvalidTransaction(err),
171 Err(err) => Self::Eth(EthApiError::InvalidTransaction(err.into())),
172 },
173 EVMError::Database(err) => Self::Eth(err.into()),
174 EVMError::Header(err) => Self::Eth(err.into()),
175 EVMError::Precompile(err) => Self::Eth(EthApiError::EvmPrecompile(err)),
176 EVMError::Custom(err) => Self::Eth(EthApiError::EvmCustom(err)),
177 }
178 }
179}
180
181impl FromEvmHalt<OpHaltReason> for OpEthApiError {
182 fn from_evm_halt(halt: OpHaltReason, gas_limit: u64) -> Self {
183 match halt {
184 OpHaltReason::FailedDeposit => {
185 OpInvalidTransactionError::HaltedDepositPostRegolith.into()
186 }
187 OpHaltReason::Base(halt) => EthApiError::from_evm_halt(halt, gas_limit).into(),
188 }
189 }
190}