Skip to main content

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