Skip to main content

anvil/eth/backend/mem/
mod.rs

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