anvil/eth/backend/mem/
mod.rs

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