//! RPC errors specific to OP. use alloy_rpc_types_eth::{error::EthRpcErrorCode, BlockError}; use jsonrpsee_types::error::INTERNAL_ERROR_CODE; use reth_optimism_evm::OpBlockExecutionError; use reth_rpc_eth_api::AsEthApiError; use reth_rpc_eth_types::EthApiError; use reth_rpc_server_types::result::{internal_rpc_err, rpc_err}; use revm::primitives::{InvalidTransaction, OptimismInvalidTransaction}; /// Optimism specific errors, that extend [`EthApiError`]. #[derive(Debug, thiserror::Error)] pub enum OpEthApiError { /// L1 ethereum error. #[error(transparent)] Eth(#[from] EthApiError), /// EVM error originating from invalid optimism data. #[error(transparent)] Evm(#[from] OpBlockExecutionError), /// Thrown when calculating L1 gas fee. #[error("failed to calculate l1 gas fee")] L1BlockFeeError, /// Thrown when calculating L1 gas used #[error("failed to calculate l1 gas used")] L1BlockGasError, /// Wrapper for [`revm_primitives::InvalidTransaction`](InvalidTransaction). #[error(transparent)] InvalidTransaction(#[from] OpInvalidTransactionError), /// Sequencer client error. #[error(transparent)] Sequencer(#[from] SequencerClientError), } impl AsEthApiError for OpEthApiError { fn as_err(&self) -> Option<&EthApiError> { match self { Self::Eth(err) => Some(err), _ => None, } } } impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(err: OpEthApiError) -> Self { match err { OpEthApiError::Eth(err) => err.into(), OpEthApiError::InvalidTransaction(err) => err.into(), OpEthApiError::Evm(_) | OpEthApiError::L1BlockFeeError | OpEthApiError::L1BlockGasError => internal_rpc_err(err.to_string()), OpEthApiError::Sequencer(err) => err.into(), } } } /// Optimism specific invalid transaction errors #[derive(thiserror::Error, Debug)] pub enum OpInvalidTransactionError { /// A deposit transaction was submitted as a system transaction post-regolith. #[error("no system transactions allowed after regolith")] DepositSystemTxPostRegolith, /// A deposit transaction halted post-regolith #[error("deposit transaction halted after regolith")] HaltedDepositPostRegolith, } impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(err: OpInvalidTransactionError) -> Self { match err { OpInvalidTransactionError::DepositSystemTxPostRegolith | OpInvalidTransactionError::HaltedDepositPostRegolith => { rpc_err(EthRpcErrorCode::TransactionRejected.code(), err.to_string(), None) } } } } impl TryFrom for OpInvalidTransactionError { type Error = InvalidTransaction; fn try_from(err: InvalidTransaction) -> Result { match err { InvalidTransaction::OptimismError(err) => match err { OptimismInvalidTransaction::DepositSystemTxPostRegolith => { Ok(Self::DepositSystemTxPostRegolith) } OptimismInvalidTransaction::HaltedDepositPostRegolith => { Ok(Self::HaltedDepositPostRegolith) } }, _ => Err(err), } } } /// Error type when interacting with the Sequencer #[derive(Debug, thiserror::Error)] pub enum SequencerClientError { /// Wrapper around an [`reqwest::Error`]. #[error(transparent)] HttpError(#[from] reqwest::Error), /// Thrown when serializing transaction to forward to sequencer #[error("invalid sequencer transaction")] InvalidSequencerTransaction, } impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(err: SequencerClientError) -> Self { jsonrpsee_types::error::ErrorObject::owned( INTERNAL_ERROR_CODE, err.to_string(), None::, ) } } impl From for OpEthApiError { fn from(error: BlockError) -> Self { Self::Eth(error.into()) } }