Skip to main content

anvil/eth/
error.rs

1//! Aggregated error type for this module
2
3use crate::eth::pool::transactions::PoolTransaction;
4use alloy_consensus::crypto::RecoveryError;
5use alloy_evm::overrides::StateOverrideError;
6use alloy_primitives::{B256, Bytes, SignatureError};
7use alloy_rpc_types::BlockNumberOrTag;
8use alloy_signer::Error as SignerError;
9use alloy_transport::TransportError;
10use anvil_core::eth::wallet::WalletError;
11use anvil_rpc::{
12    error::{ErrorCode, RpcError},
13    response::ResponseResult,
14};
15use foundry_evm::{backend::DatabaseError, decode::RevertDecoder};
16use op_revm::OpTransactionError;
17use revm::{
18    context_interface::result::{EVMError, InvalidHeader, InvalidTransaction},
19    interpreter::InstructionResult,
20};
21use serde::Serialize;
22use tokio::time::Duration;
23
24pub(crate) type Result<T> = std::result::Result<T, BlockchainError>;
25
26#[derive(Debug, thiserror::Error)]
27pub enum BlockchainError {
28    #[error(transparent)]
29    Pool(#[from] PoolError),
30    #[error("No signer available")]
31    NoSignerAvailable,
32    #[error("Chain Id not available")]
33    ChainIdNotAvailable,
34    #[error("Invalid input: `max_priority_fee_per_gas` greater than `max_fee_per_gas`")]
35    InvalidFeeInput,
36    #[error("Transaction data is empty")]
37    EmptyRawTransactionData,
38    #[error("Failed to decode signed transaction")]
39    FailedToDecodeSignedTransaction,
40    #[error("Failed to decode transaction")]
41    FailedToDecodeTransaction,
42    #[error("Failed to decode receipt")]
43    FailedToDecodeReceipt,
44    #[error("Failed to decode state")]
45    FailedToDecodeStateDump,
46    #[error("Prevrandao not in the EVM's environment after merge")]
47    PrevrandaoNotSet,
48    #[error(transparent)]
49    SignatureError(#[from] SignatureError),
50    #[error(transparent)]
51    RecoveryError(#[from] RecoveryError),
52    #[error(transparent)]
53    SignerError(#[from] SignerError),
54    #[error("Rpc Endpoint not implemented")]
55    RpcUnimplemented,
56    #[error("Rpc error {0:?}")]
57    RpcError(RpcError),
58    #[error(transparent)]
59    InvalidTransaction(#[from] InvalidTransactionError),
60    #[error(transparent)]
61    FeeHistory(#[from] FeeHistoryError),
62    #[error(transparent)]
63    AlloyForkProvider(#[from] TransportError),
64    #[error("EVM error {0:?}")]
65    EvmError(InstructionResult),
66    #[error("Evm override error: {0}")]
67    EvmOverrideError(String),
68    #[error("Invalid url {0:?}")]
69    InvalidUrl(String),
70    #[error("Internal error: {0:?}")]
71    Internal(String),
72    #[error("BlockOutOfRangeError: block height is {0} but requested was {1}")]
73    BlockOutOfRange(u64, u64),
74    #[error("Resource not found")]
75    BlockNotFound,
76    /// Thrown when a requested transaction is not found
77    #[error("transaction not found")]
78    TransactionNotFound,
79    #[error("Required data unavailable")]
80    DataUnavailable,
81    #[error("Trie error: {0}")]
82    TrieError(String),
83    #[error("{0}")]
84    UintConversion(&'static str),
85    #[error("State override error: {0}")]
86    StateOverrideError(String),
87    #[error("Timestamp error: {0}")]
88    TimestampError(String),
89    #[error(transparent)]
90    DatabaseError(#[from] DatabaseError),
91    #[error(
92        "EIP-1559 style fee params (maxFeePerGas or maxPriorityFeePerGas) received but they are not supported by the current hardfork.\n\nYou can use them by running anvil with '--hardfork london' or later."
93    )]
94    EIP1559TransactionUnsupportedAtHardfork,
95    #[error(
96        "Access list received but is not supported by the current hardfork.\n\nYou can use it by running anvil with '--hardfork berlin' or later."
97    )]
98    EIP2930TransactionUnsupportedAtHardfork,
99    #[error(
100        "EIP-4844 fields received but is not supported by the current hardfork.\n\nYou can use it by running anvil with '--hardfork cancun' or later."
101    )]
102    EIP4844TransactionUnsupportedAtHardfork,
103    #[error(
104        "EIP-7702 fields received but is not supported by the current hardfork.\n\nYou can use it by running anvil with '--hardfork prague' or later."
105    )]
106    EIP7702TransactionUnsupportedAtHardfork,
107    #[error(
108        "op-stack deposit tx received but is not supported.\n\nYou can use it by running anvil with '--optimism'."
109    )]
110    DepositTransactionUnsupported,
111    #[error("Unknown transaction type not supported")]
112    UnknownTransactionType,
113    #[error("Excess blob gas not set.")]
114    ExcessBlobGasNotSet,
115    #[error("{0}")]
116    Message(String),
117    #[error("Transaction {hash} was added to the mempool but wasn't confirmed within {duration:?}")]
118    TransactionConfirmationTimeout {
119        /// Hash of the transaction that timed out
120        hash: B256,
121        /// Duration that was waited before timing out
122        duration: Duration,
123    },
124    #[error("Invalid transaction request: {0}")]
125    InvalidTransactionRequest(String),
126    #[error("filter not found")]
127    FilterNotFound,
128}
129
130impl From<eyre::Report> for BlockchainError {
131    fn from(err: eyre::Report) -> Self {
132        Self::Message(err.to_string())
133    }
134}
135
136impl From<RpcError> for BlockchainError {
137    fn from(err: RpcError) -> Self {
138        Self::RpcError(err)
139    }
140}
141
142impl<T> From<EVMError<T>> for BlockchainError
143where
144    T: Into<Self>,
145{
146    fn from(err: EVMError<T>) -> Self {
147        match err {
148            EVMError::Transaction(err) => InvalidTransactionError::from(err).into(),
149            EVMError::Header(err) => match err {
150                InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet,
151                InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet,
152            },
153            EVMError::Database(err) => err.into(),
154            EVMError::Custom(err) => Self::Message(err),
155        }
156    }
157}
158
159impl<T> From<EVMError<T, OpTransactionError>> for BlockchainError
160where
161    T: Into<Self>,
162{
163    fn from(err: EVMError<T, OpTransactionError>) -> Self {
164        match err {
165            EVMError::Transaction(err) => match err {
166                OpTransactionError::Base(err) => InvalidTransactionError::from(err).into(),
167                OpTransactionError::DepositSystemTxPostRegolith => {
168                    Self::DepositTransactionUnsupported
169                }
170                OpTransactionError::HaltedDepositPostRegolith => {
171                    Self::DepositTransactionUnsupported
172                }
173                OpTransactionError::MissingEnvelopedTx => Self::InvalidTransaction(err.into()),
174            },
175            EVMError::Header(err) => match err {
176                InvalidHeader::ExcessBlobGasNotSet => Self::ExcessBlobGasNotSet,
177                InvalidHeader::PrevrandaoNotSet => Self::PrevrandaoNotSet,
178            },
179            EVMError::Database(err) => err.into(),
180            EVMError::Custom(err) => Self::Message(err),
181        }
182    }
183}
184
185impl From<WalletError> for BlockchainError {
186    fn from(value: WalletError) -> Self {
187        Self::Message(value.to_string())
188    }
189}
190
191impl<E> From<StateOverrideError<E>> for BlockchainError
192where
193    E: Into<Self>,
194{
195    fn from(value: StateOverrideError<E>) -> Self {
196        match value {
197            StateOverrideError::InvalidBytecode(err) => Self::StateOverrideError(err.to_string()),
198            StateOverrideError::BothStateAndStateDiff(addr) => Self::StateOverrideError(format!(
199                "state and state_diff can't be used together for account {addr}",
200            )),
201            StateOverrideError::Database(err) => err.into(),
202        }
203    }
204}
205
206/// Errors that can occur in the transaction pool
207#[derive(Debug, thiserror::Error)]
208pub enum PoolError {
209    #[error("Transaction with cyclic dependent transactions")]
210    CyclicTransaction,
211    /// Thrown if a replacement transaction's gas price is below the already imported transaction
212    #[error("Tx: [{0:?}] insufficient gas price to replace existing transaction")]
213    ReplacementUnderpriced(Box<PoolTransaction>),
214    #[error("Tx: [{0:?}] already Imported")]
215    AlreadyImported(Box<PoolTransaction>),
216}
217
218/// Errors that can occur with `eth_feeHistory`
219#[derive(Debug, thiserror::Error)]
220pub enum FeeHistoryError {
221    #[error("requested block range is out of bounds")]
222    InvalidBlockRange,
223    #[error("could not find newest block number requested: {0}")]
224    BlockNotFound(BlockNumberOrTag),
225}
226
227#[derive(Debug)]
228pub struct ErrDetail {
229    pub detail: String,
230}
231
232/// An error due to invalid transaction
233#[derive(Debug, thiserror::Error)]
234pub enum InvalidTransactionError {
235    /// returned if the nonce of a transaction is lower than the one present in the local chain.
236    #[error("nonce too low")]
237    NonceTooLow,
238    /// returned if the nonce of a transaction is higher than the next one expected based on the
239    /// local chain.
240    #[error("Nonce too high")]
241    NonceTooHigh,
242    /// Returned if the nonce of a transaction is too high
243    /// Incrementing the nonce would lead to invalid state (overflow)
244    #[error("nonce has max value")]
245    NonceMaxValue,
246    /// thrown if the transaction sender doesn't have enough funds for a transfer
247    #[error("insufficient funds for transfer")]
248    InsufficientFundsForTransfer,
249    /// thrown if creation transaction provides the init code bigger than init code size limit.
250    #[error("max initcode size exceeded")]
251    MaxInitCodeSizeExceeded,
252    /// Represents the inability to cover max cost + value (account balance too low).
253    #[error("Insufficient funds for gas * price + value")]
254    InsufficientFunds,
255    /// Thrown when calculating gas usage
256    #[error("gas uint64 overflow")]
257    GasUintOverflow,
258    /// returned if the transaction is specified to use less gas than required to start the
259    /// invocation.
260    #[error("intrinsic gas too low")]
261    GasTooLow,
262    /// returned if the transaction gas exceeds the limit
263    #[error("intrinsic gas too high -- {}",.0.detail)]
264    GasTooHigh(ErrDetail),
265    /// Thrown to ensure no one is able to specify a transaction with a tip higher than the total
266    /// fee cap.
267    #[error("max priority fee per gas higher than max fee per gas")]
268    TipAboveFeeCap,
269    /// Thrown post London if the transaction's fee is less than the base fee of the block
270    #[error("max fee per gas less than block base fee")]
271    FeeCapTooLow,
272    /// Thrown during estimate if caller has insufficient funds to cover the tx.
273    #[error("Out of gas: gas required exceeds allowance: {0:?}")]
274    BasicOutOfGas(u128),
275    /// Thrown if executing a transaction failed during estimate/call
276    #[error("execution reverted: {0:?}")]
277    Revert(Option<Bytes>),
278    /// Thrown if the sender of a transaction is a contract.
279    #[error("sender not an eoa")]
280    SenderNoEOA,
281    /// Thrown when a tx was signed with a different chain_id
282    #[error("invalid chain id for signer")]
283    InvalidChainId,
284    /// Thrown when a legacy tx was signed for a different chain
285    #[error("Incompatible EIP-155 transaction, signed for another chain")]
286    IncompatibleEIP155,
287    /// Thrown when an access list is used before the berlin hard fork.
288    #[error("Access lists are not supported before the Berlin hardfork")]
289    AccessListNotSupported,
290    /// Thrown when the block's `blob_gas_price` is greater than tx-specified
291    /// `max_fee_per_blob_gas` after Cancun.
292    #[error("Block `blob_gas_price` is greater than tx-specified `max_fee_per_blob_gas`")]
293    BlobFeeCapTooLow(u128, u128),
294    /// Thrown when we receive a tx with `blob_versioned_hashes` and we're not on the Cancun hard
295    /// fork.
296    #[error("Block `blob_versioned_hashes` is not supported before the Cancun hardfork")]
297    BlobVersionedHashesNotSupported,
298    /// Thrown when `max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork.
299    #[error("`max_fee_per_blob_gas` is not supported for blocks before the Cancun hardfork.")]
300    MaxFeePerBlobGasNotSupported,
301    /// Thrown when there are no `blob_hashes` in the transaction, and it is an EIP-4844 tx.
302    #[error("`blob_hashes` are required for EIP-4844 transactions")]
303    NoBlobHashes,
304    #[error("too many blobs in one transaction, have: {0}, max: {1}")]
305    TooManyBlobs(usize, usize),
306    /// Thrown when there's a blob validation error
307    #[error(transparent)]
308    BlobTransactionValidationError(#[from] alloy_consensus::BlobTransactionValidationError),
309    /// Thrown when Blob transaction is a create transaction. `to` must be present.
310    #[error("Blob transaction can't be a create transaction. `to` must be present.")]
311    BlobCreateTransaction,
312    /// Thrown when Blob transaction contains a versioned hash with an incorrect version.
313    #[error("Blob transaction contains a versioned hash with an incorrect version")]
314    BlobVersionNotSupported,
315    /// Thrown when there are no `blob_hashes` in the transaction.
316    #[error("There should be at least one blob in a Blob transaction.")]
317    EmptyBlobs,
318    /// Thrown when an access list is used before the berlin hard fork.
319    #[error("EIP-7702 authorization lists are not supported before the Prague hardfork")]
320    AuthorizationListNotSupported,
321    #[error("Transaction gas limit is greater than the block gas limit, gas_limit: {0}, cap: {1}")]
322    TxGasLimitGreaterThanCap(u64, u64),
323    /// Forwards error from the revm
324    #[error(transparent)]
325    Revm(revm::context_interface::result::InvalidTransaction),
326    /// Deposit transaction error post regolith
327    #[error("op-deposit failure post regolith")]
328    DepositTxErrorPostRegolith,
329    /// Missing enveloped transaction
330    #[error("missing enveloped transaction")]
331    MissingEnvelopedTx,
332}
333
334impl From<InvalidTransaction> for InvalidTransactionError {
335    fn from(err: InvalidTransaction) -> Self {
336        match err {
337            InvalidTransaction::InvalidChainId => Self::InvalidChainId,
338            InvalidTransaction::PriorityFeeGreaterThanMaxFee => Self::TipAboveFeeCap,
339            InvalidTransaction::GasPriceLessThanBasefee => Self::FeeCapTooLow,
340            InvalidTransaction::CallerGasLimitMoreThanBlock => {
341                Self::GasTooHigh(ErrDetail { detail: String::from("CallerGasLimitMoreThanBlock") })
342            }
343            InvalidTransaction::CallGasCostMoreThanGasLimit { .. } => {
344                Self::GasTooHigh(ErrDetail { detail: String::from("CallGasCostMoreThanGasLimit") })
345            }
346            InvalidTransaction::GasFloorMoreThanGasLimit { .. } => {
347                Self::GasTooHigh(ErrDetail { detail: String::from("GasFloorMoreThanGasLimit") })
348            }
349            InvalidTransaction::RejectCallerWithCode => Self::SenderNoEOA,
350            InvalidTransaction::LackOfFundForMaxFee { .. } => Self::InsufficientFunds,
351            InvalidTransaction::OverflowPaymentInTransaction => Self::GasUintOverflow,
352            InvalidTransaction::NonceOverflowInTransaction => Self::NonceMaxValue,
353            InvalidTransaction::CreateInitCodeSizeLimit => Self::MaxInitCodeSizeExceeded,
354            InvalidTransaction::NonceTooHigh { .. } => Self::NonceTooHigh,
355            InvalidTransaction::NonceTooLow { .. } => Self::NonceTooLow,
356            InvalidTransaction::AccessListNotSupported => Self::AccessListNotSupported,
357            InvalidTransaction::BlobGasPriceGreaterThanMax {
358                block_blob_gas_price,
359                tx_max_fee_per_blob_gas,
360            } => Self::BlobFeeCapTooLow(block_blob_gas_price, tx_max_fee_per_blob_gas),
361            InvalidTransaction::BlobVersionedHashesNotSupported => {
362                Self::BlobVersionedHashesNotSupported
363            }
364            InvalidTransaction::MaxFeePerBlobGasNotSupported => Self::MaxFeePerBlobGasNotSupported,
365            InvalidTransaction::BlobCreateTransaction => Self::BlobCreateTransaction,
366            InvalidTransaction::BlobVersionNotSupported => Self::BlobVersionNotSupported,
367            InvalidTransaction::EmptyBlobs => Self::EmptyBlobs,
368            InvalidTransaction::TooManyBlobs { have, max } => Self::TooManyBlobs(have, max),
369            InvalidTransaction::AuthorizationListNotSupported => {
370                Self::AuthorizationListNotSupported
371            }
372            InvalidTransaction::TxGasLimitGreaterThanCap { gas_limit, cap } => {
373                Self::TxGasLimitGreaterThanCap(gas_limit, cap)
374            }
375
376            InvalidTransaction::AuthorizationListInvalidFields
377            | InvalidTransaction::Eip1559NotSupported
378            | InvalidTransaction::Eip2930NotSupported
379            | InvalidTransaction::Eip4844NotSupported
380            | InvalidTransaction::Eip7702NotSupported
381            | InvalidTransaction::EmptyAuthorizationList
382            | InvalidTransaction::Eip7873NotSupported
383            | InvalidTransaction::Eip7873MissingTarget
384            | InvalidTransaction::MissingChainId
385            | InvalidTransaction::Str(_) => Self::Revm(err),
386        }
387    }
388}
389
390impl From<OpTransactionError> for InvalidTransactionError {
391    fn from(value: OpTransactionError) -> Self {
392        match value {
393            OpTransactionError::Base(err) => err.into(),
394            OpTransactionError::DepositSystemTxPostRegolith
395            | OpTransactionError::HaltedDepositPostRegolith => Self::DepositTxErrorPostRegolith,
396            OpTransactionError::MissingEnvelopedTx => Self::MissingEnvelopedTx,
397        }
398    }
399}
400/// Helper trait to easily convert results to rpc results
401pub(crate) trait ToRpcResponseResult {
402    fn to_rpc_result(self) -> ResponseResult;
403}
404
405/// Converts a serializable value into a `ResponseResult`
406pub fn to_rpc_result<T: Serialize>(val: T) -> ResponseResult {
407    match serde_json::to_value(val) {
408        Ok(success) => ResponseResult::Success(success),
409        Err(err) => {
410            error!(%err, "Failed serialize rpc response");
411            ResponseResult::error(RpcError::internal_error())
412        }
413    }
414}
415
416impl<T: Serialize> ToRpcResponseResult for Result<T> {
417    fn to_rpc_result(self) -> ResponseResult {
418        match self {
419            Ok(val) => to_rpc_result(val),
420            Err(err) => match err {
421                BlockchainError::Pool(err) => {
422                    error!(%err, "txpool error");
423                    match err {
424                        PoolError::CyclicTransaction => {
425                            RpcError::transaction_rejected("Cyclic transaction detected")
426                        }
427                        PoolError::ReplacementUnderpriced(_) => {
428                            RpcError::transaction_rejected("replacement transaction underpriced")
429                        }
430                        PoolError::AlreadyImported(_) => {
431                            RpcError::transaction_rejected("transaction already imported")
432                        }
433                    }
434                }
435                BlockchainError::NoSignerAvailable => {
436                    RpcError::invalid_params("No Signer available")
437                }
438                BlockchainError::ChainIdNotAvailable => {
439                    RpcError::invalid_params("Chain Id not available")
440                }
441                BlockchainError::TransactionConfirmationTimeout { .. } => {
442                    RpcError::internal_error_with("Transaction confirmation timeout")
443                }
444                BlockchainError::InvalidTransaction(err) => match err {
445                    InvalidTransactionError::Revert(data) => {
446                        // this mimics geth revert error
447                        let mut msg = "execution reverted".to_string();
448                        if let Some(reason) = data
449                            .as_ref()
450                            .and_then(|data| RevertDecoder::new().maybe_decode(data, None))
451                        {
452                            msg = format!("{msg}: {reason}");
453                        }
454                        RpcError {
455                            // geth returns this error code on reverts, See <https://eips.ethereum.org/EIPS/eip-1474#specification>
456                            code: ErrorCode::ExecutionError,
457                            message: msg.into(),
458                            data: serde_json::to_value(data).ok(),
459                        }
460                    }
461                    InvalidTransactionError::GasTooLow => {
462                        // <https://eips.ethereum.org/EIPS/eip-1898>
463                        RpcError {
464                            code: ErrorCode::ServerError(-32000),
465                            message: err.to_string().into(),
466                            data: None,
467                        }
468                    }
469                    InvalidTransactionError::GasTooHigh(_) => {
470                        // <https://eips.ethereum.org/EIPS/eip-1898>
471                        RpcError {
472                            code: ErrorCode::ServerError(-32000),
473                            message: err.to_string().into(),
474                            data: None,
475                        }
476                    }
477                    _ => RpcError::transaction_rejected(err.to_string()),
478                },
479                BlockchainError::FeeHistory(err) => RpcError::invalid_params(err.to_string()),
480                BlockchainError::EmptyRawTransactionData => {
481                    RpcError::invalid_params("Empty transaction data")
482                }
483                BlockchainError::FailedToDecodeSignedTransaction => {
484                    RpcError::invalid_params("Failed to decode transaction")
485                }
486                BlockchainError::FailedToDecodeTransaction => {
487                    RpcError::invalid_params("Failed to decode transaction")
488                }
489                BlockchainError::FailedToDecodeReceipt => {
490                    RpcError::invalid_params("Failed to decode receipt")
491                }
492                BlockchainError::FailedToDecodeStateDump => {
493                    RpcError::invalid_params("Failed to decode state dump")
494                }
495                BlockchainError::SignerError(err) => RpcError::invalid_params(err.to_string()),
496                BlockchainError::SignatureError(err) => RpcError::invalid_params(err.to_string()),
497                BlockchainError::RpcUnimplemented => {
498                    RpcError::internal_error_with("Not implemented")
499                }
500                BlockchainError::PrevrandaoNotSet => RpcError::internal_error_with(err.to_string()),
501                BlockchainError::RpcError(err) => err,
502                BlockchainError::InvalidFeeInput => RpcError::invalid_params(
503                    "Invalid input: `max_priority_fee_per_gas` greater than `max_fee_per_gas`",
504                ),
505                BlockchainError::AlloyForkProvider(err) => {
506                    error!(target: "backend", %err, "fork provider error");
507                    match err {
508                        TransportError::ErrorResp(err) => RpcError {
509                            code: ErrorCode::from(err.code),
510                            message: err.message,
511                            data: err.data.and_then(|data| serde_json::to_value(data).ok()),
512                        },
513                        err => RpcError::internal_error_with(format!("Fork Error: {err:?}")),
514                    }
515                }
516                err @ BlockchainError::EvmError(_) => {
517                    RpcError::internal_error_with(err.to_string())
518                }
519                err @ BlockchainError::EvmOverrideError(_) => {
520                    RpcError::invalid_params(err.to_string())
521                }
522                err @ BlockchainError::InvalidUrl(_) => RpcError::invalid_params(err.to_string()),
523                BlockchainError::Internal(err) => RpcError::internal_error_with(err),
524                err @ BlockchainError::BlockOutOfRange(_, _) => {
525                    RpcError::invalid_params(err.to_string())
526                }
527                err @ BlockchainError::BlockNotFound => RpcError {
528                    // <https://eips.ethereum.org/EIPS/eip-1898>
529                    code: ErrorCode::ServerError(-32001),
530                    message: err.to_string().into(),
531                    data: None,
532                },
533                err @ BlockchainError::TransactionNotFound => RpcError {
534                    code: ErrorCode::ServerError(-32001),
535                    message: err.to_string().into(),
536                    data: None,
537                },
538                err @ BlockchainError::DataUnavailable => {
539                    RpcError::internal_error_with(err.to_string())
540                }
541                err @ BlockchainError::TrieError(_) => {
542                    RpcError::internal_error_with(err.to_string())
543                }
544                BlockchainError::UintConversion(err) => RpcError::invalid_params(err),
545                err @ BlockchainError::StateOverrideError(_) => {
546                    RpcError::invalid_params(err.to_string())
547                }
548                err @ BlockchainError::TimestampError(_) => {
549                    RpcError::invalid_params(err.to_string())
550                }
551                BlockchainError::DatabaseError(err) => {
552                    RpcError::internal_error_with(err.to_string())
553                }
554                err @ BlockchainError::EIP1559TransactionUnsupportedAtHardfork => {
555                    RpcError::invalid_params(err.to_string())
556                }
557                err @ BlockchainError::EIP2930TransactionUnsupportedAtHardfork => {
558                    RpcError::invalid_params(err.to_string())
559                }
560                err @ BlockchainError::EIP4844TransactionUnsupportedAtHardfork => {
561                    RpcError::invalid_params(err.to_string())
562                }
563                err @ BlockchainError::EIP7702TransactionUnsupportedAtHardfork => {
564                    RpcError::invalid_params(err.to_string())
565                }
566                err @ BlockchainError::DepositTransactionUnsupported => {
567                    RpcError::invalid_params(err.to_string())
568                }
569                err @ BlockchainError::ExcessBlobGasNotSet => {
570                    RpcError::invalid_params(err.to_string())
571                }
572                err @ BlockchainError::Message(_) => RpcError::internal_error_with(err.to_string()),
573                err @ BlockchainError::UnknownTransactionType => {
574                    RpcError::invalid_params(err.to_string())
575                }
576                err @ BlockchainError::InvalidTransactionRequest(_) => {
577                    RpcError::invalid_params(err.to_string())
578                }
579                err @ BlockchainError::RecoveryError(_) => {
580                    RpcError::invalid_params(err.to_string())
581                }
582                BlockchainError::FilterNotFound => RpcError {
583                    code: ErrorCode::ServerError(-32000),
584                    message: "filter not found".into(),
585                    data: None,
586                },
587            }
588            .into(),
589        }
590    }
591}