Skip to main content

anvil/eth/backend/mem/
mod.rs

1//! In-memory blockchain backend.
2
3use self::state::trie_storage;
4use super::executor::new_evm_with_inspector_ref;
5use crate::{
6    ForkChoice, NodeConfig, PrecompileFactory,
7    config::PruneStateHistoryConfig,
8    eth::{
9        backend::{
10            cheats::CheatsManager,
11            db::{Db, MaybeFullDatabase, SerializableState},
12            env::Env,
13            executor::{ExecutedTransactions, TransactionExecutor},
14            fork::ClientFork,
15            genesis::GenesisConfig,
16            mem::{
17                state::{storage_root, trie_accounts},
18                storage::MinedTransactionReceipt,
19            },
20            notifications::{NewBlockNotification, NewBlockNotifications},
21            time::{TimeManager, utc_from_secs},
22            validate::TransactionValidator,
23        },
24        error::{BlockchainError, ErrDetail, InvalidTransactionError},
25        fees::{FeeDetails, FeeManager, MIN_SUGGESTED_PRIORITY_FEE},
26        macros::node_info,
27        pool::transactions::PoolTransaction,
28        sign::build_typed_transaction,
29    },
30    inject_precompiles,
31    mem::{
32        inspector::AnvilInspector,
33        storage::{BlockchainStorage, InMemoryBlockStates, MinedBlockOutcome},
34    },
35};
36use alloy_chains::NamedChain;
37use alloy_consensus::{
38    Account, Blob, BlockHeader, EnvKzgSettings, Header, Receipt, ReceiptWithBloom, Signed,
39    Transaction as TransactionTrait, TxEnvelope,
40    proofs::{calculate_receipt_root, calculate_transaction_root},
41    transaction::Recovered,
42};
43use alloy_eips::{eip1559::BaseFeeParams, eip4844::kzg_to_versioned_hash, eip7840::BlobParams};
44use alloy_evm::{
45    Database, Evm,
46    eth::EthEvmContext,
47    overrides::{OverrideBlockHashes, apply_state_overrides},
48    precompiles::PrecompilesMap,
49};
50use alloy_network::{
51    AnyHeader, AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, AnyTxEnvelope, AnyTxType,
52    EthereumWallet, UnknownTxEnvelope, UnknownTypedTransaction,
53};
54use alloy_primitives::{
55    Address, B256, Bytes, TxHash, TxKind, U64, U256, address, hex, keccak256, logs_bloom,
56    map::HashMap, utils::Unit,
57};
58use alloy_rpc_types::{
59    AccessList, Block as AlloyBlock, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
60    EIP1186AccountProofResponse as AccountProof, EIP1186StorageProof as StorageProof, Filter,
61    Header as AlloyHeader, Index, Log, Transaction, TransactionReceipt,
62    anvil::Forking,
63    request::TransactionRequest,
64    serde_helpers::JsonStorageKey,
65    simulate::{SimBlock, SimCallResult, SimulatePayload, SimulatedBlock},
66    state::EvmOverrides,
67    trace::{
68        filter::TraceFilter,
69        geth::{
70            GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingCallOptions,
71            GethDebugTracingOptions, GethTrace, NoopFrame,
72        },
73        parity::LocalizedTransactionTrace,
74    },
75};
76use alloy_serde::{OtherFields, WithOtherFields};
77use alloy_signer::Signature;
78use alloy_signer_local::PrivateKeySigner;
79use alloy_trie::{HashBuilder, Nibbles, proof::ProofRetainer};
80use anvil_core::eth::{
81    block::{Block, BlockInfo},
82    transaction::{
83        DepositReceipt, MaybeImpersonatedTransaction, PendingTransaction, ReceiptResponse,
84        TransactionInfo, TypedReceipt, TypedTransaction, has_optimism_fields,
85        transaction_request_to_typed,
86    },
87    wallet::{Capabilities, DelegationCapability, WalletCapabilities},
88};
89use anvil_rpc::error::RpcError;
90use chrono::Datelike;
91use eyre::{Context, Result};
92use flate2::{Compression, read::GzDecoder, write::GzEncoder};
93use foundry_evm::{
94    backend::{DatabaseError, DatabaseResult, RevertStateSnapshotAction},
95    constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE,
96    decode::RevertDecoder,
97    inspectors::AccessListInspector,
98    traces::{CallTraceDecoder, TracingInspectorConfig},
99    utils::{get_blob_base_fee_update_fraction, get_blob_base_fee_update_fraction_by_spec_id},
100};
101use foundry_evm_core::either_evm::EitherEvm;
102use futures::channel::mpsc::{UnboundedSender, unbounded};
103use op_alloy_consensus::DEPOSIT_TX_TYPE_ID;
104use op_revm::{
105    OpContext, OpHaltReason, OpTransaction, transaction::deposit::DepositTransactionParts,
106};
107use parking_lot::{Mutex, RwLock};
108use revm::{
109    DatabaseCommit, Inspector,
110    context::{Block as RevmBlock, BlockEnv, TxEnv},
111    context_interface::{
112        block::BlobExcessGasAndPrice,
113        result::{ExecutionResult, Output, ResultAndState},
114    },
115    database::{CacheDB, WrapDatabaseRef},
116    interpreter::InstructionResult,
117    precompile::secp256r1::{P256VERIFY, P256VERIFY_BASE_GAS_FEE},
118    primitives::{KECCAK_EMPTY, hardfork::SpecId},
119    state::AccountInfo,
120};
121use revm_inspectors::transfer::TransferInspector;
122use std::{
123    collections::BTreeMap,
124    fmt::Debug,
125    io::{Read, Write},
126    ops::Not,
127    path::PathBuf,
128    sync::Arc,
129    time::Duration,
130};
131use storage::{Blockchain, DEFAULT_HISTORY_LIMIT, MinedTransaction};
132use tokio::sync::RwLock as AsyncRwLock;
133
134pub mod cache;
135pub mod fork_db;
136pub mod in_memory_db;
137pub mod inspector;
138pub mod state;
139pub mod storage;
140
141/// Helper trait that combines DatabaseRef with Debug.
142/// This is needed because alloy-evm requires Debug on Database implementations.
143/// Specific implementation for dyn Db since trait object upcasting is not stable.
144pub trait DatabaseRef: revm::DatabaseRef<Error = DatabaseError> + Debug {}
145impl<T> DatabaseRef for T where T: revm::DatabaseRef<Error = DatabaseError> + Debug {}
146impl DatabaseRef for dyn crate::eth::backend::db::Db {}
147
148// Gas per transaction not creating a contract.
149pub const MIN_TRANSACTION_GAS: u128 = 21000;
150// Gas per transaction creating a contract.
151pub const MIN_CREATE_GAS: u128 = 53000;
152// Executor
153pub const EXECUTOR: Address = address!("0x6634F723546eCc92277e8a2F93d4f248bf1189ea");
154pub const EXECUTOR_PK: &str = "0x502d47e1421cb9abef497096728e69f07543232b93ef24de4998e18b5fd9ba0f";
155// P256 Batch Delegation Contract: https://odyssey-explorer.ithaca.xyz/address/0x35202a6E6317F3CC3a177EeEE562D3BcDA4a6FcC
156pub const P256_DELEGATION_CONTRACT: Address =
157    address!("0x35202a6e6317f3cc3a177eeee562d3bcda4a6fcc");
158// Runtime code of the P256 delegation contract
159pub const P256_DELEGATION_RUNTIME_CODE: &[u8] = &hex!(
160    "60806040526004361015610018575b361561001657005b005b5f3560e01c806309c5eabe146100c75780630cb6aaf1146100c257806330f6a8e5146100bd5780635fce1927146100b8578063641cdfe2146100b357806376ba882d146100ae5780638d80ff0a146100a9578063972ce4bc146100a4578063a78fc2441461009f578063a82e44e01461009a5763b34893910361000e576108e1565b6108b5565b610786565b610646565b6105ba565b610529565b6103f8565b6103a2565b61034c565b6102c0565b61020b565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176100fc57604052565b6100cc565b6080810190811067ffffffffffffffff8211176100fc57604052565b60a0810190811067ffffffffffffffff8211176100fc57604052565b90601f8019910116810190811067ffffffffffffffff8211176100fc57604052565b6040519061016a608083610139565b565b67ffffffffffffffff81116100fc57601f01601f191660200190565b9291926101948261016c565b916101a26040519384610139565b8294818452818301116101be578281602093845f960137010152565b5f80fd5b9080601f830112156101be578160206101dd93359101610188565b90565b60206003198201126101be576004359067ffffffffffffffff82116101be576101dd916004016101c2565b346101be57610219366101e0565b3033036102295761001690610ae6565b636f6a1b8760e11b5f5260045ffd5b634e487b7160e01b5f52603260045260245ffd5b5f54811015610284575f8080526005919091027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5630191565b610238565b8054821015610284575f52600560205f20910201905f90565b906040516102af816100e0565b602060018294805484520154910152565b346101be5760203660031901126101be576004355f548110156101be576102e69061024c565b5060ff815416600182015491610306600360ff60028401541692016102a2565b926040519215158352602083015260028110156103385760a09260209160408401528051606084015201516080820152f35b634e487b7160e01b5f52602160045260245ffd5b346101be575f3660031901126101be576020600254604051908152f35b6004359063ffffffff821682036101be57565b6064359063ffffffff821682036101be57565b6084359063ffffffff821682036101be57565b346101be5760203660031901126101be576103bb610369565b303303610229576103cb9061024c565b50805460ff19169055005b60609060231901126101be57602490565b60609060831901126101be57608490565b346101be5760803660031901126101be57610411610369565b60205f61041d366103d6565b60015461043161042c82610a0b565b600155565b60405184810191825260e086901b6001600160e01b031916602083015261046581602484015b03601f198101835282610139565b51902060ff61047660408401610a19565b161583146104fe576104b2601b925b85813591013590604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156104f9575f51306001600160a01b03909116036104ea576104df6100169161024c565b50805460ff19169055565b638baa579f60e01b5f5260045ffd5b610a27565b6104b2601c92610485565b60409060031901126101be57600490565b6044359060028210156101be57565b346101be5760803660031901126101be5761054336610509565b61054b61051a565b606435903033036102295761059192610580610587926040519461056e86610101565b60018652602086015260408501610a32565b36906105f3565b6060820152610a3e565b5f545f1981019081116105b55760405163ffffffff919091168152602090f35b0390f35b6109f7565b6100166105c6366101e0565b610ae6565b60409060231901126101be57604051906105e4826100e0565b60243582526044356020830152565b91908260409103126101be5760405161060b816100e0565b6020808294803584520135910152565b6084359081151582036101be57565b60a4359081151582036101be57565b359081151582036101be57565b346101be5760a03660031901126101be5760043567ffffffffffffffff81116101be576106779036906004016101c2565b610680366105cb565b61068861037c565b61069061061b565b906002546106a56106a082610a0b565b600255565b6040516106bb8161045788602083019586610b6a565b51902091610747575b6106d06106d69161024c565b50610b7b565b906106e86106e48351151590565b1590565b610738576020820151801515908161072e575b5061071f576107129260606106e493015191610ce3565b6104ea5761001690610ae6565b632572e3a960e01b5f5260045ffd5b905042115f6106fb565b637dd286d760e11b5f5260045ffd5b905f61077361045761076760209460405192839187830160209181520190565b60405191828092610b58565b039060025afa156104f9575f51906106c4565b346101be5760e03660031901126101be576107a036610509565b6107a861051a565b6064359060205f6107b8366103e7565b6001546107c761042c82610a0b565b60408051808601928352883560208401528589013591830191909152606082018790526107f78160808401610457565b51902060ff61080860408401610a19565b161583146108aa5760408051918252601b602083015282359082015290830135606082015280608081015b838052039060015afa156104f9575f51306001600160a01b03909116036104ea5761087a926105806105879261086761015b565b6001815294602086015260408501610a32565b6105b161089361088a5f54610ad8565b63ffffffff1690565b60405163ffffffff90911681529081906020820190565b610833601c92610485565b346101be575f3660031901126101be576020600154604051908152f35b359061ffff821682036101be57565b346101be5760c03660031901126101be5760043567ffffffffffffffff81116101be576109129036906004016101c2565b61091b366105cb565b906064359167ffffffffffffffff83116101be5760a060031984360301126101be576040516109498161011d565b836004013567ffffffffffffffff81116101be5761096d90600436918701016101c2565b8152602484013567ffffffffffffffff81116101be57840193366023860112156101be5760846109db916109ae610016973690602460048201359101610188565b60208501526109bf604482016108d2565b60408501526109d0606482016108d2565b606085015201610639565b60808201526109e861038f565b916109f161062a565b93610bc3565b634e487b7160e01b5f52601160045260245ffd5b5f1981146105b55760010190565b3560ff811681036101be5790565b6040513d5f823e3d90fd5b60028210156103385752565b5f54680100000000000000008110156100fc57806001610a6192015f555f610289565b610ac557610a7e82511515829060ff801983541691151516179055565b6020820151600182015560028101604083015160028110156103385761016a9360039260609260ff8019835416911617905501519101906020600191805184550151910155565b634e487b7160e01b5f525f60045260245ffd5b5f198101919082116105b557565b80519060205b828110610af857505050565b808201805160f81c600182015160601c91601581015160358201519384915f9493845f14610b4257505050506001146101be575b15610b3a5701605501610aec565b3d5f803e3d5ffd5b5f95508594506055019130811502175af1610b2c565b805191908290602001825e015f815290565b6020906101dd939281520190610b58565b90604051610b8881610101565b6060610bbe6003839560ff8154161515855260018101546020860152610bb860ff60028301541660408701610a32565b016102a2565b910152565b93909192600254610bd66106a082610a0b565b604051610bec8161045789602083019586610b6a565b51902091610c50575b6106d0610c019161024c565b91610c0f6106e48451151590565b6107385760208301518015159081610c46575b5061071f57610c399360606106e494015192610e0d565b6104ea5761016a90610ae6565b905042115f610c22565b905f610c7061045761076760209460405192839187830160209181520190565b039060025afa156104f9575f5190610bf5565b3d15610cad573d90610c948261016c565b91610ca26040519384610139565b82523d5f602084013e565b606090565b8051601f101561028457603f0190565b8051602010156102845760400190565b908151811015610284570160200190565b5f9291839260208251920151906020815191015191604051936020850195865260408501526060840152608083015260a082015260a08152610d2660c082610139565b519060145afa610d34610c83565b81610d74575b81610d43575090565b600160f81b91506001600160f81b031990610d6f90610d6190610cb2565b516001600160f81b03191690565b161490565b80516020149150610d3a565b60405190610d8f604083610139565b6015825274113a3cb832911d113bb2b130baba34371733b2ba1160591b6020830152565b9061016a6001610de3936040519485916c1131b430b63632b733b2911d1160991b6020840152602d830190610b58565b601160f91b815203601e19810185520183610139565b610e069060209392610b58565b9081520190565b92919281516025815110908115610f0a575b50610ef957610e2c610d80565b90610e596106e460208501938451610e53610e4c606089015161ffff1690565b61ffff1690565b91610f9b565b610f01576106e4610e8d610e88610457610e83610ea1956040519283916020830160209181520190565b611012565b610db3565b8351610e53610e4c604088015161ffff1690565b610ef9575f610eb96020925160405191828092610b58565b039060025afa156104f9575f610ee360209261076783519151610457604051938492888401610df9565b039060025afa156104f9576101dd915f51610ce3565b505050505f90565b50505050505f90565b610f2b9150610f1e610d616106e492610cc2565b6080850151151590610f31565b5f610e1f565b906001600160f81b0319600160f81b831601610f955780610f85575b610f8057601f60fb1b600160fb1b821601610f69575b50600190565b600160fc1b90811614610f7c575f610f63565b5f90565b505f90565b50600160fa1b8181161415610f4d565b50505f90565b80519282515f5b858110610fb457505050505050600190565b8083018084116105b5578281101561100757610fe56001600160f81b0319610fdc8488610cd2565b51169187610cd2565b516001600160f81b03191603610ffd57600101610fa2565b5050505050505f90565b505050505050505f90565b80516060929181611021575050565b9092506003600284010460021b604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f603f52602085019282860191602083019460208284010190600460038351955f85525b0191603f8351818160121c16515f538181600c1c1651600153818160061c165160025316516003535f5181520190878210156110db5760049060039061109a565b5095505f93600393604092520160405206600204809303613d3d60f01b81525203825256fea26469706673582212200ba93b78f286a25ece47e9403c47be9862f9b8b70ba1a95098667b90c47308b064736f6c634300081a0033"
161);
162// Experimental ERC20
163pub const EXP_ERC20_CONTRACT: Address = address!("0x238c8CD93ee9F8c7Edf395548eF60c0d2e46665E");
164// Runtime code of the experimental ERC20 contract
165pub const EXP_ERC20_RUNTIME_CODE: &[u8] = &hex!(
166    "60806040526004361015610010575b005b5f3560e01c806306fdde03146106f7578063095ea7b31461068c57806318160ddd1461066757806323b872dd146105a15780632bb7c5951461050e578063313ce567146104f35780633644e5151461045557806340c10f191461043057806370a08231146103fe5780637ecebe00146103cc57806395d89b4114610366578063a9059cbb146102ea578063ad0c8fdd146102ad578063d505accf146100fb5763dd62ed3e0361000e57346100f75760403660031901126100f7576100d261075c565b6100da610772565b602052637f5e9f20600c525f5260206034600c2054604051908152f35b5f80fd5b346100f75760e03660031901126100f75761011461075c565b61011c610772565b6084359160643560443560ff851685036100f757610138610788565b60208101906e04578706572696d656e74455243323608c1b8252519020908242116102a0576040519360018060a01b03169460018060a01b03169565383775081901600e52855f5260c06020600c20958654957f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252602082019586528660408301967fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc688528b6060850198468a528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528688525260a082015220604e526042602c205f5260ff1660205260a43560405260c43560605260208060805f60015afa93853d5103610293577f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92594602094019055856303faf4f960a51b176040526034602c2055a3005b63ddafbaef5f526004601cfd5b631a15a3cc5f526004601cfd5b5f3660031901126100f7576103e834023481046103e814341517156102d65761000e90336107ac565b634e487b7160e01b5f52601160045260245ffd5b346100f75760403660031901126100f75761030361075c565b602435906387a211a2600c52335f526020600c2080548084116103595783900390555f526020600c20818154019055602052600c5160601c335f51602061080d5f395f51905f52602080a3602060405160018152f35b63f4d678b85f526004601cfd5b346100f7575f3660031901126100f757604051604081019080821067ffffffffffffffff8311176103b8576103b491604052600381526204558560ec1b602082015260405191829182610732565b0390f35b634e487b7160e01b5f52604160045260245ffd5b346100f75760203660031901126100f7576103e561075c565b6338377508600c525f52602080600c2054604051908152f35b346100f75760203660031901126100f75761041761075c565b6387a211a2600c525f52602080600c2054604051908152f35b346100f75760403660031901126100f75761000e61044c61075c565b602435906107ac565b346100f7575f3660031901126100f757602060a0610471610788565b828101906e04578706572696d656e74455243323608c1b8252519020604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b346100f7575f3660031901126100f757602060405160128152f35b346100f75760203660031901126100f7576004356387a211a2600c52335f526020600c2090815490818111610359575f80806103e88487839688039055806805345cdf77eb68f44c54036805345cdf77eb68f44c5580835282335f51602061080d5f395f51905f52602083a304818115610598575b3390f11561058d57005b6040513d5f823e3d90fd5b506108fc610583565b346100f75760603660031901126100f7576105ba61075c565b6105c2610772565b604435908260601b33602052637f5e9f208117600c526034600c20908154918219610643575b506387a211a2915017600c526020600c2080548084116103595783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f51602061080d5f395f51905f52602080a3602060405160018152f35b82851161065a57846387a211a293039055856105e8565b6313be252b5f526004601cfd5b346100f7575f3660031901126100f75760206805345cdf77eb68f44c54604051908152f35b346100f75760403660031901126100f7576106a561075c565b60243590602052637f5e9f20600c52335f52806034600c20555f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa3602060405160018152f35b346100f7575f3660031901126100f7576103b4610712610788565b6e04578706572696d656e74455243323608c1b6020820152604051918291825b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100f757565b602435906001600160a01b03821682036100f757565b604051906040820182811067ffffffffffffffff8211176103b857604052600f8252565b6805345cdf77eb68f44c548281019081106107ff576805345cdf77eb68f44c556387a211a2600c525f526020600c20818154019055602052600c5160601c5f5f51602061080d5f395f51905f52602080a3565b63e5cfe9575f526004601cfdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220fbe302881d9891005ba1448ba48547cc1cb17dea1a5c4011dfcb035de325bb1d64736f6c634300081b0033"
167);
168
169pub type State = foundry_evm::utils::StateChangeset;
170
171/// A block request, which includes the Pool Transactions if it's Pending
172#[derive(Debug)]
173pub enum BlockRequest {
174    Pending(Vec<Arc<PoolTransaction>>),
175    Number(u64),
176}
177
178impl BlockRequest {
179    pub fn block_number(&self) -> BlockNumber {
180        match *self {
181            Self::Pending(_) => BlockNumber::Pending,
182            Self::Number(n) => BlockNumber::Number(n),
183        }
184    }
185}
186
187/// Gives access to the [revm::Database]
188#[derive(Clone, Debug)]
189pub struct Backend {
190    /// Access to [`revm::Database`] abstraction.
191    ///
192    /// This will be used in combination with [`alloy_evm::Evm`] and is responsible for feeding
193    /// data to the evm during its execution.
194    ///
195    /// At time of writing, there are two different types of `Db`:
196    ///   - [`MemDb`](crate::mem::in_memory_db::MemDb): everything is stored in memory
197    ///   - [`ForkDb`](crate::mem::fork_db::ForkedDatabase): forks off a remote client, missing
198    ///     data is retrieved via RPC-calls
199    ///
200    /// In order to commit changes to the [`revm::Database`], the [`alloy_evm::Evm`] requires
201    /// mutable access, which requires a write-lock from this `db`. In forking mode, the time
202    /// during which the write-lock is active depends on whether the `ForkDb` can provide all
203    /// requested data from memory or whether it has to retrieve it via RPC calls first. This
204    /// means that it potentially blocks for some time, even taking into account the rate
205    /// limits of RPC endpoints. Therefore the `Db` is guarded by a `tokio::sync::RwLock` here
206    /// so calls that need to read from it, while it's currently written to, don't block. E.g.
207    /// a new block is currently mined and a new [`Self::set_storage_at()`] request is being
208    /// executed.
209    db: Arc<AsyncRwLock<Box<dyn Db>>>,
210    /// stores all block related data in memory.
211    blockchain: Blockchain,
212    /// Historic states of previous blocks.
213    states: Arc<RwLock<InMemoryBlockStates>>,
214    /// Env data of the chain
215    env: Arc<RwLock<Env>>,
216    /// This is set if this is currently forked off another client.
217    fork: Arc<RwLock<Option<ClientFork>>>,
218    /// Provides time related info, like timestamp.
219    time: TimeManager,
220    /// Contains state of custom overrides.
221    cheats: CheatsManager,
222    /// Contains fee data.
223    fees: FeeManager,
224    /// Initialised genesis.
225    genesis: GenesisConfig,
226    /// Listeners for new blocks that get notified when a new block was imported.
227    new_block_listeners: Arc<Mutex<Vec<UnboundedSender<NewBlockNotification>>>>,
228    /// Keeps track of active state snapshots at a specific block.
229    active_state_snapshots: Arc<Mutex<HashMap<U256, (u64, B256)>>>,
230    enable_steps_tracing: bool,
231    print_logs: bool,
232    print_traces: bool,
233    /// Recorder used for decoding traces, used together with print_traces
234    call_trace_decoder: Arc<CallTraceDecoder>,
235    odyssey: bool,
236    /// How to keep history state
237    prune_state_history_config: PruneStateHistoryConfig,
238    /// max number of blocks with transactions in memory
239    transaction_block_keeper: Option<usize>,
240    node_config: Arc<AsyncRwLock<NodeConfig>>,
241    /// Slots in an epoch
242    slots_in_an_epoch: u64,
243    /// Precompiles to inject to the EVM.
244    precompile_factory: Option<Arc<dyn PrecompileFactory>>,
245    /// Prevent race conditions during mining
246    mining: Arc<tokio::sync::Mutex<()>>,
247    // === wallet === //
248    capabilities: Arc<RwLock<WalletCapabilities>>,
249    executor_wallet: Arc<RwLock<Option<EthereumWallet>>>,
250}
251
252impl Backend {
253    /// Initialises the balance of the given accounts
254    #[expect(clippy::too_many_arguments)]
255    pub async fn with_genesis(
256        db: Arc<AsyncRwLock<Box<dyn Db>>>,
257        env: Arc<RwLock<Env>>,
258        genesis: GenesisConfig,
259        fees: FeeManager,
260        fork: Arc<RwLock<Option<ClientFork>>>,
261        enable_steps_tracing: bool,
262        print_logs: bool,
263        print_traces: bool,
264        call_trace_decoder: Arc<CallTraceDecoder>,
265        odyssey: bool,
266        prune_state_history_config: PruneStateHistoryConfig,
267        max_persisted_states: Option<usize>,
268        transaction_block_keeper: Option<usize>,
269        automine_block_time: Option<Duration>,
270        cache_path: Option<PathBuf>,
271        node_config: Arc<AsyncRwLock<NodeConfig>>,
272    ) -> Result<Self> {
273        // if this is a fork then adjust the blockchain storage
274        let blockchain = if let Some(fork) = fork.read().as_ref() {
275            trace!(target: "backend", "using forked blockchain at {}", fork.block_number());
276            Blockchain::forked(fork.block_number(), fork.block_hash(), fork.total_difficulty())
277        } else {
278            let env = env.read();
279            Blockchain::new(
280                &env,
281                env.evm_env.cfg_env.spec,
282                fees.is_eip1559().then(|| fees.base_fee()),
283                genesis.timestamp,
284                genesis.number,
285            )
286        };
287
288        let start_timestamp = if let Some(fork) = fork.read().as_ref() {
289            fork.timestamp()
290        } else {
291            genesis.timestamp
292        };
293
294        let mut states = if prune_state_history_config.is_config_enabled() {
295            // if prune state history is enabled, configure the state cache only for memory
296            prune_state_history_config
297                .max_memory_history
298                .map(|limit| InMemoryBlockStates::new(limit, 0))
299                .unwrap_or_default()
300                .memory_only()
301        } else if max_persisted_states.is_some() {
302            max_persisted_states
303                .map(|limit| InMemoryBlockStates::new(DEFAULT_HISTORY_LIMIT, limit))
304                .unwrap_or_default()
305        } else {
306            Default::default()
307        };
308
309        if let Some(cache_path) = cache_path {
310            states = states.disk_path(cache_path);
311        }
312
313        let (slots_in_an_epoch, precompile_factory) = {
314            let cfg = node_config.read().await;
315            (cfg.slots_in_an_epoch, cfg.precompile_factory.clone())
316        };
317
318        let (capabilities, executor_wallet) = if odyssey {
319            // Insert account that sponsors the delegated txs. And deploy P256 delegation contract.
320            let mut db = db.write().await;
321
322            let _ = db.set_code(
323                P256_DELEGATION_CONTRACT,
324                Bytes::from_static(P256_DELEGATION_RUNTIME_CODE),
325            );
326
327            // Insert EXP ERC20 contract
328            let _ = db.set_code(EXP_ERC20_CONTRACT, Bytes::from_static(EXP_ERC20_RUNTIME_CODE));
329
330            let init_balance = Unit::ETHER.wei().saturating_mul(U256::from(10_000)); // 10K ETH
331
332            // Add ETH
333            let _ = db.set_balance(EXP_ERC20_CONTRACT, init_balance);
334            let _ = db.set_balance(EXECUTOR, init_balance);
335
336            let mut capabilities = WalletCapabilities::default();
337
338            let chain_id = env.read().evm_env.cfg_env.chain_id;
339            capabilities.insert(
340                chain_id,
341                Capabilities {
342                    delegation: DelegationCapability { addresses: vec![P256_DELEGATION_CONTRACT] },
343                },
344            );
345
346            let signer: PrivateKeySigner = EXECUTOR_PK.parse().unwrap();
347
348            let executor_wallet = EthereumWallet::new(signer);
349
350            (capabilities, Some(executor_wallet))
351        } else {
352            (WalletCapabilities::default(), None)
353        };
354
355        let backend = Self {
356            db,
357            blockchain,
358            states: Arc::new(RwLock::new(states)),
359            env,
360            fork,
361            time: TimeManager::new(start_timestamp),
362            cheats: Default::default(),
363            new_block_listeners: Default::default(),
364            fees,
365            genesis,
366            active_state_snapshots: Arc::new(Mutex::new(Default::default())),
367            enable_steps_tracing,
368            print_logs,
369            print_traces,
370            call_trace_decoder,
371            odyssey,
372            prune_state_history_config,
373            transaction_block_keeper,
374            node_config,
375            slots_in_an_epoch,
376            precompile_factory,
377            mining: Arc::new(tokio::sync::Mutex::new(())),
378            capabilities: Arc::new(RwLock::new(capabilities)),
379            executor_wallet: Arc::new(RwLock::new(executor_wallet)),
380        };
381
382        if let Some(interval_block_time) = automine_block_time {
383            backend.update_interval_mine_block_time(interval_block_time);
384        }
385
386        // Note: this can only fail in forking mode, in which case we can't recover
387        backend.apply_genesis().await.wrap_err("failed to create genesis")?;
388        Ok(backend)
389    }
390
391    /// Writes the CREATE2 deployer code directly to the database at the address provided.
392    pub async fn set_create2_deployer(&self, address: Address) -> DatabaseResult<()> {
393        self.set_code(address, Bytes::from_static(DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE)).await?;
394
395        Ok(())
396    }
397
398    /// Get the capabilities of the wallet.
399    ///
400    /// Currently the only capability is [`DelegationCapability`].
401    ///
402    /// [`DelegationCapability`]: anvil_core::eth::wallet::DelegationCapability
403    pub(crate) fn get_capabilities(&self) -> WalletCapabilities {
404        self.capabilities.read().clone()
405    }
406
407    /// Updates memory limits that should be more strict when auto-mine is enabled
408    pub(crate) fn update_interval_mine_block_time(&self, block_time: Duration) {
409        self.states.write().update_interval_mine_block_time(block_time)
410    }
411
412    pub(crate) fn executor_wallet(&self) -> Option<EthereumWallet> {
413        self.executor_wallet.read().clone()
414    }
415
416    /// Adds an address to the [`DelegationCapability`] of the wallet.
417    pub(crate) fn add_capability(&self, address: Address) {
418        let chain_id = self.env.read().evm_env.cfg_env.chain_id;
419        let mut capabilities = self.capabilities.write();
420        let mut capability = capabilities.get(chain_id).cloned().unwrap_or_default();
421        capability.delegation.addresses.push(address);
422        capabilities.insert(chain_id, capability);
423    }
424
425    pub(crate) fn set_executor(&self, executor_pk: String) -> Result<Address, BlockchainError> {
426        let signer: PrivateKeySigner =
427            executor_pk.parse().map_err(|_| RpcError::invalid_params("Invalid private key"))?;
428
429        let executor = signer.address();
430        let wallet = EthereumWallet::new(signer);
431
432        *self.executor_wallet.write() = Some(wallet);
433
434        Ok(executor)
435    }
436
437    /// Applies the configured genesis settings
438    ///
439    /// This will fund, create the genesis accounts
440    async fn apply_genesis(&self) -> Result<(), DatabaseError> {
441        trace!(target: "backend", "setting genesis balances");
442
443        if self.fork.read().is_some() {
444            // fetch all account first
445            let mut genesis_accounts_futures = Vec::with_capacity(self.genesis.accounts.len());
446            for address in self.genesis.accounts.iter().copied() {
447                let db = Arc::clone(&self.db);
448
449                // The forking Database backend can handle concurrent requests, we can fetch all dev
450                // accounts concurrently by spawning the job to a new task
451                genesis_accounts_futures.push(tokio::task::spawn(async move {
452                    let db = db.read().await;
453                    let info = db.basic_ref(address)?.unwrap_or_default();
454                    Ok::<_, DatabaseError>((address, info))
455                }));
456            }
457
458            let genesis_accounts = futures::future::join_all(genesis_accounts_futures).await;
459
460            let mut db = self.db.write().await;
461
462            for res in genesis_accounts {
463                let (address, mut info) = res.unwrap()?;
464                info.balance = self.genesis.balance;
465                db.insert_account(address, info.clone());
466            }
467        } else {
468            let mut db = self.db.write().await;
469            for (account, info) in self.genesis.account_infos() {
470                db.insert_account(account, info);
471            }
472
473            // insert the new genesis hash to the database so it's available for the next block in
474            // the evm
475            db.insert_block_hash(U256::from(self.best_number()), self.best_hash());
476        }
477
478        let db = self.db.write().await;
479        // apply the genesis.json alloc
480        self.genesis.apply_genesis_json_alloc(db)?;
481
482        trace!(target: "backend", "set genesis balances");
483
484        Ok(())
485    }
486
487    /// Sets the account to impersonate
488    ///
489    /// Returns `true` if the account is already impersonated
490    pub fn impersonate(&self, addr: Address) -> bool {
491        if self.cheats.impersonated_accounts().contains(&addr) {
492            return true;
493        }
494        // Ensure EIP-3607 is disabled
495        let mut env = self.env.write();
496        env.evm_env.cfg_env.disable_eip3607 = true;
497        self.cheats.impersonate(addr)
498    }
499
500    /// Removes the account that from the impersonated set
501    ///
502    /// If the impersonated `addr` is a contract then we also reset the code here
503    pub fn stop_impersonating(&self, addr: Address) {
504        self.cheats.stop_impersonating(&addr);
505    }
506
507    /// If set to true will make every account impersonated
508    pub fn auto_impersonate_account(&self, enabled: bool) {
509        self.cheats.set_auto_impersonate_account(enabled);
510    }
511
512    /// Returns the configured fork, if any
513    pub fn get_fork(&self) -> Option<ClientFork> {
514        self.fork.read().clone()
515    }
516
517    /// Returns the database
518    pub fn get_db(&self) -> &Arc<AsyncRwLock<Box<dyn Db>>> {
519        &self.db
520    }
521
522    /// Returns the `AccountInfo` from the database
523    pub async fn get_account(&self, address: Address) -> DatabaseResult<AccountInfo> {
524        Ok(self.db.read().await.basic_ref(address)?.unwrap_or_default())
525    }
526
527    /// Whether we're forked off some remote client
528    pub fn is_fork(&self) -> bool {
529        self.fork.read().is_some()
530    }
531
532    /// Resets the fork to a fresh state
533    pub async fn reset_fork(&self, forking: Forking) -> Result<(), BlockchainError> {
534        if !self.is_fork() {
535            if let Some(eth_rpc_url) = forking.clone().json_rpc_url {
536                let mut env = self.env.read().clone();
537
538                let (db, config) = {
539                    let mut node_config = self.node_config.write().await;
540
541                    // we want to force the correct base fee for the next block during
542                    // `setup_fork_db_config`
543                    node_config.base_fee.take();
544
545                    node_config.setup_fork_db_config(eth_rpc_url, &mut env, &self.fees).await?
546                };
547
548                *self.db.write().await = Box::new(db);
549
550                let fork = ClientFork::new(config, Arc::clone(&self.db));
551
552                *self.env.write() = env;
553                *self.fork.write() = Some(fork);
554            } else {
555                return Err(RpcError::invalid_params(
556                    "Forking not enabled and RPC URL not provided to start forking",
557                )
558                .into());
559            }
560        }
561
562        if let Some(fork) = self.get_fork() {
563            let block_number =
564                forking.block_number.map(BlockNumber::from).unwrap_or(BlockNumber::Latest);
565            // reset the fork entirely and reapply the genesis config
566            fork.reset(forking.json_rpc_url.clone(), block_number).await?;
567            let fork_block_number = fork.block_number();
568            let fork_block = fork
569                .block_by_number(fork_block_number)
570                .await?
571                .ok_or(BlockchainError::BlockNotFound)?;
572            // update all settings related to the forked block
573            {
574                if let Some(fork_url) = forking.json_rpc_url {
575                    self.reset_block_number(fork_url, fork_block_number).await?;
576                } else {
577                    // If rpc url is unspecified, then update the fork with the new block number and
578                    // existing rpc url, this updates the cache path
579                    {
580                        let maybe_fork_url = { self.node_config.read().await.eth_rpc_url.clone() };
581                        if let Some(fork_url) = maybe_fork_url {
582                            self.reset_block_number(fork_url, fork_block_number).await?;
583                        }
584                    }
585
586                    let gas_limit = self.node_config.read().await.fork_gas_limit(&fork_block);
587                    let mut env = self.env.write();
588
589                    env.evm_env.cfg_env.chain_id = fork.chain_id();
590                    env.evm_env.block_env = BlockEnv {
591                        number: U256::from(fork_block_number),
592                        timestamp: U256::from(fork_block.header.timestamp),
593                        gas_limit,
594                        difficulty: fork_block.header.difficulty,
595                        prevrandao: Some(fork_block.header.mix_hash.unwrap_or_default()),
596                        // Keep previous `beneficiary` and `basefee` value
597                        beneficiary: env.evm_env.block_env.beneficiary,
598                        basefee: env.evm_env.block_env.basefee,
599                        ..env.evm_env.block_env.clone()
600                    };
601
602                    // this is the base fee of the current block, but we need the base fee of
603                    // the next block
604                    let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
605                        fork_block.header.gas_used,
606                        gas_limit,
607                        fork_block.header.base_fee_per_gas.unwrap_or_default(),
608                    );
609
610                    self.fees.set_base_fee(next_block_base_fee);
611                }
612
613                // reset the time to the timestamp of the forked block
614                self.time.reset(fork_block.header.timestamp);
615
616                // also reset the total difficulty
617                self.blockchain.storage.write().total_difficulty = fork.total_difficulty();
618            }
619            // reset storage
620            *self.blockchain.storage.write() = BlockchainStorage::forked(
621                fork.block_number(),
622                fork.block_hash(),
623                fork.total_difficulty(),
624            );
625            self.states.write().clear();
626            self.db.write().await.clear();
627
628            self.apply_genesis().await?;
629
630            trace!(target: "backend", "reset fork");
631
632            Ok(())
633        } else {
634            Err(RpcError::invalid_params("Forking not enabled").into())
635        }
636    }
637
638    /// Resets the backend to a fresh in-memory state, clearing all existing data
639    pub async fn reset_to_in_mem(&self) -> Result<(), BlockchainError> {
640        // Clear the fork if any exists
641        *self.fork.write() = None;
642
643        // Get environment and genesis config
644        let env = self.env.read().clone();
645        let genesis_timestamp = self.genesis.timestamp;
646        let genesis_number = self.genesis.number;
647        let spec_id = self.spec_id();
648
649        // Reset environment to genesis state
650        {
651            let mut env = self.env.write();
652            env.evm_env.block_env.number = U256::from(genesis_number);
653            env.evm_env.block_env.timestamp = U256::from(genesis_timestamp);
654            // Reset other block env fields to their defaults
655            env.evm_env.block_env.basefee = self.fees.base_fee();
656            env.evm_env.block_env.prevrandao = Some(B256::ZERO);
657        }
658
659        // Clear all storage and reinitialize with genesis
660        let base_fee = if self.fees.is_eip1559() { Some(self.fees.base_fee()) } else { None };
661        *self.blockchain.storage.write() =
662            BlockchainStorage::new(&env, spec_id, base_fee, genesis_timestamp, genesis_number);
663        self.states.write().clear();
664
665        // Clear the database
666        self.db.write().await.clear();
667
668        // Reset time manager
669        self.time.reset(genesis_timestamp);
670
671        // Reset fees to initial state
672        if self.fees.is_eip1559() {
673            self.fees.set_base_fee(crate::eth::fees::INITIAL_BASE_FEE);
674        }
675
676        self.fees.set_gas_price(crate::eth::fees::INITIAL_GAS_PRICE);
677
678        // Reapply genesis configuration
679        self.apply_genesis().await?;
680
681        trace!(target: "backend", "reset to fresh in-memory state");
682
683        Ok(())
684    }
685
686    async fn reset_block_number(
687        &self,
688        fork_url: String,
689        fork_block_number: u64,
690    ) -> Result<(), BlockchainError> {
691        let mut node_config = self.node_config.write().await;
692        node_config.fork_choice = Some(ForkChoice::Block(fork_block_number as i128));
693
694        let mut env = self.env.read().clone();
695        let (forked_db, client_fork_config) =
696            node_config.setup_fork_db_config(fork_url, &mut env, &self.fees).await?;
697
698        *self.db.write().await = Box::new(forked_db);
699        let fork = ClientFork::new(client_fork_config, Arc::clone(&self.db));
700        *self.fork.write() = Some(fork);
701        *self.env.write() = env;
702
703        Ok(())
704    }
705
706    /// Returns the `TimeManager` responsible for timestamps
707    pub fn time(&self) -> &TimeManager {
708        &self.time
709    }
710
711    /// Returns the `CheatsManager` responsible for executing cheatcodes
712    pub fn cheats(&self) -> &CheatsManager {
713        &self.cheats
714    }
715
716    /// Whether to skip blob validation
717    pub fn skip_blob_validation(&self, impersonator: Option<Address>) -> bool {
718        self.cheats().auto_impersonate_accounts()
719            || impersonator
720                .is_some_and(|addr| self.cheats().impersonated_accounts().contains(&addr))
721    }
722
723    /// Returns the `FeeManager` that manages fee/pricings
724    pub fn fees(&self) -> &FeeManager {
725        &self.fees
726    }
727
728    /// The env data of the blockchain
729    pub fn env(&self) -> &Arc<RwLock<Env>> {
730        &self.env
731    }
732
733    /// Returns the current best hash of the chain
734    pub fn best_hash(&self) -> B256 {
735        self.blockchain.storage.read().best_hash
736    }
737
738    /// Returns the current best number of the chain
739    pub fn best_number(&self) -> u64 {
740        self.blockchain.storage.read().best_number
741    }
742
743    /// Sets the block number
744    pub fn set_block_number(&self, number: u64) {
745        let mut env = self.env.write();
746        env.evm_env.block_env.number = U256::from(number);
747    }
748
749    /// Returns the client coinbase address.
750    pub fn coinbase(&self) -> Address {
751        self.env.read().evm_env.block_env.beneficiary
752    }
753
754    /// Returns the client coinbase address.
755    pub fn chain_id(&self) -> U256 {
756        U256::from(self.env.read().evm_env.cfg_env.chain_id)
757    }
758
759    pub fn set_chain_id(&self, chain_id: u64) {
760        self.env.write().evm_env.cfg_env.chain_id = chain_id;
761    }
762
763    /// Returns balance of the given account.
764    pub async fn current_balance(&self, address: Address) -> DatabaseResult<U256> {
765        Ok(self.get_account(address).await?.balance)
766    }
767
768    /// Returns balance of the given account.
769    pub async fn current_nonce(&self, address: Address) -> DatabaseResult<u64> {
770        Ok(self.get_account(address).await?.nonce)
771    }
772
773    /// Sets the coinbase address
774    pub fn set_coinbase(&self, address: Address) {
775        self.env.write().evm_env.block_env.beneficiary = address;
776    }
777
778    /// Sets the nonce of the given address
779    pub async fn set_nonce(&self, address: Address, nonce: U256) -> DatabaseResult<()> {
780        self.db.write().await.set_nonce(address, nonce.try_into().unwrap_or(u64::MAX))
781    }
782
783    /// Sets the balance of the given address
784    pub async fn set_balance(&self, address: Address, balance: U256) -> DatabaseResult<()> {
785        self.db.write().await.set_balance(address, balance)
786    }
787
788    /// Sets the code of the given address
789    pub async fn set_code(&self, address: Address, code: Bytes) -> DatabaseResult<()> {
790        self.db.write().await.set_code(address, code.0.into())
791    }
792
793    /// Sets the value for the given slot of the given address
794    pub async fn set_storage_at(
795        &self,
796        address: Address,
797        slot: U256,
798        val: B256,
799    ) -> DatabaseResult<()> {
800        self.db.write().await.set_storage_at(address, slot.into(), val)
801    }
802
803    /// Returns the configured specid
804    pub fn spec_id(&self) -> SpecId {
805        self.env.read().evm_env.cfg_env.spec
806    }
807
808    /// Returns true for post London
809    pub fn is_eip1559(&self) -> bool {
810        (self.spec_id() as u8) >= (SpecId::LONDON as u8)
811    }
812
813    /// Returns true for post Merge
814    pub fn is_eip3675(&self) -> bool {
815        (self.spec_id() as u8) >= (SpecId::MERGE as u8)
816    }
817
818    /// Returns true for post Berlin
819    pub fn is_eip2930(&self) -> bool {
820        (self.spec_id() as u8) >= (SpecId::BERLIN as u8)
821    }
822
823    /// Returns true for post Cancun
824    pub fn is_eip4844(&self) -> bool {
825        (self.spec_id() as u8) >= (SpecId::CANCUN as u8)
826    }
827
828    /// Returns true for post Prague
829    pub fn is_eip7702(&self) -> bool {
830        (self.spec_id() as u8) >= (SpecId::PRAGUE as u8)
831    }
832
833    /// Returns true if op-stack deposits are active
834    pub fn is_optimism(&self) -> bool {
835        self.env.read().is_optimism
836    }
837
838    /// Returns [`BlobParams`] corresponding to the current spec.
839    pub fn blob_params(&self) -> BlobParams {
840        let spec_id = self.env.read().evm_env.cfg_env.spec;
841
842        if spec_id >= SpecId::OSAKA {
843            return BlobParams::osaka();
844        }
845
846        if spec_id >= SpecId::PRAGUE {
847            return BlobParams::prague();
848        }
849
850        BlobParams::cancun()
851    }
852
853    /// Returns an error if EIP1559 is not active (pre Berlin)
854    pub fn ensure_eip1559_active(&self) -> Result<(), BlockchainError> {
855        if self.is_eip1559() {
856            return Ok(());
857        }
858        Err(BlockchainError::EIP1559TransactionUnsupportedAtHardfork)
859    }
860
861    /// Returns an error if EIP1559 is not active (pre muirGlacier)
862    pub fn ensure_eip2930_active(&self) -> Result<(), BlockchainError> {
863        if self.is_eip2930() {
864            return Ok(());
865        }
866        Err(BlockchainError::EIP2930TransactionUnsupportedAtHardfork)
867    }
868
869    pub fn ensure_eip4844_active(&self) -> Result<(), BlockchainError> {
870        if self.is_eip4844() {
871            return Ok(());
872        }
873        Err(BlockchainError::EIP4844TransactionUnsupportedAtHardfork)
874    }
875
876    pub fn ensure_eip7702_active(&self) -> Result<(), BlockchainError> {
877        if self.is_eip7702() {
878            return Ok(());
879        }
880        Err(BlockchainError::EIP7702TransactionUnsupportedAtHardfork)
881    }
882
883    /// Returns an error if op-stack deposits are not active
884    pub fn ensure_op_deposits_active(&self) -> Result<(), BlockchainError> {
885        if self.is_optimism() {
886            return Ok(());
887        }
888        Err(BlockchainError::DepositTransactionUnsupported)
889    }
890
891    /// Returns the block gas limit
892    pub fn gas_limit(&self) -> u64 {
893        self.env.read().evm_env.block_env.gas_limit
894    }
895
896    /// Sets the block gas limit
897    pub fn set_gas_limit(&self, gas_limit: u64) {
898        self.env.write().evm_env.block_env.gas_limit = gas_limit;
899    }
900
901    /// Returns the current base fee
902    pub fn base_fee(&self) -> u64 {
903        self.fees.base_fee()
904    }
905
906    /// Returns whether the minimum suggested priority fee is enforced
907    pub fn is_min_priority_fee_enforced(&self) -> bool {
908        self.fees.is_min_priority_fee_enforced()
909    }
910
911    pub fn excess_blob_gas_and_price(&self) -> Option<BlobExcessGasAndPrice> {
912        self.fees.excess_blob_gas_and_price()
913    }
914
915    /// Sets the current basefee
916    pub fn set_base_fee(&self, basefee: u64) {
917        self.fees.set_base_fee(basefee)
918    }
919
920    /// Sets the gas price
921    pub fn set_gas_price(&self, price: u128) {
922        self.fees.set_gas_price(price)
923    }
924
925    pub fn elasticity(&self) -> f64 {
926        self.fees.elasticity()
927    }
928
929    /// Returns the total difficulty of the chain until this block
930    ///
931    /// Note: this will always be `0` in memory mode
932    /// In forking mode this will always be the total difficulty of the forked block
933    pub fn total_difficulty(&self) -> U256 {
934        self.blockchain.storage.read().total_difficulty
935    }
936
937    /// Creates a new `evm_snapshot` at the current height.
938    ///
939    /// Returns the id of the snapshot created.
940    pub async fn create_state_snapshot(&self) -> U256 {
941        let num = self.best_number();
942        let hash = self.best_hash();
943        let id = self.db.write().await.snapshot_state();
944        trace!(target: "backend", "creating snapshot {} at {}", id, num);
945        self.active_state_snapshots.lock().insert(id, (num, hash));
946        id
947    }
948
949    /// Reverts the state to the state snapshot identified by the given `id`.
950    pub async fn revert_state_snapshot(&self, id: U256) -> Result<bool, BlockchainError> {
951        let block = { self.active_state_snapshots.lock().remove(&id) };
952        if let Some((num, hash)) = block {
953            let best_block_hash = {
954                // revert the storage that's newer than the snapshot
955                let current_height = self.best_number();
956                let mut storage = self.blockchain.storage.write();
957
958                for n in ((num + 1)..=current_height).rev() {
959                    trace!(target: "backend", "reverting block {}", n);
960                    if let Some(hash) = storage.hashes.remove(&n)
961                        && let Some(block) = storage.blocks.remove(&hash)
962                    {
963                        for tx in block.transactions {
964                            let _ = storage.transactions.remove(&tx.hash());
965                        }
966                    }
967                }
968
969                storage.best_number = num;
970                storage.best_hash = hash;
971                hash
972            };
973            let block =
974                self.block_by_hash(best_block_hash).await?.ok_or(BlockchainError::BlockNotFound)?;
975
976            let reset_time = block.header.timestamp;
977            self.time.reset(reset_time);
978
979            let mut env = self.env.write();
980            env.evm_env.block_env = BlockEnv {
981                number: U256::from(num),
982                timestamp: U256::from(block.header.timestamp),
983                difficulty: block.header.difficulty,
984                // ensures prevrandao is set
985                prevrandao: Some(block.header.mix_hash.unwrap_or_default()),
986                gas_limit: block.header.gas_limit,
987                // Keep previous `beneficiary` and `basefee` value
988                beneficiary: env.evm_env.block_env.beneficiary,
989                basefee: env.evm_env.block_env.basefee,
990                ..Default::default()
991            }
992        }
993        Ok(self.db.write().await.revert_state(id, RevertStateSnapshotAction::RevertRemove))
994    }
995
996    pub fn list_state_snapshots(&self) -> BTreeMap<U256, (u64, B256)> {
997        self.active_state_snapshots.lock().clone().into_iter().collect()
998    }
999
1000    /// Get the current state.
1001    pub async fn serialized_state(
1002        &self,
1003        preserve_historical_states: bool,
1004    ) -> Result<SerializableState, BlockchainError> {
1005        let at = self.env.read().evm_env.block_env.clone();
1006        let best_number = self.blockchain.storage.read().best_number;
1007        let blocks = self.blockchain.storage.read().serialized_blocks();
1008        let transactions = self.blockchain.storage.read().serialized_transactions();
1009        let historical_states = if preserve_historical_states {
1010            Some(self.states.write().serialized_states())
1011        } else {
1012            None
1013        };
1014
1015        let state = self.db.read().await.dump_state(
1016            at,
1017            best_number,
1018            blocks,
1019            transactions,
1020            historical_states,
1021        )?;
1022        state.ok_or_else(|| {
1023            RpcError::invalid_params("Dumping state not supported with the current configuration")
1024                .into()
1025        })
1026    }
1027
1028    /// Write all chain data to serialized bytes buffer
1029    pub async fn dump_state(
1030        &self,
1031        preserve_historical_states: bool,
1032    ) -> Result<Bytes, BlockchainError> {
1033        let state = self.serialized_state(preserve_historical_states).await?;
1034        let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
1035        encoder
1036            .write_all(&serde_json::to_vec(&state).unwrap_or_default())
1037            .map_err(|_| BlockchainError::DataUnavailable)?;
1038        Ok(encoder.finish().unwrap_or_default().into())
1039    }
1040
1041    /// Apply [SerializableState] data to the backend storage.
1042    pub async fn load_state(&self, state: SerializableState) -> Result<bool, BlockchainError> {
1043        // load the blocks and transactions into the storage
1044        self.blockchain.storage.write().load_blocks(state.blocks.clone());
1045        self.blockchain.storage.write().load_transactions(state.transactions.clone());
1046        // reset the block env
1047        if let Some(block) = state.block.clone() {
1048            self.env.write().evm_env.block_env = block.clone();
1049
1050            // Set the current best block number.
1051            // Defaults to block number for compatibility with existing state files.
1052            let fork_num_and_hash = self.get_fork().map(|f| (f.block_number(), f.block_hash()));
1053
1054            let best_number = state.best_block_number.unwrap_or(block.number.saturating_to());
1055            if let Some((number, hash)) = fork_num_and_hash {
1056                trace!(target: "backend", state_block_number=?best_number, fork_block_number=?number);
1057                // If the state.block_number is greater than the fork block number, set best number
1058                // to the state block number.
1059                // Ref: https://github.com/foundry-rs/foundry/issues/9539
1060                if best_number > number {
1061                    self.blockchain.storage.write().best_number = best_number;
1062                    let best_hash =
1063                        self.blockchain.storage.read().hash(best_number.into()).ok_or_else(
1064                            || {
1065                                BlockchainError::RpcError(RpcError::internal_error_with(format!(
1066                                    "Best hash not found for best number {best_number}",
1067                                )))
1068                            },
1069                        )?;
1070                    self.blockchain.storage.write().best_hash = best_hash;
1071                } else {
1072                    // If loading state file on a fork, set best number to the fork block number.
1073                    // Ref: https://github.com/foundry-rs/foundry/pull/9215#issue-2618681838
1074                    self.blockchain.storage.write().best_number = number;
1075                    self.blockchain.storage.write().best_hash = hash;
1076                }
1077            } else {
1078                self.blockchain.storage.write().best_number = best_number;
1079
1080                // Set the current best block hash;
1081                let best_hash =
1082                    self.blockchain.storage.read().hash(best_number.into()).ok_or_else(|| {
1083                        BlockchainError::RpcError(RpcError::internal_error_with(format!(
1084                            "Best hash not found for best number {best_number}",
1085                        )))
1086                    })?;
1087
1088                self.blockchain.storage.write().best_hash = best_hash;
1089            }
1090        }
1091
1092        if let Some(latest) = state.blocks.iter().max_by_key(|b| b.header.number) {
1093            let header = &latest.header;
1094            let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
1095                header.gas_used,
1096                header.gas_limit,
1097                header.base_fee_per_gas.unwrap_or_default(),
1098            );
1099            let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(
1100                header.excess_blob_gas.unwrap_or_default(),
1101                header.blob_gas_used.unwrap_or_default(),
1102            );
1103
1104            // update next base fee
1105            self.fees.set_base_fee(next_block_base_fee);
1106
1107            self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1108                next_block_excess_blob_gas,
1109                get_blob_base_fee_update_fraction(
1110                    self.env.read().evm_env.cfg_env.chain_id,
1111                    header.timestamp,
1112                ),
1113            ));
1114        }
1115
1116        if !self.db.write().await.load_state(state.clone())? {
1117            return Err(RpcError::invalid_params(
1118                "Loading state not supported with the current configuration",
1119            )
1120            .into());
1121        }
1122
1123        if let Some(historical_states) = state.historical_states {
1124            self.states.write().load_states(historical_states);
1125        }
1126
1127        Ok(true)
1128    }
1129
1130    /// Deserialize and add all chain data to the backend storage
1131    pub async fn load_state_bytes(&self, buf: Bytes) -> Result<bool, BlockchainError> {
1132        let orig_buf = &buf.0[..];
1133        let mut decoder = GzDecoder::new(orig_buf);
1134        let mut decoded_data = Vec::new();
1135
1136        let state: SerializableState = serde_json::from_slice(if decoder.header().is_some() {
1137            decoder
1138                .read_to_end(decoded_data.as_mut())
1139                .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;
1140            &decoded_data
1141        } else {
1142            &buf.0
1143        })
1144        .map_err(|_| BlockchainError::FailedToDecodeStateDump)?;
1145
1146        self.load_state(state).await
1147    }
1148
1149    /// Returns the environment for the next block
1150    fn next_env(&self) -> Env {
1151        let mut env = self.env.read().clone();
1152        // increase block number for this block
1153        env.evm_env.block_env.number = env.evm_env.block_env.number.saturating_add(U256::from(1));
1154        env.evm_env.block_env.basefee = self.base_fee();
1155        env.evm_env.block_env.timestamp = U256::from(self.time.current_call_timestamp());
1156        env
1157    }
1158
1159    /// Creates an EVM instance with optionally injected precompiles.
1160    fn new_evm_with_inspector_ref<'db, I, DB>(
1161        &self,
1162        db: &'db DB,
1163        env: &Env,
1164        inspector: &'db mut I,
1165    ) -> EitherEvm<WrapDatabaseRef<&'db DB>, &'db mut I, PrecompilesMap>
1166    where
1167        DB: DatabaseRef + ?Sized,
1168        I: Inspector<EthEvmContext<WrapDatabaseRef<&'db DB>>>
1169            + Inspector<OpContext<WrapDatabaseRef<&'db DB>>>,
1170        WrapDatabaseRef<&'db DB>: Database<Error = DatabaseError>,
1171    {
1172        let mut evm = new_evm_with_inspector_ref(db, env, inspector);
1173
1174        if self.odyssey {
1175            inject_precompiles(&mut evm, vec![(P256VERIFY, P256VERIFY_BASE_GAS_FEE)]);
1176        }
1177
1178        if let Some(factory) = &self.precompile_factory {
1179            inject_precompiles(&mut evm, factory.precompiles());
1180        }
1181
1182        evm
1183    }
1184
1185    /// executes the transactions without writing to the underlying database
1186    pub async fn inspect_tx(
1187        &self,
1188        tx: Arc<PoolTransaction>,
1189    ) -> Result<
1190        (InstructionResult, Option<Output>, u64, State, Vec<revm::primitives::Log>),
1191        BlockchainError,
1192    > {
1193        let mut env = self.next_env();
1194        env.tx = tx.pending_transaction.to_revm_tx_env();
1195
1196        if env.is_optimism {
1197            env.tx.enveloped_tx =
1198                Some(alloy_rlp::encode(&tx.pending_transaction.transaction.transaction).into());
1199        }
1200
1201        let db = self.db.read().await;
1202        let mut inspector = self.build_inspector();
1203        let mut evm = self.new_evm_with_inspector_ref(&**db, &env, &mut inspector);
1204        let ResultAndState { result, state } = evm.transact(env.tx)?;
1205        let (exit_reason, gas_used, out, logs) = match result {
1206            ExecutionResult::Success { reason, gas_used, logs, output, .. } => {
1207                (reason.into(), gas_used, Some(output), Some(logs))
1208            }
1209            ExecutionResult::Revert { gas_used, output } => {
1210                (InstructionResult::Revert, gas_used, Some(Output::Call(output)), None)
1211            }
1212            ExecutionResult::Halt { reason, gas_used } => {
1213                let eth_reason = op_haltreason_to_instruction_result(reason);
1214                (eth_reason, gas_used, None, None)
1215            }
1216        };
1217
1218        drop(evm);
1219        inspector.print_logs();
1220
1221        if self.print_traces {
1222            inspector.print_traces(self.call_trace_decoder.clone());
1223        }
1224
1225        Ok((exit_reason, out, gas_used, state, logs.unwrap_or_default()))
1226    }
1227
1228    /// Creates the pending block
1229    ///
1230    /// This will execute all transaction in the order they come but will not mine the block
1231    pub async fn pending_block(&self, pool_transactions: Vec<Arc<PoolTransaction>>) -> BlockInfo {
1232        self.with_pending_block(pool_transactions, |_, block| block).await
1233    }
1234
1235    /// Creates the pending block
1236    ///
1237    /// This will execute all transaction in the order they come but will not mine the block
1238    pub async fn with_pending_block<F, T>(
1239        &self,
1240        pool_transactions: Vec<Arc<PoolTransaction>>,
1241        f: F,
1242    ) -> T
1243    where
1244        F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockInfo) -> T,
1245    {
1246        let db = self.db.read().await;
1247        let env = self.next_env();
1248
1249        let mut cache_db = CacheDB::new(&*db);
1250
1251        let storage = self.blockchain.storage.read();
1252
1253        let executor = TransactionExecutor {
1254            db: &mut cache_db,
1255            validator: self,
1256            pending: pool_transactions.into_iter(),
1257            block_env: env.evm_env.block_env.clone(),
1258            cfg_env: env.evm_env.cfg_env,
1259            parent_hash: storage.best_hash,
1260            gas_used: 0,
1261            blob_gas_used: 0,
1262            enable_steps_tracing: self.enable_steps_tracing,
1263            print_logs: self.print_logs,
1264            print_traces: self.print_traces,
1265            call_trace_decoder: self.call_trace_decoder.clone(),
1266            precompile_factory: self.precompile_factory.clone(),
1267            odyssey: self.odyssey,
1268            optimism: self.is_optimism(),
1269            blob_params: self.blob_params(),
1270        };
1271
1272        // create a new pending block
1273        let executed = executor.execute();
1274        f(Box::new(cache_db), executed.block)
1275    }
1276
1277    /// Mines a new block and stores it.
1278    ///
1279    /// this will execute all transaction in the order they come in and return all the markers they
1280    /// provide.
1281    pub async fn mine_block(
1282        &self,
1283        pool_transactions: Vec<Arc<PoolTransaction>>,
1284    ) -> MinedBlockOutcome {
1285        self.do_mine_block(pool_transactions).await
1286    }
1287
1288    async fn do_mine_block(
1289        &self,
1290        pool_transactions: Vec<Arc<PoolTransaction>>,
1291    ) -> MinedBlockOutcome {
1292        let _mining_guard = self.mining.lock().await;
1293        trace!(target: "backend", "creating new block with {} transactions", pool_transactions.len());
1294
1295        let (outcome, header, block_hash) = {
1296            let current_base_fee = self.base_fee();
1297            let current_excess_blob_gas_and_price = self.excess_blob_gas_and_price();
1298
1299            let mut env = self.env.read().clone();
1300
1301            if env.evm_env.block_env.basefee == 0 {
1302                // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`
1303                // 0 is only possible if it's manually set
1304                env.evm_env.cfg_env.disable_base_fee = true;
1305            }
1306
1307            let block_number = self.blockchain.storage.read().best_number.saturating_add(1);
1308
1309            // increase block number for this block
1310            if is_arbitrum(env.evm_env.cfg_env.chain_id) {
1311                // Temporary set `env.block.number` to `block_number` for Arbitrum chains.
1312                env.evm_env.block_env.number = U256::from(block_number);
1313            } else {
1314                env.evm_env.block_env.number =
1315                    env.evm_env.block_env.number.saturating_add(U256::from(1));
1316            }
1317
1318            env.evm_env.block_env.basefee = current_base_fee;
1319            env.evm_env.block_env.blob_excess_gas_and_price = current_excess_blob_gas_and_price;
1320
1321            // pick a random value for prevrandao
1322            env.evm_env.block_env.prevrandao = Some(B256::random());
1323
1324            let best_hash = self.blockchain.storage.read().best_hash;
1325
1326            if self.prune_state_history_config.is_state_history_supported() {
1327                let db = self.db.read().await.current_state();
1328                // store current state before executing all transactions
1329                self.states.write().insert(best_hash, db);
1330            }
1331
1332            let (executed_tx, block_hash) = {
1333                let mut db = self.db.write().await;
1334
1335                // finally set the next block timestamp, this is done just before execution, because
1336                // there can be concurrent requests that can delay acquiring the db lock and we want
1337                // to ensure the timestamp is as close as possible to the actual execution.
1338                env.evm_env.block_env.timestamp = U256::from(self.time.next_timestamp());
1339
1340                let executor = TransactionExecutor {
1341                    db: &mut **db,
1342                    validator: self,
1343                    pending: pool_transactions.into_iter(),
1344                    block_env: env.evm_env.block_env.clone(),
1345                    cfg_env: env.evm_env.cfg_env.clone(),
1346                    parent_hash: best_hash,
1347                    gas_used: 0,
1348                    blob_gas_used: 0,
1349                    enable_steps_tracing: self.enable_steps_tracing,
1350                    print_logs: self.print_logs,
1351                    print_traces: self.print_traces,
1352                    call_trace_decoder: self.call_trace_decoder.clone(),
1353                    odyssey: self.odyssey,
1354                    precompile_factory: self.precompile_factory.clone(),
1355                    optimism: self.is_optimism(),
1356                    blob_params: self.blob_params(),
1357                };
1358                let executed_tx = executor.execute();
1359
1360                // we also need to update the new blockhash in the db itself
1361                let block_hash = executed_tx.block.block.header.hash_slow();
1362                db.insert_block_hash(U256::from(executed_tx.block.block.header.number), block_hash);
1363
1364                (executed_tx, block_hash)
1365            };
1366
1367            // create the new block with the current timestamp
1368            let ExecutedTransactions { block, included, invalid } = executed_tx;
1369            let BlockInfo { block, transactions, receipts } = block;
1370
1371            let header = block.header.clone();
1372
1373            trace!(
1374                target: "backend",
1375                "Mined block {} with {} tx {:?}",
1376                block_number,
1377                transactions.len(),
1378                transactions.iter().map(|tx| tx.transaction_hash).collect::<Vec<_>>()
1379            );
1380            let mut storage = self.blockchain.storage.write();
1381            // update block metadata
1382            storage.best_number = block_number;
1383            storage.best_hash = block_hash;
1384            // Difficulty is removed and not used after Paris (aka TheMerge). Value is replaced with
1385            // prevrandao. https://github.com/bluealloy/revm/blob/1839b3fce8eaeebb85025576f2519b80615aca1e/crates/interpreter/src/instructions/host_env.rs#L27
1386            if !self.is_eip3675() {
1387                storage.total_difficulty =
1388                    storage.total_difficulty.saturating_add(header.difficulty);
1389            }
1390
1391            storage.blocks.insert(block_hash, block);
1392            storage.hashes.insert(block_number, block_hash);
1393
1394            node_info!("");
1395            // insert all transactions
1396            for (info, receipt) in transactions.into_iter().zip(receipts) {
1397                // log some tx info
1398                node_info!("    Transaction: {:?}", info.transaction_hash);
1399                if let Some(contract) = &info.contract_address {
1400                    node_info!("    Contract created: {contract}");
1401                }
1402                node_info!("    Gas used: {}", receipt.cumulative_gas_used());
1403                if !info.exit.is_ok() {
1404                    let r = RevertDecoder::new().decode(
1405                        info.out.as_ref().map(|b| &b[..]).unwrap_or_default(),
1406                        Some(info.exit),
1407                    );
1408                    node_info!("    Error: reverted with: {r}");
1409                }
1410                node_info!("");
1411
1412                let mined_tx = MinedTransaction { info, receipt, block_hash, block_number };
1413                storage.transactions.insert(mined_tx.info.transaction_hash, mined_tx);
1414            }
1415
1416            // remove old transactions that exceed the transaction block keeper
1417            if let Some(transaction_block_keeper) = self.transaction_block_keeper
1418                && storage.blocks.len() > transaction_block_keeper
1419            {
1420                let to_clear = block_number
1421                    .saturating_sub(transaction_block_keeper.try_into().unwrap_or(u64::MAX));
1422                storage.remove_block_transactions_by_number(to_clear)
1423            }
1424
1425            // we intentionally set the difficulty to `0` for newer blocks
1426            env.evm_env.block_env.difficulty = U256::from(0);
1427
1428            // update env with new values
1429            *self.env.write() = env;
1430
1431            let timestamp = utc_from_secs(header.timestamp);
1432
1433            node_info!("    Block Number: {}", block_number);
1434            node_info!("    Block Hash: {:?}", block_hash);
1435            if timestamp.year() > 9999 {
1436                // rf2822 panics with more than 4 digits
1437                node_info!("    Block Time: {:?}\n", timestamp.to_rfc3339());
1438            } else {
1439                node_info!("    Block Time: {:?}\n", timestamp.to_rfc2822());
1440            }
1441
1442            let outcome = MinedBlockOutcome { block_number, included, invalid };
1443
1444            (outcome, header, block_hash)
1445        };
1446        let next_block_base_fee = self.fees.get_next_block_base_fee_per_gas(
1447            header.gas_used,
1448            header.gas_limit,
1449            header.base_fee_per_gas.unwrap_or_default(),
1450        );
1451        let next_block_excess_blob_gas = self.fees.get_next_block_blob_excess_gas(
1452            header.excess_blob_gas.unwrap_or_default(),
1453            header.blob_gas_used.unwrap_or_default(),
1454        );
1455
1456        // update next base fee
1457        self.fees.set_base_fee(next_block_base_fee);
1458
1459        self.fees.set_blob_excess_gas_and_price(BlobExcessGasAndPrice::new(
1460            next_block_excess_blob_gas,
1461            get_blob_base_fee_update_fraction_by_spec_id(*self.env.read().evm_env.spec_id()),
1462        ));
1463
1464        // notify all listeners
1465        self.notify_on_new_block(header, block_hash);
1466
1467        outcome
1468    }
1469
1470    /// Executes the [TransactionRequest] without writing to the DB
1471    ///
1472    /// # Errors
1473    ///
1474    /// Returns an error if the `block_number` is greater than the current height
1475    pub async fn call(
1476        &self,
1477        request: WithOtherFields<TransactionRequest>,
1478        fee_details: FeeDetails,
1479        block_request: Option<BlockRequest>,
1480        overrides: EvmOverrides,
1481    ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {
1482        self.with_database_at(block_request, |state, mut block| {
1483            let block_number = block.number;
1484            let (exit, out, gas, state) = {
1485                let mut cache_db = CacheDB::new(state);
1486                if let Some(state_overrides) = overrides.state {
1487                    apply_state_overrides(state_overrides.into_iter().collect(), &mut cache_db)?;
1488                }
1489                if let Some(block_overrides) = overrides.block {
1490                    cache_db.apply_block_overrides(*block_overrides, &mut block);
1491                }
1492                self.call_with_state(&cache_db as &dyn DatabaseRef, request, fee_details, block)
1493            }?;
1494            trace!(target: "backend", "call return {:?} out: {:?} gas {} on block {}", exit, out, gas, block_number);
1495            Ok((exit, out, gas, state))
1496        }).await?
1497    }
1498
1499    /// ## EVM settings
1500    ///
1501    /// This modifies certain EVM settings to mirror geth's `SkipAccountChecks` when transacting requests, see also: <https://github.com/ethereum/go-ethereum/blob/380688c636a654becc8f114438c2a5d93d2db032/core/state_transition.go#L145-L148>:
1502    ///
1503    ///  - `disable_eip3607` is set to `true`
1504    ///  - `disable_base_fee` is set to `true`
1505    ///  - `nonce` check is skipped if `request.nonce` is None
1506    fn build_call_env(
1507        &self,
1508        request: WithOtherFields<TransactionRequest>,
1509        fee_details: FeeDetails,
1510        block_env: BlockEnv,
1511    ) -> Env {
1512        let tx_type = request.minimal_tx_type() as u8;
1513
1514        let WithOtherFields::<TransactionRequest> {
1515            inner:
1516                TransactionRequest {
1517                    from,
1518                    to,
1519                    gas,
1520                    value,
1521                    input,
1522                    access_list,
1523                    blob_versioned_hashes,
1524                    authorization_list,
1525                    nonce,
1526                    sidecar: _,
1527                    chain_id,
1528                    transaction_type,
1529                    .. // Rest of the gas fees related fields are taken from `fee_details`
1530                },
1531            other,
1532        } = request;
1533
1534        let FeeDetails {
1535            gas_price,
1536            max_fee_per_gas,
1537            max_priority_fee_per_gas,
1538            max_fee_per_blob_gas,
1539        } = fee_details;
1540
1541        let gas_limit = gas.unwrap_or(block_env.gas_limit);
1542        let mut env = self.env.read().clone();
1543        env.evm_env.block_env = block_env;
1544        // we want to disable this in eth_call, since this is common practice used by other node
1545        // impls and providers <https://github.com/foundry-rs/foundry/issues/4388>
1546        env.evm_env.cfg_env.disable_block_gas_limit = true;
1547
1548        // The basefee should be ignored for calls against state for
1549        // - eth_call
1550        // - eth_estimateGas
1551        // - eth_createAccessList
1552        // - tracing
1553        env.evm_env.cfg_env.disable_base_fee = true;
1554
1555        let gas_price = gas_price.or(max_fee_per_gas).unwrap_or_else(|| {
1556            self.fees().raw_gas_price().saturating_add(MIN_SUGGESTED_PRIORITY_FEE)
1557        });
1558        let caller = from.unwrap_or_default();
1559        let to = to.as_ref().and_then(TxKind::to);
1560        let blob_hashes = blob_versioned_hashes.unwrap_or_default();
1561        let mut base = TxEnv {
1562            caller,
1563            gas_limit,
1564            gas_price,
1565            gas_priority_fee: max_priority_fee_per_gas,
1566            max_fee_per_blob_gas: max_fee_per_blob_gas
1567                .or_else(|| {
1568                    if !blob_hashes.is_empty() {
1569                        env.evm_env.block_env.blob_gasprice()
1570                    } else {
1571                        Some(0)
1572                    }
1573                })
1574                .unwrap_or_default(),
1575            kind: match to {
1576                Some(addr) => TxKind::Call(*addr),
1577                None => TxKind::Create,
1578            },
1579            tx_type,
1580            value: value.unwrap_or_default(),
1581            data: input.into_input().unwrap_or_default(),
1582            chain_id: Some(chain_id.unwrap_or(self.env.read().evm_env.cfg_env.chain_id)),
1583            access_list: access_list.unwrap_or_default(),
1584            blob_hashes,
1585            ..Default::default()
1586        };
1587        base.set_signed_authorization(authorization_list.unwrap_or_default());
1588        env.tx = OpTransaction { base, ..Default::default() };
1589
1590        if let Some(nonce) = nonce {
1591            env.tx.base.nonce = nonce;
1592        } else {
1593            // Disable nonce check in revm
1594            env.evm_env.cfg_env.disable_nonce_check = true;
1595        }
1596
1597        if env.evm_env.block_env.basefee == 0 {
1598            // this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`
1599            // 0 is only possible if it's manually set
1600            env.evm_env.cfg_env.disable_base_fee = true;
1601        }
1602
1603        // Deposit transaction?
1604        if transaction_type == Some(DEPOSIT_TX_TYPE_ID) && has_optimism_fields(&other) {
1605            let deposit = DepositTransactionParts {
1606                source_hash: other
1607                    .get_deserialized::<B256>("sourceHash")
1608                    .map(|sh| sh.unwrap_or_default())
1609                    .unwrap_or_default(),
1610                mint: other
1611                    .get_deserialized::<u128>("mint")
1612                    .map(|m| m.unwrap_or_default())
1613                    .or(None),
1614                is_system_transaction: other
1615                    .get_deserialized::<bool>("isSystemTx")
1616                    .map(|st| st.unwrap_or_default())
1617                    .unwrap_or_default(),
1618            };
1619            env.tx.deposit = deposit;
1620        }
1621
1622        env
1623    }
1624
1625    /// Builds [`Inspector`] with the configured options.
1626    fn build_inspector(&self) -> AnvilInspector {
1627        let mut inspector = AnvilInspector::default();
1628
1629        if self.print_logs {
1630            inspector = inspector.with_log_collector();
1631        }
1632        if self.print_traces {
1633            inspector = inspector.with_trace_printer();
1634        }
1635
1636        inspector
1637    }
1638
1639    /// Simulates the payload by executing the calls in request.
1640    pub async fn simulate(
1641        &self,
1642        request: SimulatePayload,
1643        block_request: Option<BlockRequest>,
1644    ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>, BlockchainError> {
1645        self.with_database_at(block_request, |state, mut block_env| {
1646            let SimulatePayload {
1647                block_state_calls,
1648                trace_transfers,
1649                validation,
1650                return_full_transactions,
1651            } = request;
1652            let mut cache_db = CacheDB::new(state);
1653            let mut block_res = Vec::with_capacity(block_state_calls.len());
1654
1655            // execute the blocks
1656            for block in block_state_calls {
1657                let SimBlock { block_overrides, state_overrides, calls } = block;
1658                let mut call_res = Vec::with_capacity(calls.len());
1659                let mut log_index = 0;
1660                let mut gas_used = 0;
1661                let mut transactions = Vec::with_capacity(calls.len());
1662                let mut logs= Vec::new();
1663
1664                // apply state overrides before executing the transactions
1665                if let Some(state_overrides) = state_overrides {
1666                    apply_state_overrides(state_overrides, &mut cache_db)?;
1667                }
1668                if let Some(block_overrides) = block_overrides {
1669                    cache_db.apply_block_overrides(block_overrides, &mut block_env);
1670                }
1671
1672                // execute all calls in that block
1673                for (req_idx, request) in calls.into_iter().enumerate() {
1674                    let fee_details = FeeDetails::new(
1675                        request.gas_price,
1676                        request.max_fee_per_gas,
1677                        request.max_priority_fee_per_gas,
1678                        request.max_fee_per_blob_gas,
1679                    )?
1680                    .or_zero_fees();
1681
1682                    let mut env = self.build_call_env(
1683                        WithOtherFields::new(request.clone()),
1684                        fee_details,
1685                        block_env.clone(),
1686                    );
1687
1688                    // Always disable EIP-3607
1689                    env.evm_env.cfg_env.disable_eip3607 = true;
1690
1691                    if !validation {
1692                        env.evm_env.cfg_env.disable_base_fee = !validation;
1693                        env.evm_env.block_env.basefee = 0;
1694                    }
1695
1696                    // transact
1697                    let ResultAndState { result, state } = if trace_transfers {
1698                        // prepare inspector to capture transfer inside the evm so they are
1699                        // recorded and included in logs
1700                        let mut inspector = TransferInspector::new(false).with_logs(true);
1701                        let mut evm= self.new_evm_with_inspector_ref(
1702                            &cache_db as &dyn DatabaseRef,
1703                            &env,
1704                            &mut inspector,
1705                        );
1706
1707                        trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env");
1708                        evm.transact(env.tx)?
1709                    } else {
1710                        let mut inspector = self.build_inspector();
1711                        let mut evm = self.new_evm_with_inspector_ref(
1712                            &cache_db as &dyn DatabaseRef,
1713                            &env,
1714                            &mut inspector,
1715                        );
1716                        trace!(target: "backend", env=?env.evm_env, spec=?env.evm_env.spec_id(),"simulate evm env");
1717                        evm.transact(env.tx)?
1718                    };
1719                    trace!(target: "backend", ?result, ?request, "simulate call");
1720
1721                    // commit the transaction
1722                    cache_db.commit(state);
1723                    gas_used += result.gas_used();
1724
1725                    // create the transaction from a request
1726                    let from = request.from.unwrap_or_default();
1727                    let request = transaction_request_to_typed(WithOtherFields::new(request))
1728                        .ok_or(BlockchainError::MissingRequiredFields)?;
1729                    let tx = build_typed_transaction(
1730                        request,
1731                        Signature::new(Default::default(), Default::default(), false),
1732                    )?;
1733                    let tx_hash = tx.hash();
1734                    let rpc_tx = transaction_build(
1735                        None,
1736                        MaybeImpersonatedTransaction::impersonated(tx, from),
1737                        None,
1738                        None,
1739                        Some(block_env.basefee),
1740                    );
1741                    transactions.push(rpc_tx);
1742
1743                    let return_data = result.output().cloned().unwrap_or_default();
1744                    let sim_res = SimCallResult {
1745                        return_data,
1746                        gas_used: result.gas_used(),
1747                        status: result.is_success(),
1748                        error: result.is_success().not().then(|| {
1749                            alloy_rpc_types::simulate::SimulateError {
1750                                code: -3200,
1751                                message: "execution failed".to_string(),
1752                            }
1753                        }),
1754                        logs: result.clone()
1755                            .into_logs()
1756                            .into_iter()
1757                            .enumerate()
1758                            .map(|(idx, log)| Log {
1759                                inner: log,
1760                                block_number: Some(block_env.number.saturating_to()),
1761                                block_timestamp: Some(block_env.timestamp.saturating_to()),
1762                                transaction_index: Some(req_idx as u64),
1763                                log_index: Some((idx + log_index) as u64),
1764                                removed: false,
1765
1766                                block_hash: None,
1767                                transaction_hash: Some(tx_hash),
1768                            })
1769                            .collect(),
1770                    };
1771                    logs.extend(sim_res.logs.clone().iter().map(|log| log.inner.clone()));
1772                    log_index += sim_res.logs.len();
1773                    call_res.push(sim_res);
1774                }
1775
1776                let transactions_envelopes: Vec<AnyTxEnvelope> = transactions
1777                .iter()
1778                .map(|tx| AnyTxEnvelope::from(tx.clone()))
1779                .collect();
1780                let header = Header {
1781                    logs_bloom: logs_bloom(logs.iter()),
1782                    transactions_root: calculate_transaction_root(&transactions_envelopes),
1783                    receipts_root: calculate_receipt_root(&transactions_envelopes),
1784                    parent_hash: Default::default(),
1785                    beneficiary: block_env.beneficiary,
1786                    state_root: Default::default(),
1787                    difficulty: Default::default(),
1788                    number: block_env.number.saturating_to(),
1789                    gas_limit: block_env.gas_limit,
1790                    gas_used,
1791                    timestamp: block_env.timestamp.saturating_to(),
1792                    extra_data: Default::default(),
1793                    mix_hash: Default::default(),
1794                    nonce: Default::default(),
1795                    base_fee_per_gas: Some(block_env.basefee),
1796                    withdrawals_root: None,
1797                    blob_gas_used: None,
1798                    excess_blob_gas: None,
1799                    parent_beacon_block_root: None,
1800                    requests_hash: None,
1801                    ..Default::default()
1802                };
1803                let mut block = alloy_rpc_types::Block {
1804                    header: AnyRpcHeader {
1805                        hash: header.hash_slow(),
1806                        inner: header.into(),
1807                        total_difficulty: None,
1808                        size: None,
1809                    },
1810                    uncles: vec![],
1811                    transactions: BlockTransactions::Full(transactions),
1812                    withdrawals: None,
1813                };
1814
1815                if !return_full_transactions {
1816                    block.transactions.convert_to_hashes();
1817                }
1818
1819                for res in &mut call_res {
1820                    res.logs.iter_mut().for_each(|log| {
1821                        log.block_hash = Some(block.header.hash);
1822                    });
1823                }
1824
1825                let simulated_block = SimulatedBlock {
1826                    inner: AnyRpcBlock::new(WithOtherFields::new(block)),
1827                    calls: call_res,
1828                };
1829
1830                // update block env
1831                block_env.number += U256::from(1);
1832                block_env.timestamp += U256::from(12);
1833                block_env.basefee = simulated_block
1834                    .inner
1835                    .header
1836                    .next_block_base_fee(BaseFeeParams::ethereum())
1837                    .unwrap_or_default();
1838
1839                block_res.push(simulated_block);
1840            }
1841
1842            Ok(block_res)
1843        })
1844        .await?
1845    }
1846
1847    pub fn call_with_state(
1848        &self,
1849        state: &dyn DatabaseRef,
1850        request: WithOtherFields<TransactionRequest>,
1851        fee_details: FeeDetails,
1852        block_env: BlockEnv,
1853    ) -> Result<(InstructionResult, Option<Output>, u128, State), BlockchainError> {
1854        let mut inspector = self.build_inspector();
1855
1856        let env = self.build_call_env(request, fee_details, block_env);
1857        let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector);
1858        let ResultAndState { result, state } = evm.transact(env.tx)?;
1859        let (exit_reason, gas_used, out) = match result {
1860            ExecutionResult::Success { reason, gas_used, output, .. } => {
1861                (reason.into(), gas_used, Some(output))
1862            }
1863            ExecutionResult::Revert { gas_used, output } => {
1864                (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
1865            }
1866            ExecutionResult::Halt { reason, gas_used } => {
1867                (op_haltreason_to_instruction_result(reason), gas_used, None)
1868            }
1869        };
1870        drop(evm);
1871        inspector.print_logs();
1872
1873        if self.print_traces {
1874            inspector.into_print_traces(self.call_trace_decoder.clone());
1875        }
1876
1877        Ok((exit_reason, out, gas_used as u128, state))
1878    }
1879
1880    pub async fn call_with_tracing(
1881        &self,
1882        request: WithOtherFields<TransactionRequest>,
1883        fee_details: FeeDetails,
1884        block_request: Option<BlockRequest>,
1885        opts: GethDebugTracingCallOptions,
1886    ) -> Result<GethTrace, BlockchainError> {
1887        let GethDebugTracingCallOptions { tracing_options, block_overrides, state_overrides } =
1888            opts;
1889        let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
1890
1891        self.with_database_at(block_request, |state, mut block| {
1892            let block_number = block.number;
1893
1894            let mut cache_db = CacheDB::new(state);
1895            if let Some(state_overrides) = state_overrides {
1896                apply_state_overrides(state_overrides, &mut cache_db)?;
1897            }
1898            if let Some(block_overrides) = block_overrides {
1899                cache_db.apply_block_overrides(block_overrides, &mut block);
1900            }
1901
1902            if let Some(tracer) = tracer {
1903                return match tracer {
1904                    GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
1905                        GethDebugBuiltInTracerType::CallTracer => {
1906                            let call_config = tracer_config
1907                                .into_call_config()
1908                                .map_err(|e| RpcError::invalid_params(e.to_string()))?;
1909
1910                            let mut inspector = self.build_inspector().with_tracing_config(
1911                                TracingInspectorConfig::from_geth_call_config(&call_config),
1912                            );
1913
1914                            let env = self.build_call_env(request, fee_details, block);
1915                            let mut evm = self.new_evm_with_inspector_ref(
1916                                &cache_db as &dyn DatabaseRef,
1917                                &env,
1918                                &mut inspector,
1919                            );
1920                            let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
1921
1922                            drop(evm);
1923                            let tracing_inspector = inspector.tracer.expect("tracer disappeared");
1924
1925                            Ok(tracing_inspector
1926                                .into_geth_builder()
1927                                .geth_call_traces(call_config, result.gas_used())
1928                                .into())
1929                        }
1930                        GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
1931                        GethDebugBuiltInTracerType::FourByteTracer
1932                        | GethDebugBuiltInTracerType::PreStateTracer
1933                        | GethDebugBuiltInTracerType::MuxTracer
1934                        | GethDebugBuiltInTracerType::FlatCallTracer => {
1935                            Err(RpcError::invalid_params("unsupported tracer type").into())
1936                        }
1937                    },
1938
1939                    GethDebugTracerType::JsTracer(_code) => {
1940                        Err(RpcError::invalid_params("unsupported tracer type").into())
1941                    }
1942                };
1943            }
1944
1945            // defaults to StructLog tracer used since no tracer is specified
1946            let mut inspector = self
1947                .build_inspector()
1948                .with_tracing_config(TracingInspectorConfig::from_geth_config(&config));
1949
1950            let env = self.build_call_env(request, fee_details, block);
1951            let mut evm = self.new_evm_with_inspector_ref(
1952                &cache_db as &dyn DatabaseRef,
1953                &env,
1954                &mut inspector,
1955            );
1956            let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
1957
1958            let (exit_reason, gas_used, out) = match result {
1959                ExecutionResult::Success { reason, gas_used, output, .. } => {
1960                    (reason.into(), gas_used, Some(output))
1961                }
1962                ExecutionResult::Revert { gas_used, output } => {
1963                    (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
1964                }
1965                ExecutionResult::Halt { reason, gas_used } => {
1966                    (op_haltreason_to_instruction_result(reason), gas_used, None)
1967                }
1968            };
1969
1970            drop(evm);
1971            let tracing_inspector = inspector.tracer.expect("tracer disappeared");
1972            let return_value = out.as_ref().map(|o| o.data().clone()).unwrap_or_default();
1973
1974            trace!(target: "backend", ?exit_reason, ?out, %gas_used, %block_number, "trace call");
1975
1976            let res = tracing_inspector
1977                .into_geth_builder()
1978                .geth_traces(gas_used, return_value, config)
1979                .into();
1980
1981            Ok(res)
1982        })
1983        .await?
1984    }
1985
1986    pub fn build_access_list_with_state(
1987        &self,
1988        state: &dyn DatabaseRef,
1989        request: WithOtherFields<TransactionRequest>,
1990        fee_details: FeeDetails,
1991        block_env: BlockEnv,
1992    ) -> Result<(InstructionResult, Option<Output>, u64, AccessList), BlockchainError> {
1993        let mut inspector =
1994            AccessListInspector::new(request.access_list.clone().unwrap_or_default());
1995
1996        let env = self.build_call_env(request, fee_details, block_env);
1997        let mut evm = self.new_evm_with_inspector_ref(state, &env, &mut inspector);
1998        let ResultAndState { result, state: _ } = evm.transact(env.tx)?;
1999        let (exit_reason, gas_used, out) = match result {
2000            ExecutionResult::Success { reason, gas_used, output, .. } => {
2001                (reason.into(), gas_used, Some(output))
2002            }
2003            ExecutionResult::Revert { gas_used, output } => {
2004                (InstructionResult::Revert, gas_used, Some(Output::Call(output)))
2005            }
2006            ExecutionResult::Halt { reason, gas_used } => {
2007                (op_haltreason_to_instruction_result(reason), gas_used, None)
2008            }
2009        };
2010        drop(evm);
2011        let access_list = inspector.access_list();
2012        Ok((exit_reason, out, gas_used, access_list))
2013    }
2014
2015    /// returns all receipts for the given transactions
2016    fn get_receipts(&self, tx_hashes: impl IntoIterator<Item = TxHash>) -> Vec<TypedReceipt> {
2017        let storage = self.blockchain.storage.read();
2018        let mut receipts = vec![];
2019
2020        for hash in tx_hashes {
2021            if let Some(tx) = storage.transactions.get(&hash) {
2022                receipts.push(tx.receipt.clone());
2023            }
2024        }
2025
2026        receipts
2027    }
2028
2029    /// Returns the logs of the block that match the filter
2030    async fn logs_for_block(
2031        &self,
2032        filter: Filter,
2033        hash: B256,
2034    ) -> Result<Vec<Log>, BlockchainError> {
2035        if let Some(block) = self.blockchain.get_block_by_hash(&hash) {
2036            return Ok(self.mined_logs_for_block(filter, block));
2037        }
2038
2039        if let Some(fork) = self.get_fork() {
2040            return Ok(fork.logs(&filter).await?);
2041        }
2042
2043        Ok(Vec::new())
2044    }
2045
2046    /// Returns all `Log`s mined by the node that were emitted in the `block` and match the `Filter`
2047    fn mined_logs_for_block(&self, filter: Filter, block: Block) -> Vec<Log> {
2048        let mut all_logs = Vec::new();
2049        let block_hash = block.header.hash_slow();
2050        let mut block_log_index = 0u32;
2051
2052        let storage = self.blockchain.storage.read();
2053
2054        for tx in block.transactions {
2055            let Some(tx) = storage.transactions.get(&tx.hash()) else {
2056                continue;
2057            };
2058
2059            let logs = tx.receipt.logs();
2060            let transaction_hash = tx.info.transaction_hash;
2061
2062            for log in logs {
2063                if filter.matches(log) {
2064                    all_logs.push(Log {
2065                        inner: log.clone(),
2066                        block_hash: Some(block_hash),
2067                        block_number: Some(block.header.number),
2068                        block_timestamp: Some(block.header.timestamp),
2069                        transaction_hash: Some(transaction_hash),
2070                        transaction_index: Some(tx.info.transaction_index),
2071                        log_index: Some(block_log_index as u64),
2072                        removed: false,
2073                    });
2074                }
2075                block_log_index += 1;
2076            }
2077        }
2078        all_logs
2079    }
2080
2081    /// Returns the logs that match the filter in the given range of blocks
2082    async fn logs_for_range(
2083        &self,
2084        filter: &Filter,
2085        mut from: u64,
2086        to: u64,
2087    ) -> Result<Vec<Log>, BlockchainError> {
2088        let mut all_logs = Vec::new();
2089
2090        // get the range that predates the fork if any
2091        if let Some(fork) = self.get_fork() {
2092            let mut to_on_fork = to;
2093
2094            if !fork.predates_fork(to) {
2095                // adjust the ranges
2096                to_on_fork = fork.block_number();
2097            }
2098
2099            if fork.predates_fork_inclusive(from) {
2100                // this data is only available on the forked client
2101                let filter = filter.clone().from_block(from).to_block(to_on_fork);
2102                all_logs = fork.logs(&filter).await?;
2103
2104                // update the range
2105                from = fork.block_number() + 1;
2106            }
2107        }
2108
2109        for number in from..=to {
2110            if let Some(block) = self.get_block(number) {
2111                all_logs.extend(self.mined_logs_for_block(filter.clone(), block));
2112            }
2113        }
2114
2115        Ok(all_logs)
2116    }
2117
2118    /// Returns the logs according to the filter
2119    pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>, BlockchainError> {
2120        trace!(target: "backend", "get logs [{:?}]", filter);
2121        if let Some(hash) = filter.get_block_hash() {
2122            self.logs_for_block(filter, hash).await
2123        } else {
2124            let best = self.best_number();
2125            let to_block =
2126                self.convert_block_number(filter.block_option.get_to_block().copied()).min(best);
2127            let from_block =
2128                self.convert_block_number(filter.block_option.get_from_block().copied());
2129            if from_block > best {
2130                // requested log range does not exist yet
2131                return Ok(vec![]);
2132            }
2133
2134            self.logs_for_range(&filter, from_block, to_block).await
2135        }
2136    }
2137
2138    pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2139        trace!(target: "backend", "get block by hash {:?}", hash);
2140        if let tx @ Some(_) = self.mined_block_by_hash(hash) {
2141            return Ok(tx);
2142        }
2143
2144        if let Some(fork) = self.get_fork() {
2145            return Ok(fork.block_by_hash(hash).await?);
2146        }
2147
2148        Ok(None)
2149    }
2150
2151    pub async fn block_by_hash_full(
2152        &self,
2153        hash: B256,
2154    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2155        trace!(target: "backend", "get block by hash {:?}", hash);
2156        if let tx @ Some(_) = self.get_full_block(hash) {
2157            return Ok(tx);
2158        }
2159
2160        if let Some(fork) = self.get_fork() {
2161            return Ok(fork.block_by_hash_full(hash).await?);
2162        }
2163
2164        Ok(None)
2165    }
2166
2167    fn mined_block_by_hash(&self, hash: B256) -> Option<AnyRpcBlock> {
2168        let block = self.blockchain.get_block_by_hash(&hash)?;
2169        Some(self.convert_block(block))
2170    }
2171
2172    pub(crate) async fn mined_transactions_by_block_number(
2173        &self,
2174        number: BlockNumber,
2175    ) -> Option<Vec<AnyRpcTransaction>> {
2176        if let Some(block) = self.get_block(number) {
2177            return self.mined_transactions_in_block(&block);
2178        }
2179        None
2180    }
2181
2182    /// Returns all transactions given a block
2183    pub(crate) fn mined_transactions_in_block(
2184        &self,
2185        block: &Block,
2186    ) -> Option<Vec<AnyRpcTransaction>> {
2187        let mut transactions = Vec::with_capacity(block.transactions.len());
2188        let base_fee = block.header.base_fee_per_gas;
2189        let storage = self.blockchain.storage.read();
2190        for hash in block.transactions.iter().map(|tx| tx.hash()) {
2191            let info = storage.transactions.get(&hash)?.info.clone();
2192            let tx = block.transactions.get(info.transaction_index as usize)?.clone();
2193
2194            let tx = transaction_build(Some(hash), tx, Some(block), Some(info), base_fee);
2195            transactions.push(tx);
2196        }
2197        Some(transactions)
2198    }
2199
2200    pub async fn block_by_number(
2201        &self,
2202        number: BlockNumber,
2203    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2204        trace!(target: "backend", "get block by number {:?}", number);
2205        if let tx @ Some(_) = self.mined_block_by_number(number) {
2206            return Ok(tx);
2207        }
2208
2209        if let Some(fork) = self.get_fork() {
2210            let number = self.convert_block_number(Some(number));
2211            if fork.predates_fork_inclusive(number) {
2212                return Ok(fork.block_by_number(number).await?);
2213            }
2214        }
2215
2216        Ok(None)
2217    }
2218
2219    pub async fn block_by_number_full(
2220        &self,
2221        number: BlockNumber,
2222    ) -> Result<Option<AnyRpcBlock>, BlockchainError> {
2223        trace!(target: "backend", "get block by number {:?}", number);
2224        if let tx @ Some(_) = self.get_full_block(number) {
2225            return Ok(tx);
2226        }
2227
2228        if let Some(fork) = self.get_fork() {
2229            let number = self.convert_block_number(Some(number));
2230            if fork.predates_fork_inclusive(number) {
2231                return Ok(fork.block_by_number_full(number).await?);
2232            }
2233        }
2234
2235        Ok(None)
2236    }
2237
2238    pub fn get_block(&self, id: impl Into<BlockId>) -> Option<Block> {
2239        let hash = match id.into() {
2240            BlockId::Hash(hash) => hash.block_hash,
2241            BlockId::Number(number) => {
2242                let storage = self.blockchain.storage.read();
2243                let slots_in_an_epoch = self.slots_in_an_epoch;
2244                match number {
2245                    BlockNumber::Latest => storage.best_hash,
2246                    BlockNumber::Earliest => storage.genesis_hash,
2247                    BlockNumber::Pending => return None,
2248                    BlockNumber::Number(num) => *storage.hashes.get(&num)?,
2249                    BlockNumber::Safe => {
2250                        if storage.best_number > (slots_in_an_epoch) {
2251                            *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch)))?
2252                        } else {
2253                            storage.genesis_hash // treat the genesis block as safe "by definition"
2254                        }
2255                    }
2256                    BlockNumber::Finalized => {
2257                        if storage.best_number > (slots_in_an_epoch * 2) {
2258                            *storage.hashes.get(&(storage.best_number - (slots_in_an_epoch * 2)))?
2259                        } else {
2260                            storage.genesis_hash
2261                        }
2262                    }
2263                }
2264            }
2265        };
2266        self.get_block_by_hash(hash)
2267    }
2268
2269    pub fn get_block_by_hash(&self, hash: B256) -> Option<Block> {
2270        self.blockchain.get_block_by_hash(&hash)
2271    }
2272
2273    pub fn mined_block_by_number(&self, number: BlockNumber) -> Option<AnyRpcBlock> {
2274        let block = self.get_block(number)?;
2275        let mut block = self.convert_block(block);
2276        block.transactions.convert_to_hashes();
2277        Some(block)
2278    }
2279
2280    pub fn get_full_block(&self, id: impl Into<BlockId>) -> Option<AnyRpcBlock> {
2281        let block = self.get_block(id)?;
2282        let transactions = self.mined_transactions_in_block(&block)?;
2283        let mut block = self.convert_block(block);
2284        block.inner.transactions = BlockTransactions::Full(transactions);
2285
2286        Some(block)
2287    }
2288
2289    /// Takes a block as it's stored internally and returns the eth api conform block format.
2290    pub fn convert_block(&self, block: Block) -> AnyRpcBlock {
2291        let size = U256::from(alloy_rlp::encode(&block).len() as u32);
2292
2293        let Block { header, transactions, .. } = block;
2294
2295        let hash = header.hash_slow();
2296        let Header { number, withdrawals_root, .. } = header;
2297
2298        let block = AlloyBlock {
2299            header: AlloyHeader {
2300                inner: AnyHeader::from(header),
2301                hash,
2302                total_difficulty: Some(self.total_difficulty()),
2303                size: Some(size),
2304            },
2305            transactions: alloy_rpc_types::BlockTransactions::Hashes(
2306                transactions.into_iter().map(|tx| tx.hash()).collect(),
2307            ),
2308            uncles: vec![],
2309            withdrawals: withdrawals_root.map(|_| Default::default()),
2310        };
2311
2312        let mut block = WithOtherFields::new(block);
2313
2314        // If Arbitrum, apply chain specifics to converted block.
2315        if is_arbitrum(self.env.read().evm_env.cfg_env.chain_id) {
2316            // Set `l1BlockNumber` field.
2317            block.other.insert("l1BlockNumber".to_string(), number.into());
2318        }
2319
2320        AnyRpcBlock::from(block)
2321    }
2322
2323    /// Converts the `BlockNumber` into a numeric value
2324    ///
2325    /// # Errors
2326    ///
2327    /// returns an error if the requested number is larger than the current height
2328    pub async fn ensure_block_number<T: Into<BlockId>>(
2329        &self,
2330        block_id: Option<T>,
2331    ) -> Result<u64, BlockchainError> {
2332        let current = self.best_number();
2333        let requested =
2334            match block_id.map(Into::into).unwrap_or(BlockId::Number(BlockNumber::Latest)) {
2335                BlockId::Hash(hash) => {
2336                    self.block_by_hash(hash.block_hash)
2337                        .await?
2338                        .ok_or(BlockchainError::BlockNotFound)?
2339                        .header
2340                        .number
2341                }
2342                BlockId::Number(num) => match num {
2343                    BlockNumber::Latest | BlockNumber::Pending => current,
2344                    BlockNumber::Earliest => U64::ZERO.to::<u64>(),
2345                    BlockNumber::Number(num) => num,
2346                    BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),
2347                    BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),
2348                },
2349            };
2350
2351        if requested > current {
2352            Err(BlockchainError::BlockOutOfRange(current, requested))
2353        } else {
2354            Ok(requested)
2355        }
2356    }
2357
2358    pub fn convert_block_number(&self, block: Option<BlockNumber>) -> u64 {
2359        let current = self.best_number();
2360        match block.unwrap_or(BlockNumber::Latest) {
2361            BlockNumber::Latest | BlockNumber::Pending => current,
2362            BlockNumber::Earliest => 0,
2363            BlockNumber::Number(num) => num,
2364            BlockNumber::Safe => current.saturating_sub(self.slots_in_an_epoch),
2365            BlockNumber::Finalized => current.saturating_sub(self.slots_in_an_epoch * 2),
2366        }
2367    }
2368
2369    /// Helper function to execute a closure with the database at a specific block
2370    pub async fn with_database_at<F, T>(
2371        &self,
2372        block_request: Option<BlockRequest>,
2373        f: F,
2374    ) -> Result<T, BlockchainError>
2375    where
2376        F: FnOnce(Box<dyn MaybeFullDatabase + '_>, BlockEnv) -> T,
2377    {
2378        let block_number = match block_request {
2379            Some(BlockRequest::Pending(pool_transactions)) => {
2380                let result = self
2381                    .with_pending_block(pool_transactions, |state, block| {
2382                        let block = block.block;
2383                        let block = BlockEnv {
2384                            number: U256::from(block.header.number),
2385                            beneficiary: block.header.beneficiary,
2386                            timestamp: U256::from(block.header.timestamp),
2387                            difficulty: block.header.difficulty,
2388                            prevrandao: Some(block.header.mix_hash),
2389                            basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2390                            gas_limit: block.header.gas_limit,
2391                            ..Default::default()
2392                        };
2393                        f(state, block)
2394                    })
2395                    .await;
2396                return Ok(result);
2397            }
2398            Some(BlockRequest::Number(bn)) => Some(BlockNumber::Number(bn)),
2399            None => None,
2400        };
2401        let block_number = self.convert_block_number(block_number);
2402
2403        if block_number < self.env.read().evm_env.block_env.number.saturating_to() {
2404            if let Some((block_hash, block)) = self
2405                .block_by_number(BlockNumber::Number(block_number))
2406                .await?
2407                .map(|block| (block.header.hash, block))
2408                && let Some(state) = self.states.write().get(&block_hash)
2409            {
2410                let block = BlockEnv {
2411                    number: U256::from(block_number),
2412                    beneficiary: block.header.beneficiary,
2413                    timestamp: U256::from(block.header.timestamp),
2414                    difficulty: block.header.difficulty,
2415                    prevrandao: block.header.mix_hash,
2416                    basefee: block.header.base_fee_per_gas.unwrap_or_default(),
2417                    gas_limit: block.header.gas_limit,
2418                    ..Default::default()
2419                };
2420                return Ok(f(Box::new(state), block));
2421            }
2422
2423            warn!(target: "backend", "Not historic state found for block={}", block_number);
2424            return Err(BlockchainError::BlockOutOfRange(
2425                self.env.read().evm_env.block_env.number.saturating_to(),
2426                block_number,
2427            ));
2428        }
2429
2430        let db = self.db.read().await;
2431        let block = self.env.read().evm_env.block_env.clone();
2432        Ok(f(Box::new(&**db), block))
2433    }
2434
2435    pub async fn storage_at(
2436        &self,
2437        address: Address,
2438        index: U256,
2439        block_request: Option<BlockRequest>,
2440    ) -> Result<B256, BlockchainError> {
2441        self.with_database_at(block_request, |db, _| {
2442            trace!(target: "backend", "get storage for {:?} at {:?}", address, index);
2443            let val = db.storage_ref(address, index)?;
2444            Ok(val.into())
2445        })
2446        .await?
2447    }
2448
2449    /// Returns the code of the address
2450    ///
2451    /// If the code is not present and fork mode is enabled then this will try to fetch it from the
2452    /// forked client
2453    pub async fn get_code(
2454        &self,
2455        address: Address,
2456        block_request: Option<BlockRequest>,
2457    ) -> Result<Bytes, BlockchainError> {
2458        self.with_database_at(block_request, |db, _| self.get_code_with_state(&db, address)).await?
2459    }
2460
2461    pub fn get_code_with_state(
2462        &self,
2463        state: &dyn DatabaseRef<Error = DatabaseError>,
2464        address: Address,
2465    ) -> Result<Bytes, BlockchainError> {
2466        trace!(target: "backend", "get code for {:?}", address);
2467        let account = state.basic_ref(address)?.unwrap_or_default();
2468        if account.code_hash == KECCAK_EMPTY {
2469            // if the code hash is `KECCAK_EMPTY`, we check no further
2470            return Ok(Default::default());
2471        }
2472        let code = if let Some(code) = account.code {
2473            code
2474        } else {
2475            state.code_by_hash_ref(account.code_hash)?
2476        };
2477        Ok(code.bytes()[..code.len()].to_vec().into())
2478    }
2479
2480    /// Returns the balance of the address
2481    ///
2482    /// If the requested number predates the fork then this will fetch it from the endpoint
2483    pub async fn get_balance(
2484        &self,
2485        address: Address,
2486        block_request: Option<BlockRequest>,
2487    ) -> Result<U256, BlockchainError> {
2488        self.with_database_at(block_request, |db, _| self.get_balance_with_state(db, address))
2489            .await?
2490    }
2491
2492    pub async fn get_account_at_block(
2493        &self,
2494        address: Address,
2495        block_request: Option<BlockRequest>,
2496    ) -> Result<Account, BlockchainError> {
2497        self.with_database_at(block_request, |block_db, _| {
2498            let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
2499            let account = db.get(&address).cloned().unwrap_or_default();
2500            let storage_root = storage_root(&account.storage);
2501            let code_hash = account.info.code_hash;
2502            let balance = account.info.balance;
2503            let nonce = account.info.nonce;
2504            Ok(Account { balance, nonce, code_hash, storage_root })
2505        })
2506        .await?
2507    }
2508
2509    pub fn get_balance_with_state<D>(
2510        &self,
2511        state: D,
2512        address: Address,
2513    ) -> Result<U256, BlockchainError>
2514    where
2515        D: DatabaseRef<Error = DatabaseError>,
2516    {
2517        trace!(target: "backend", "get balance for {:?}", address);
2518        Ok(state.basic_ref(address)?.unwrap_or_default().balance)
2519    }
2520
2521    /// Returns the nonce of the address
2522    ///
2523    /// If the requested number predates the fork then this will fetch it from the endpoint
2524    pub async fn get_nonce(
2525        &self,
2526        address: Address,
2527        block_request: BlockRequest,
2528    ) -> Result<u64, BlockchainError> {
2529        if let BlockRequest::Pending(pool_transactions) = &block_request
2530            && let Some(value) = get_pool_transactions_nonce(pool_transactions, address)
2531        {
2532            return Ok(value);
2533        }
2534        let final_block_request = match block_request {
2535            BlockRequest::Pending(_) => BlockRequest::Number(self.best_number()),
2536            BlockRequest::Number(bn) => BlockRequest::Number(bn),
2537        };
2538
2539        self.with_database_at(Some(final_block_request), |db, _| {
2540            trace!(target: "backend", "get nonce for {:?}", address);
2541            Ok(db.basic_ref(address)?.unwrap_or_default().nonce)
2542        })
2543        .await?
2544    }
2545
2546    /// Returns the traces for the given transaction
2547    pub async fn trace_transaction(
2548        &self,
2549        hash: B256,
2550    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
2551        if let Some(traces) = self.mined_parity_trace_transaction(hash) {
2552            return Ok(traces);
2553        }
2554
2555        if let Some(fork) = self.get_fork() {
2556            return Ok(fork.trace_transaction(hash).await?);
2557        }
2558
2559        Ok(vec![])
2560    }
2561
2562    /// Returns the traces for the given transaction
2563    pub(crate) fn mined_parity_trace_transaction(
2564        &self,
2565        hash: B256,
2566    ) -> Option<Vec<LocalizedTransactionTrace>> {
2567        self.blockchain.storage.read().transactions.get(&hash).map(|tx| tx.parity_traces())
2568    }
2569
2570    /// Returns the traces for the given transaction
2571    pub(crate) fn mined_transaction(&self, hash: B256) -> Option<MinedTransaction> {
2572        self.blockchain.storage.read().transactions.get(&hash).cloned()
2573    }
2574
2575    /// Returns the traces for the given block
2576    pub(crate) fn mined_parity_trace_block(
2577        &self,
2578        block: u64,
2579    ) -> Option<Vec<LocalizedTransactionTrace>> {
2580        let block = self.get_block(block)?;
2581        let mut traces = vec![];
2582        let storage = self.blockchain.storage.read();
2583        for tx in block.transactions {
2584            traces.extend(storage.transactions.get(&tx.hash())?.parity_traces());
2585        }
2586        Some(traces)
2587    }
2588
2589    /// Returns the traces for the given transaction
2590    pub async fn debug_trace_transaction(
2591        &self,
2592        hash: B256,
2593        opts: GethDebugTracingOptions,
2594    ) -> Result<GethTrace, BlockchainError> {
2595        if let Some(trace) = self.mined_geth_trace_transaction(hash, opts.clone()) {
2596            return trace;
2597        }
2598
2599        if let Some(fork) = self.get_fork() {
2600            return Ok(fork.debug_trace_transaction(hash, opts).await?);
2601        }
2602
2603        Ok(GethTrace::Default(Default::default()))
2604    }
2605
2606    /// Returns code by its hash
2607    pub async fn debug_code_by_hash(
2608        &self,
2609        code_hash: B256,
2610        block_id: Option<BlockId>,
2611    ) -> Result<Option<Bytes>, BlockchainError> {
2612        if let Ok(code) = self.db.read().await.code_by_hash_ref(code_hash) {
2613            return Ok(Some(code.original_bytes()));
2614        }
2615        if let Some(fork) = self.get_fork() {
2616            return Ok(fork.debug_code_by_hash(code_hash, block_id).await?);
2617        }
2618
2619        Ok(None)
2620    }
2621
2622    fn mined_geth_trace_transaction(
2623        &self,
2624        hash: B256,
2625        opts: GethDebugTracingOptions,
2626    ) -> Option<Result<GethTrace, BlockchainError>> {
2627        self.blockchain.storage.read().transactions.get(&hash).map(|tx| tx.geth_trace(opts))
2628    }
2629
2630    /// Returns the traces for the given block
2631    pub async fn trace_block(
2632        &self,
2633        block: BlockNumber,
2634    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
2635        let number = self.convert_block_number(Some(block));
2636        if let Some(traces) = self.mined_parity_trace_block(number) {
2637            return Ok(traces);
2638        }
2639
2640        if let Some(fork) = self.get_fork()
2641            && fork.predates_fork(number)
2642        {
2643            return Ok(fork.trace_block(number).await?);
2644        }
2645
2646        Ok(vec![])
2647    }
2648
2649    pub async fn transaction_receipt(
2650        &self,
2651        hash: B256,
2652    ) -> Result<Option<ReceiptResponse>, BlockchainError> {
2653        if let Some(receipt) = self.mined_transaction_receipt(hash) {
2654            return Ok(Some(receipt.inner));
2655        }
2656
2657        if let Some(fork) = self.get_fork() {
2658            let receipt = fork.transaction_receipt(hash).await?;
2659            let number = self.convert_block_number(
2660                receipt.clone().and_then(|r| r.block_number).map(BlockNumber::from),
2661            );
2662
2663            if fork.predates_fork_inclusive(number) {
2664                return Ok(receipt);
2665            }
2666        }
2667
2668        Ok(None)
2669    }
2670
2671    // Returns the traces matching a given filter
2672    pub async fn trace_filter(
2673        &self,
2674        filter: TraceFilter,
2675    ) -> Result<Vec<LocalizedTransactionTrace>, BlockchainError> {
2676        let matcher = filter.matcher();
2677        let start = filter.from_block.unwrap_or(0);
2678        let end = filter.to_block.unwrap_or_else(|| self.best_number());
2679
2680        if start > end {
2681            return Err(BlockchainError::RpcError(RpcError::invalid_params(
2682                "invalid block range, ensure that to block is greater than from block".to_string(),
2683            )));
2684        }
2685
2686        let dist = end - start;
2687        if dist > 300 {
2688            return Err(BlockchainError::RpcError(RpcError::invalid_params(
2689                "block range too large, currently limited to 300".to_string(),
2690            )));
2691        }
2692
2693        // Accumulate tasks for block range
2694        let mut trace_tasks = vec![];
2695        for num in start..=end {
2696            trace_tasks.push(self.trace_block(num.into()));
2697        }
2698
2699        // Execute tasks and filter traces
2700        let traces = futures::future::try_join_all(trace_tasks).await?;
2701        let filtered_traces =
2702            traces.into_iter().flatten().filter(|trace| matcher.matches(&trace.trace));
2703
2704        // Apply after and count
2705        let filtered_traces: Vec<_> = if let Some(after) = filter.after {
2706            filtered_traces.skip(after as usize).collect()
2707        } else {
2708            filtered_traces.collect()
2709        };
2710
2711        let filtered_traces: Vec<_> = if let Some(count) = filter.count {
2712            filtered_traces.into_iter().take(count as usize).collect()
2713        } else {
2714            filtered_traces
2715        };
2716
2717        Ok(filtered_traces)
2718    }
2719
2720    /// Returns all receipts of the block
2721    pub fn mined_receipts(&self, hash: B256) -> Option<Vec<TypedReceipt>> {
2722        let block = self.mined_block_by_hash(hash)?;
2723        let mut receipts = Vec::new();
2724        let storage = self.blockchain.storage.read();
2725        for tx in block.transactions.hashes() {
2726            let receipt = storage.transactions.get(&tx)?.receipt.clone();
2727            receipts.push(receipt);
2728        }
2729        Some(receipts)
2730    }
2731
2732    /// Returns all transaction receipts of the block
2733    pub fn mined_block_receipts(&self, id: impl Into<BlockId>) -> Option<Vec<ReceiptResponse>> {
2734        let mut receipts = Vec::new();
2735        let block = self.get_block(id)?;
2736
2737        for transaction in block.transactions {
2738            let receipt = self.mined_transaction_receipt(transaction.hash())?;
2739            receipts.push(receipt.inner);
2740        }
2741
2742        Some(receipts)
2743    }
2744
2745    /// Returns the transaction receipt for the given hash
2746    pub(crate) fn mined_transaction_receipt(&self, hash: B256) -> Option<MinedTransactionReceipt> {
2747        let MinedTransaction { info, receipt: tx_receipt, block_hash, .. } =
2748            self.blockchain.get_transaction_by_hash(&hash)?;
2749
2750        let index = info.transaction_index as usize;
2751        let block = self.blockchain.get_block_by_hash(&block_hash)?;
2752        let transaction = block.transactions[index].clone();
2753
2754        // Cancun specific
2755        let excess_blob_gas = block.header.excess_blob_gas;
2756        let blob_gas_price =
2757            alloy_eips::eip4844::calc_blob_gasprice(excess_blob_gas.unwrap_or_default());
2758        let blob_gas_used = transaction.blob_gas();
2759
2760        let effective_gas_price = match transaction.transaction {
2761            TypedTransaction::Legacy(t) => t.tx().gas_price,
2762            TypedTransaction::EIP2930(t) => t.tx().gas_price,
2763            TypedTransaction::EIP1559(t) => block
2764                .header
2765                .base_fee_per_gas
2766                .map_or(self.base_fee() as u128, |g| g as u128)
2767                .saturating_add(t.tx().max_priority_fee_per_gas),
2768            TypedTransaction::EIP4844(t) => block
2769                .header
2770                .base_fee_per_gas
2771                .map_or(self.base_fee() as u128, |g| g as u128)
2772                .saturating_add(t.tx().tx().max_priority_fee_per_gas),
2773            TypedTransaction::EIP7702(t) => block
2774                .header
2775                .base_fee_per_gas
2776                .map_or(self.base_fee() as u128, |g| g as u128)
2777                .saturating_add(t.tx().max_priority_fee_per_gas),
2778            TypedTransaction::Deposit(_) => 0_u128,
2779        };
2780
2781        let receipts = self.get_receipts(block.transactions.iter().map(|tx| tx.hash()));
2782        let next_log_index = receipts[..index].iter().map(|r| r.logs().len()).sum::<usize>();
2783
2784        let receipt = tx_receipt.as_receipt_with_bloom().receipt.clone();
2785        let receipt = Receipt {
2786            status: receipt.status,
2787            cumulative_gas_used: receipt.cumulative_gas_used,
2788            logs: receipt
2789                .logs
2790                .into_iter()
2791                .enumerate()
2792                .map(|(index, log)| alloy_rpc_types::Log {
2793                    inner: log,
2794                    block_hash: Some(block_hash),
2795                    block_number: Some(block.header.number),
2796                    block_timestamp: Some(block.header.timestamp),
2797                    transaction_hash: Some(info.transaction_hash),
2798                    transaction_index: Some(info.transaction_index),
2799                    log_index: Some((next_log_index + index) as u64),
2800                    removed: false,
2801                })
2802                .collect(),
2803        };
2804        let receipt_with_bloom =
2805            ReceiptWithBloom { receipt, logs_bloom: tx_receipt.as_receipt_with_bloom().logs_bloom };
2806
2807        let inner = match tx_receipt {
2808            TypedReceipt::EIP1559(_) => TypedReceipt::EIP1559(receipt_with_bloom),
2809            TypedReceipt::Legacy(_) => TypedReceipt::Legacy(receipt_with_bloom),
2810            TypedReceipt::EIP2930(_) => TypedReceipt::EIP2930(receipt_with_bloom),
2811            TypedReceipt::EIP4844(_) => TypedReceipt::EIP4844(receipt_with_bloom),
2812            TypedReceipt::EIP7702(_) => TypedReceipt::EIP7702(receipt_with_bloom),
2813            TypedReceipt::Deposit(r) => TypedReceipt::Deposit(DepositReceipt {
2814                inner: receipt_with_bloom,
2815                deposit_nonce: r.deposit_nonce,
2816                deposit_receipt_version: r.deposit_receipt_version,
2817            }),
2818        };
2819
2820        let inner = TransactionReceipt {
2821            inner,
2822            transaction_hash: info.transaction_hash,
2823            transaction_index: Some(info.transaction_index),
2824            block_number: Some(block.header.number),
2825            gas_used: info.gas_used,
2826            contract_address: info.contract_address,
2827            effective_gas_price,
2828            block_hash: Some(block_hash),
2829            from: info.from,
2830            to: info.to,
2831            blob_gas_price: Some(blob_gas_price),
2832            blob_gas_used,
2833        };
2834
2835        Some(MinedTransactionReceipt { inner, out: info.out.map(|o| o.0.into()) })
2836    }
2837
2838    /// Returns the blocks receipts for the given number
2839    pub async fn block_receipts(
2840        &self,
2841        number: BlockId,
2842    ) -> Result<Option<Vec<ReceiptResponse>>, BlockchainError> {
2843        if let Some(receipts) = self.mined_block_receipts(number) {
2844            return Ok(Some(receipts));
2845        }
2846
2847        if let Some(fork) = self.get_fork() {
2848            let number = match self.ensure_block_number(Some(number)).await {
2849                Err(_) => return Ok(None),
2850                Ok(n) => n,
2851            };
2852
2853            if fork.predates_fork_inclusive(number) {
2854                let receipts = fork.block_receipts(number).await?;
2855
2856                return Ok(receipts);
2857            }
2858        }
2859
2860        Ok(None)
2861    }
2862
2863    pub async fn transaction_by_block_number_and_index(
2864        &self,
2865        number: BlockNumber,
2866        index: Index,
2867    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
2868        if let Some(block) = self.mined_block_by_number(number) {
2869            return Ok(self.mined_transaction_by_block_hash_and_index(block.header.hash, index));
2870        }
2871
2872        if let Some(fork) = self.get_fork() {
2873            let number = self.convert_block_number(Some(number));
2874            if fork.predates_fork(number) {
2875                return Ok(fork
2876                    .transaction_by_block_number_and_index(number, index.into())
2877                    .await?);
2878            }
2879        }
2880
2881        Ok(None)
2882    }
2883
2884    pub async fn transaction_by_block_hash_and_index(
2885        &self,
2886        hash: B256,
2887        index: Index,
2888    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
2889        if let tx @ Some(_) = self.mined_transaction_by_block_hash_and_index(hash, index) {
2890            return Ok(tx);
2891        }
2892
2893        if let Some(fork) = self.get_fork() {
2894            return Ok(fork.transaction_by_block_hash_and_index(hash, index.into()).await?);
2895        }
2896
2897        Ok(None)
2898    }
2899
2900    pub fn mined_transaction_by_block_hash_and_index(
2901        &self,
2902        block_hash: B256,
2903        index: Index,
2904    ) -> Option<AnyRpcTransaction> {
2905        let (info, block, tx) = {
2906            let storage = self.blockchain.storage.read();
2907            let block = storage.blocks.get(&block_hash).cloned()?;
2908            let index: usize = index.into();
2909            let tx = block.transactions.get(index)?.clone();
2910            let info = storage.transactions.get(&tx.hash())?.info.clone();
2911            (info, block, tx)
2912        };
2913
2914        Some(transaction_build(
2915            Some(info.transaction_hash),
2916            tx,
2917            Some(&block),
2918            Some(info),
2919            block.header.base_fee_per_gas,
2920        ))
2921    }
2922
2923    pub async fn transaction_by_hash(
2924        &self,
2925        hash: B256,
2926    ) -> Result<Option<AnyRpcTransaction>, BlockchainError> {
2927        trace!(target: "backend", "transaction_by_hash={:?}", hash);
2928        if let tx @ Some(_) = self.mined_transaction_by_hash(hash) {
2929            return Ok(tx);
2930        }
2931
2932        if let Some(fork) = self.get_fork() {
2933            return fork
2934                .transaction_by_hash(hash)
2935                .await
2936                .map_err(BlockchainError::AlloyForkProvider);
2937        }
2938
2939        Ok(None)
2940    }
2941
2942    pub fn mined_transaction_by_hash(&self, hash: B256) -> Option<AnyRpcTransaction> {
2943        let (info, block) = {
2944            let storage = self.blockchain.storage.read();
2945            let MinedTransaction { info, block_hash, .. } =
2946                storage.transactions.get(&hash)?.clone();
2947            let block = storage.blocks.get(&block_hash).cloned()?;
2948            (info, block)
2949        };
2950        let tx = block.transactions.get(info.transaction_index as usize)?.clone();
2951
2952        Some(transaction_build(
2953            Some(info.transaction_hash),
2954            tx,
2955            Some(&block),
2956            Some(info),
2957            block.header.base_fee_per_gas,
2958        ))
2959    }
2960
2961    pub fn get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<alloy_consensus::Blob>>> {
2962        // Try to get the mined transaction by hash
2963        if let Some(tx) = self.mined_transaction_by_hash(hash)
2964            && let Ok(typed_tx) = TypedTransaction::try_from(tx)
2965            && let Some(sidecar) = typed_tx.sidecar()
2966        {
2967            return Ok(Some(sidecar.sidecar.blobs.clone()));
2968        }
2969
2970        Ok(None)
2971    }
2972
2973    pub fn get_blob_by_versioned_hash(&self, hash: B256) -> Result<Option<Blob>> {
2974        let storage = self.blockchain.storage.read();
2975        for block in storage.blocks.values() {
2976            for tx in &block.transactions {
2977                let typed_tx = tx.as_ref();
2978                if let Some(sidecar) = typed_tx.sidecar() {
2979                    for versioned_hash in sidecar.sidecar.versioned_hashes() {
2980                        if versioned_hash == hash
2981                            && let Some(index) =
2982                                sidecar.sidecar.commitments.iter().position(|commitment| {
2983                                    kzg_to_versioned_hash(commitment.as_slice()) == *hash
2984                                })
2985                            && let Some(blob) = sidecar.sidecar.blobs.get(index)
2986                        {
2987                            return Ok(Some(*blob));
2988                        }
2989                    }
2990                }
2991            }
2992        }
2993        Ok(None)
2994    }
2995
2996    /// Prove an account's existence or nonexistence in the state trie.
2997    ///
2998    /// Returns a merkle proof of the account's trie node, `account_key` == keccak(address)
2999    pub async fn prove_account_at(
3000        &self,
3001        address: Address,
3002        keys: Vec<B256>,
3003        block_request: Option<BlockRequest>,
3004    ) -> Result<AccountProof, BlockchainError> {
3005        let block_number = block_request.as_ref().map(|r| r.block_number());
3006
3007        self.with_database_at(block_request, |block_db, _| {
3008            trace!(target: "backend", "get proof for {:?} at {:?}", address, block_number);
3009            let db = block_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3010            let account = db.get(&address).cloned().unwrap_or_default();
3011
3012            let mut builder = HashBuilder::default()
3013                .with_proof_retainer(ProofRetainer::new(vec![Nibbles::unpack(keccak256(address))]));
3014
3015            for (key, account) in trie_accounts(db) {
3016                builder.add_leaf(key, &account);
3017            }
3018
3019            let _ = builder.root();
3020
3021            let proof = builder
3022                .take_proof_nodes()
3023                .into_nodes_sorted()
3024                .into_iter()
3025                .map(|(_, v)| v)
3026                .collect();
3027            let storage_proofs = prove_storage(&account.storage, &keys);
3028
3029            let account_proof = AccountProof {
3030                address,
3031                balance: account.info.balance,
3032                nonce: account.info.nonce,
3033                code_hash: account.info.code_hash,
3034                storage_hash: storage_root(&account.storage),
3035                account_proof: proof,
3036                storage_proof: keys
3037                    .into_iter()
3038                    .zip(storage_proofs)
3039                    .map(|(key, proof)| {
3040                        let storage_key: U256 = key.into();
3041                        let value = account.storage.get(&storage_key).copied().unwrap_or_default();
3042                        StorageProof { key: JsonStorageKey::Hash(key), value, proof }
3043                    })
3044                    .collect(),
3045            };
3046
3047            Ok(account_proof)
3048        })
3049        .await?
3050    }
3051
3052    /// Returns a new block event stream
3053    pub fn new_block_notifications(&self) -> NewBlockNotifications {
3054        let (tx, rx) = unbounded();
3055        self.new_block_listeners.lock().push(tx);
3056        trace!(target: "backed", "added new block listener");
3057        rx
3058    }
3059
3060    /// Notifies all `new_block_listeners` about the new block
3061    fn notify_on_new_block(&self, header: Header, hash: B256) {
3062        // cleanup closed notification streams first, if the channel is closed we can remove the
3063        // sender half for the set
3064        self.new_block_listeners.lock().retain(|tx| !tx.is_closed());
3065
3066        let notification = NewBlockNotification { hash, header: Arc::new(header) };
3067
3068        self.new_block_listeners
3069            .lock()
3070            .retain(|tx| tx.unbounded_send(notification.clone()).is_ok());
3071    }
3072
3073    /// Reorg the chain to a common height and execute blocks to build new chain.
3074    ///
3075    /// The state of the chain is rewound using `rewind` to the common block, including the db,
3076    /// storage, and env.
3077    ///
3078    /// Finally, `do_mine_block` is called to create the new chain.
3079    pub async fn reorg(
3080        &self,
3081        depth: u64,
3082        tx_pairs: HashMap<u64, Vec<Arc<PoolTransaction>>>,
3083        common_block: Block,
3084    ) -> Result<(), BlockchainError> {
3085        self.rollback(common_block).await?;
3086        // Create the new reorged chain, filling the blocks with transactions if supplied
3087        for i in 0..depth {
3088            let to_be_mined = tx_pairs.get(&i).cloned().unwrap_or_else(Vec::new);
3089            let outcome = self.do_mine_block(to_be_mined).await;
3090            node_info!(
3091                "    Mined reorg block number {}. With {} valid txs and with invalid {} txs",
3092                outcome.block_number,
3093                outcome.included.len(),
3094                outcome.invalid.len()
3095            );
3096        }
3097
3098        Ok(())
3099    }
3100
3101    /// Rollback the chain to a common height.
3102    ///
3103    /// The state of the chain is rewound using `rewind` to the common block, including the db,
3104    /// storage, and env.
3105    pub async fn rollback(&self, common_block: Block) -> Result<(), BlockchainError> {
3106        // Get the database at the common block
3107        let common_state = {
3108            let mut state = self.states.write();
3109            let state_db = state
3110                .get(&common_block.header.hash_slow())
3111                .ok_or(BlockchainError::DataUnavailable)?;
3112            let db_full = state_db.maybe_as_full_db().ok_or(BlockchainError::DataUnavailable)?;
3113            db_full.clone()
3114        };
3115
3116        {
3117            // Set state to common state
3118            self.db.write().await.clear();
3119            for (address, acc) in common_state {
3120                for (key, value) in acc.storage {
3121                    self.db.write().await.set_storage_at(address, key.into(), value.into())?;
3122                }
3123                self.db.write().await.insert_account(address, acc.info);
3124            }
3125        }
3126
3127        {
3128            // Unwind the storage back to the common ancestor
3129            self.blockchain
3130                .storage
3131                .write()
3132                .unwind_to(common_block.header.number, common_block.header.hash_slow());
3133
3134            // Set environment back to common block
3135            let mut env = self.env.write();
3136            env.evm_env.block_env.number = U256::from(common_block.header.number);
3137            env.evm_env.block_env.timestamp = U256::from(common_block.header.timestamp);
3138            env.evm_env.block_env.gas_limit = common_block.header.gas_limit;
3139            env.evm_env.block_env.difficulty = common_block.header.difficulty;
3140            env.evm_env.block_env.prevrandao = Some(common_block.header.mix_hash);
3141
3142            self.time.reset(env.evm_env.block_env.timestamp.saturating_to());
3143        }
3144        Ok(())
3145    }
3146}
3147
3148/// Get max nonce from transaction pool by address.
3149fn get_pool_transactions_nonce(
3150    pool_transactions: &[Arc<PoolTransaction>],
3151    address: Address,
3152) -> Option<u64> {
3153    if let Some(highest_nonce) = pool_transactions
3154        .iter()
3155        .filter(|tx| *tx.pending_transaction.sender() == address)
3156        .map(|tx| tx.pending_transaction.nonce())
3157        .max()
3158    {
3159        let tx_count = highest_nonce.saturating_add(1);
3160        return Some(tx_count);
3161    }
3162    None
3163}
3164
3165#[async_trait::async_trait]
3166impl TransactionValidator for Backend {
3167    async fn validate_pool_transaction(
3168        &self,
3169        tx: &PendingTransaction,
3170    ) -> Result<(), BlockchainError> {
3171        let address = *tx.sender();
3172        let account = self.get_account(address).await?;
3173        let env = self.next_env();
3174        Ok(self.validate_pool_transaction_for(tx, &account, &env)?)
3175    }
3176
3177    fn validate_pool_transaction_for(
3178        &self,
3179        pending: &PendingTransaction,
3180        account: &AccountInfo,
3181        env: &Env,
3182    ) -> Result<(), InvalidTransactionError> {
3183        let tx = &pending.transaction;
3184
3185        if let Some(tx_chain_id) = tx.chain_id() {
3186            let chain_id = self.chain_id();
3187            if chain_id.to::<u64>() != tx_chain_id {
3188                if let Some(legacy) = tx.as_legacy() {
3189                    // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md>
3190                    if env.evm_env.cfg_env.spec >= SpecId::SPURIOUS_DRAGON
3191                        && legacy.tx().chain_id.is_none()
3192                    {
3193                        warn!(target: "backend", ?chain_id, ?tx_chain_id, "incompatible EIP155-based V");
3194                        return Err(InvalidTransactionError::IncompatibleEIP155);
3195                    }
3196                } else {
3197                    warn!(target: "backend", ?chain_id, ?tx_chain_id, "invalid chain id");
3198                    return Err(InvalidTransactionError::InvalidChainId);
3199                }
3200            }
3201        }
3202
3203        if tx.gas_limit() < MIN_TRANSACTION_GAS as u64 {
3204            warn!(target: "backend", "[{:?}] gas too low", tx.hash());
3205            return Err(InvalidTransactionError::GasTooLow);
3206        }
3207
3208        // Check gas limit, iff block gas limit is set.
3209        if !env.evm_env.cfg_env.disable_block_gas_limit
3210            && tx.gas_limit() > env.evm_env.block_env.gas_limit
3211        {
3212            warn!(target: "backend", "[{:?}] gas too high", tx.hash());
3213            return Err(InvalidTransactionError::GasTooHigh(ErrDetail {
3214                detail: String::from("tx.gas_limit > env.block.gas_limit"),
3215            }));
3216        }
3217
3218        // check nonce
3219        let is_deposit_tx =
3220            matches!(&pending.transaction.transaction, TypedTransaction::Deposit(_));
3221        let nonce = tx.nonce();
3222        if nonce < account.nonce && !is_deposit_tx {
3223            warn!(target: "backend", "[{:?}] nonce too low", tx.hash());
3224            return Err(InvalidTransactionError::NonceTooLow);
3225        }
3226
3227        if env.evm_env.cfg_env.spec >= SpecId::LONDON {
3228            if tx.gas_price() < env.evm_env.block_env.basefee.into() && !is_deposit_tx {
3229                warn!(target: "backend", "max fee per gas={}, too low, block basefee={}",tx.gas_price(),  env.evm_env.block_env.basefee);
3230                return Err(InvalidTransactionError::FeeCapTooLow);
3231            }
3232
3233            if let (Some(max_priority_fee_per_gas), Some(max_fee_per_gas)) =
3234                (tx.essentials().max_priority_fee_per_gas, tx.essentials().max_fee_per_gas)
3235                && max_priority_fee_per_gas > max_fee_per_gas
3236            {
3237                warn!(target: "backend", "max priority fee per gas={}, too high, max fee per gas={}", max_priority_fee_per_gas, max_fee_per_gas);
3238                return Err(InvalidTransactionError::TipAboveFeeCap);
3239            }
3240        }
3241
3242        // EIP-4844 Cancun hard fork validation steps
3243        if env.evm_env.cfg_env.spec >= SpecId::CANCUN && tx.transaction.is_eip4844() {
3244            // Light checks first: see if the blob fee cap is too low.
3245            if let Some(max_fee_per_blob_gas) = tx.essentials().max_fee_per_blob_gas
3246                && let Some(blob_gas_and_price) = &env.evm_env.block_env.blob_excess_gas_and_price
3247                && max_fee_per_blob_gas < blob_gas_and_price.blob_gasprice
3248            {
3249                warn!(target: "backend", "max fee per blob gas={}, too low, block blob gas price={}", max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice);
3250                return Err(InvalidTransactionError::BlobFeeCapTooLow);
3251            }
3252
3253            // Heavy (blob validation) checks
3254            let tx = match &tx.transaction {
3255                TypedTransaction::EIP4844(tx) => tx.tx(),
3256                _ => unreachable!(),
3257            };
3258
3259            let blob_count = tx.tx().blob_versioned_hashes.len();
3260
3261            // Ensure there are blob hashes.
3262            if blob_count == 0 {
3263                return Err(InvalidTransactionError::NoBlobHashes);
3264            }
3265
3266            // Ensure the tx does not exceed the max blobs per block.
3267            let max_blob_count = self.blob_params().max_blob_count as usize;
3268            if blob_count > max_blob_count {
3269                return Err(InvalidTransactionError::TooManyBlobs(blob_count, max_blob_count));
3270            }
3271
3272            // Check for any blob validation errors if not impersonating.
3273            if !self.skip_blob_validation(Some(*pending.sender()))
3274                && let Err(err) = tx.validate(EnvKzgSettings::default().get())
3275            {
3276                return Err(InvalidTransactionError::BlobTransactionValidationError(err));
3277            }
3278        }
3279
3280        let max_cost = tx.max_cost();
3281        let value = tx.value();
3282
3283        match &tx.transaction {
3284            TypedTransaction::Deposit(deposit_tx) => {
3285                // Deposit transactions
3286                // https://specs.optimism.io/protocol/deposits.html#execution
3287                // 1. no gas cost check required since already have prepaid gas from L1
3288                // 2. increment account balance by deposited amount before checking for sufficient
3289                //    funds `tx.value <= existing account value + deposited value`
3290                if value > account.balance + U256::from(deposit_tx.mint) {
3291                    warn!(target: "backend", "[{:?}] insufficient balance={}, required={} account={:?}", tx.hash(), account.balance + U256::from(deposit_tx.mint), value, *pending.sender());
3292                    return Err(InvalidTransactionError::InsufficientFunds);
3293                }
3294            }
3295            _ => {
3296                // check sufficient funds: `gas * price + value`
3297                let req_funds = max_cost.checked_add(value.saturating_to()).ok_or_else(|| {
3298                    warn!(target: "backend", "[{:?}] cost too high", tx.hash());
3299                    InvalidTransactionError::InsufficientFunds
3300                })?;
3301                if account.balance < U256::from(req_funds) {
3302                    warn!(target: "backend", "[{:?}] insufficient allowance={}, required={} account={:?}", tx.hash(), account.balance, req_funds, *pending.sender());
3303                    return Err(InvalidTransactionError::InsufficientFunds);
3304                }
3305            }
3306        }
3307
3308        Ok(())
3309    }
3310
3311    fn validate_for(
3312        &self,
3313        tx: &PendingTransaction,
3314        account: &AccountInfo,
3315        env: &Env,
3316    ) -> Result<(), InvalidTransactionError> {
3317        self.validate_pool_transaction_for(tx, account, env)?;
3318        if tx.nonce() > account.nonce {
3319            return Err(InvalidTransactionError::NonceTooHigh);
3320        }
3321        Ok(())
3322    }
3323}
3324
3325/// Creates a `AnyRpcTransaction` as it's expected for the `eth` RPC api from storage data
3326pub fn transaction_build(
3327    tx_hash: Option<B256>,
3328    eth_transaction: MaybeImpersonatedTransaction,
3329    block: Option<&Block>,
3330    info: Option<TransactionInfo>,
3331    base_fee: Option<u64>,
3332) -> AnyRpcTransaction {
3333    if let TypedTransaction::Deposit(ref deposit_tx) = eth_transaction.transaction {
3334        let dep_tx = deposit_tx;
3335
3336        let ser = serde_json::to_value(dep_tx).expect("could not serialize TxDeposit");
3337        let maybe_deposit_fields = OtherFields::try_from(ser);
3338
3339        match maybe_deposit_fields {
3340            Ok(mut fields) => {
3341                // Add zeroed signature fields for backwards compatibility
3342                // https://specs.optimism.io/protocol/deposits.html#the-deposited-transaction-type
3343                fields.insert("v".to_string(), serde_json::to_value("0x0").unwrap());
3344                fields.insert("r".to_string(), serde_json::to_value(B256::ZERO).unwrap());
3345                fields.insert(String::from("s"), serde_json::to_value(B256::ZERO).unwrap());
3346                fields.insert(String::from("nonce"), serde_json::to_value("0x0").unwrap());
3347
3348                let inner = UnknownTypedTransaction {
3349                    ty: AnyTxType(DEPOSIT_TX_TYPE_ID),
3350                    fields,
3351                    memo: Default::default(),
3352                };
3353
3354                let envelope = AnyTxEnvelope::Unknown(UnknownTxEnvelope {
3355                    hash: eth_transaction.hash(),
3356                    inner,
3357                });
3358
3359                let tx = Transaction {
3360                    inner: Recovered::new_unchecked(envelope, deposit_tx.from),
3361                    block_hash: block
3362                        .as_ref()
3363                        .map(|block| B256::from(keccak256(alloy_rlp::encode(&block.header)))),
3364                    block_number: block.as_ref().map(|block| block.header.number),
3365                    transaction_index: info.as_ref().map(|info| info.transaction_index),
3366                    effective_gas_price: None,
3367                };
3368
3369                return AnyRpcTransaction::from(WithOtherFields::new(tx));
3370            }
3371            Err(_) => {
3372                error!(target: "backend", "failed to serialize deposit transaction");
3373            }
3374        }
3375    }
3376
3377    let mut transaction: Transaction = eth_transaction.clone().into();
3378
3379    let effective_gas_price = if !eth_transaction.is_dynamic_fee() {
3380        transaction.effective_gas_price(base_fee)
3381    } else if block.is_none() && info.is_none() {
3382        // transaction is not mined yet, gas price is considered just `max_fee_per_gas`
3383        transaction.max_fee_per_gas()
3384    } else {
3385        // if transaction is already mined, gas price is considered base fee + priority
3386        // fee: the effective gas price.
3387        let base_fee = base_fee.map_or(0u128, |g| g as u128);
3388        let max_priority_fee_per_gas = transaction.max_priority_fee_per_gas().unwrap_or(0);
3389
3390        base_fee.saturating_add(max_priority_fee_per_gas)
3391    };
3392
3393    transaction.effective_gas_price = Some(effective_gas_price);
3394
3395    let envelope = transaction.inner;
3396
3397    // if a specific hash was provided we update the transaction's hash
3398    // This is important for impersonated transactions since they all use the
3399    // `BYPASS_SIGNATURE` which would result in different hashes
3400    // Note: for impersonated transactions this only concerns pending transactions because
3401    // there's // no `info` yet.
3402    let hash = tx_hash.unwrap_or(*envelope.tx_hash());
3403
3404    let envelope = match envelope.into_inner() {
3405        TxEnvelope::Legacy(signed_tx) => {
3406            let (t, sig, _) = signed_tx.into_parts();
3407            let new_signed = Signed::new_unchecked(t, sig, hash);
3408            AnyTxEnvelope::Ethereum(TxEnvelope::Legacy(new_signed))
3409        }
3410        TxEnvelope::Eip1559(signed_tx) => {
3411            let (t, sig, _) = signed_tx.into_parts();
3412            let new_signed = Signed::new_unchecked(t, sig, hash);
3413            AnyTxEnvelope::Ethereum(TxEnvelope::Eip1559(new_signed))
3414        }
3415        TxEnvelope::Eip2930(signed_tx) => {
3416            let (t, sig, _) = signed_tx.into_parts();
3417            let new_signed = Signed::new_unchecked(t, sig, hash);
3418            AnyTxEnvelope::Ethereum(TxEnvelope::Eip2930(new_signed))
3419        }
3420        TxEnvelope::Eip4844(signed_tx) => {
3421            let (t, sig, _) = signed_tx.into_parts();
3422            let new_signed = Signed::new_unchecked(t, sig, hash);
3423            AnyTxEnvelope::Ethereum(TxEnvelope::Eip4844(new_signed))
3424        }
3425        TxEnvelope::Eip7702(signed_tx) => {
3426            let (t, sig, _) = signed_tx.into_parts();
3427            let new_signed = Signed::new_unchecked(t, sig, hash);
3428            AnyTxEnvelope::Ethereum(TxEnvelope::Eip7702(new_signed))
3429        }
3430    };
3431
3432    let tx = Transaction {
3433        inner: Recovered::new_unchecked(
3434            envelope,
3435            eth_transaction.recover().expect("can recover signed tx"),
3436        ),
3437        block_hash: block
3438            .as_ref()
3439            .map(|block| B256::from(keccak256(alloy_rlp::encode(&block.header)))),
3440        block_number: block.as_ref().map(|block| block.header.number),
3441        transaction_index: info.as_ref().map(|info| info.transaction_index),
3442        // deprecated
3443        effective_gas_price: Some(effective_gas_price),
3444    };
3445    AnyRpcTransaction::from(WithOtherFields::new(tx))
3446}
3447
3448/// Prove a storage key's existence or nonexistence in the account's storage trie.
3449///
3450/// `storage_key` is the hash of the desired storage key, meaning
3451/// this will only work correctly under a secure trie.
3452/// `storage_key` == keccak(key)
3453pub fn prove_storage(storage: &HashMap<U256, U256>, keys: &[B256]) -> Vec<Vec<Bytes>> {
3454    let keys: Vec<_> = keys.iter().map(|key| Nibbles::unpack(keccak256(key))).collect();
3455
3456    let mut builder = HashBuilder::default().with_proof_retainer(ProofRetainer::new(keys.clone()));
3457
3458    for (key, value) in trie_storage(storage) {
3459        builder.add_leaf(key, &value);
3460    }
3461
3462    let _ = builder.root();
3463
3464    let mut proofs = Vec::new();
3465    let all_proof_nodes = builder.take_proof_nodes();
3466
3467    for proof_key in keys {
3468        // Iterate over all proof nodes and find the matching ones.
3469        // The filtered results are guaranteed to be in order.
3470        let matching_proof_nodes =
3471            all_proof_nodes.matching_nodes_sorted(&proof_key).into_iter().map(|(_, node)| node);
3472        proofs.push(matching_proof_nodes.collect());
3473    }
3474
3475    proofs
3476}
3477
3478pub fn is_arbitrum(chain_id: u64) -> bool {
3479    if let Ok(chain) = NamedChain::try_from(chain_id) {
3480        return chain.is_arbitrum();
3481    }
3482    false
3483}
3484
3485pub fn op_haltreason_to_instruction_result(op_reason: OpHaltReason) -> InstructionResult {
3486    match op_reason {
3487        OpHaltReason::Base(eth_h) => eth_h.into(),
3488        OpHaltReason::FailedDeposit => InstructionResult::Stop,
3489    }
3490}