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