anvil/eth/
error.rs

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