anvil/eth/backend/mem/
mod.rs

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