Skip to main content

anvil/eth/
error.rs

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