Skip to main content

foundry_evm_core/backend/
mod.rs

1//! Foundry's main executor backend abstraction and implementation.
2
3use crate::{
4    EthInspectorExt, FoundryBlock, FoundryTransaction,
5    constants::{CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, TEST_CONTRACT_ADDRESS},
6    evm::new_eth_evm_with_inspector,
7    fork::{CreateFork, ForkId, MultiFork},
8    state_snapshot::StateSnapshots,
9    utils::get_blob_base_fee_update_fraction,
10};
11use alloy_consensus::{BlockHeader, Typed2718};
12use alloy_evm::{Evm, EvmEnv, FromRecoveredTx};
13use alloy_genesis::GenesisAccount;
14use alloy_network::{
15    AnyNetwork, AnyRpcBlock, AnyRpcTransaction, AnyTxEnvelope, BlockResponse, TransactionResponse,
16};
17use alloy_primitives::{Address, B256, TxKind, U256, keccak256, uint};
18use alloy_rpc_types::{BlockNumberOrTag, Transaction};
19use eyre::Context;
20use foundry_common::{SYSTEM_TRANSACTION_TYPE, is_known_system_sender};
21pub use foundry_fork_db::{BlockchainDb, SharedBackend, cache::BlockchainDbMeta};
22use revm::{
23    Database, DatabaseCommit, JournalEntry,
24    bytecode::Bytecode,
25    context::{BlockEnv, JournalInner, TxEnv},
26    context_interface::{journaled_state::account::JournaledAccountTr, result::ResultAndState},
27    database::{CacheDB, DatabaseRef},
28    inspector::NoOpInspector,
29    precompile::{PrecompileSpecId, Precompiles},
30    primitives::{HashMap as Map, KECCAK_EMPTY, Log, hardfork::SpecId},
31    state::{Account, AccountInfo, EvmState, EvmStorageSlot},
32};
33use std::{
34    collections::{BTreeMap, HashMap, HashSet},
35    fmt::Debug,
36    time::Instant,
37};
38
39mod diagnostic;
40pub use diagnostic::RevertDiagnostic;
41
42mod error;
43pub use error::{BackendError, BackendResult, DatabaseError, DatabaseResult};
44
45mod cow;
46pub use cow::CowBackend;
47
48mod in_memory_db;
49pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
50
51mod snapshot;
52pub use snapshot::{BackendStateSnapshot, RevertStateSnapshotAction, StateSnapshot};
53
54// A `revm::Database` that is used in forking mode
55type ForkDB = CacheDB<SharedBackend>;
56
57/// Represents a numeric `ForkId` valid only for the existence of the `Backend`.
58///
59/// The difference between `ForkId` and `LocalForkId` is that `ForkId` tracks pairs of `endpoint +
60/// block` which can be reused by multiple tests, whereas the `LocalForkId` is unique within a test
61pub type LocalForkId = U256;
62
63/// Represents the index of a fork in the created forks vector
64/// This is used for fast lookup
65type ForkLookupIndex = usize;
66
67/// All accounts that will have persistent storage across fork swaps.
68const DEFAULT_PERSISTENT_ACCOUNTS: [Address; 3] =
69    [CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, CALLER];
70
71/// `bytes32("failed")`, as a storage slot key into [`CHEATCODE_ADDRESS`].
72///
73/// Used by all `forge-std` test contracts and newer `DSTest` test contracts as a global marker for
74/// a failed test.
75pub const GLOBAL_FAIL_SLOT: U256 =
76    uint!(0x6661696c65640000000000000000000000000000000000000000000000000000_U256);
77
78pub type JournaledState = JournalInner<JournalEntry>;
79
80/// An extension trait that allows us to easily extend the `revm::Inspector` capabilities
81#[auto_impl::auto_impl(&mut)]
82pub trait DatabaseExt<BLOCK = BlockEnv, TX = TxEnv, SPEC = SpecId>:
83    Database<Error = DatabaseError> + DatabaseCommit + Debug
84{
85    /// Creates a new state snapshot at the current point of execution.
86    ///
87    /// A state snapshot is associated with a new unique id that's created for the snapshot.
88    /// State snapshots can be reverted: [DatabaseExt::revert_state], however, depending on the
89    /// [RevertStateSnapshotAction], it will keep the snapshot alive or delete it.
90    fn snapshot_state(
91        &mut self,
92        journaled_state: &JournaledState,
93        evm_env: &EvmEnv<SPEC, BLOCK>,
94    ) -> U256;
95
96    /// Reverts the snapshot if it exists
97    ///
98    /// Returns `true` if the snapshot was successfully reverted, `false` if no snapshot for that id
99    /// exists.
100    ///
101    /// **N.B.** While this reverts the state of the evm to the snapshot, it keeps new logs made
102    /// since the snapshots was created. This way we can show logs that were emitted between
103    /// snapshot and its revert.
104    /// This will also revert any changes in the `EvmEnv` and `TxEnv` and replace them with the
105    /// captured values from `Self::snapshot_state`.
106    ///
107    /// Depending on [RevertStateSnapshotAction] it will keep the snapshot alive or delete it.
108    fn revert_state(
109        &mut self,
110        id: U256,
111        journaled_state: &JournaledState,
112        evm_env: &mut EvmEnv<SPEC, BLOCK>,
113        tx_env: &mut TX,
114        action: RevertStateSnapshotAction,
115    ) -> Option<JournaledState>;
116
117    /// Deletes the state snapshot with the given `id`
118    ///
119    /// Returns `true` if the snapshot was successfully deleted, `false` if no snapshot for that id
120    /// exists.
121    fn delete_state_snapshot(&mut self, id: U256) -> bool;
122
123    /// Deletes all state snapshots.
124    fn delete_state_snapshots(&mut self);
125
126    /// Creates and also selects a new fork
127    ///
128    /// This is basically `create_fork` + `select_fork`
129    fn create_select_fork(
130        &mut self,
131        fork: CreateFork,
132        evm_env: &mut EvmEnv<SPEC, BLOCK>,
133        tx_env: &mut TX,
134        journaled_state: &mut JournaledState,
135    ) -> eyre::Result<LocalForkId> {
136        let id = self.create_fork(fork)?;
137        self.select_fork(id, evm_env, tx_env, journaled_state)?;
138        Ok(id)
139    }
140
141    /// Creates and also selects a new fork
142    ///
143    /// This is basically `create_fork` + `select_fork`
144    fn create_select_fork_at_transaction(
145        &mut self,
146        fork: CreateFork,
147        evm_env: &mut EvmEnv<SPEC, BLOCK>,
148        tx_env: &mut TX,
149        journaled_state: &mut JournaledState,
150        transaction: B256,
151    ) -> eyre::Result<LocalForkId> {
152        let id = self.create_fork_at_transaction(fork, transaction)?;
153        self.select_fork(id, evm_env, tx_env, journaled_state)?;
154        Ok(id)
155    }
156
157    /// Creates a new fork but does _not_ select it
158    fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId>;
159
160    /// Creates a new fork but does _not_ select it
161    fn create_fork_at_transaction(
162        &mut self,
163        fork: CreateFork,
164        transaction: B256,
165    ) -> eyre::Result<LocalForkId>;
166
167    /// Selects the fork's state
168    ///
169    /// This will also modify the current `EvmEnv` and `TxEnv`.
170    ///
171    /// **Note**: this does not change the local state, but swaps the remote state
172    ///
173    /// # Errors
174    ///
175    /// Returns an error if no fork with the given `id` exists
176    fn select_fork(
177        &mut self,
178        id: LocalForkId,
179        evm_env: &mut EvmEnv<SPEC, BLOCK>,
180        tx_env: &mut TX,
181        journaled_state: &mut JournaledState,
182    ) -> eyre::Result<()>;
183
184    /// Updates the fork to given block number.
185    ///
186    /// This will essentially create a new fork at the given block height.
187    ///
188    /// # Errors
189    ///
190    /// Returns an error if not matching fork was found.
191    fn roll_fork(
192        &mut self,
193        id: Option<LocalForkId>,
194        block_number: u64,
195        evm_env: &mut EvmEnv<SPEC, BLOCK>,
196        tx_env: &mut TX,
197        journaled_state: &mut JournaledState,
198    ) -> eyre::Result<()>;
199
200    /// Updates the fork to given transaction hash
201    ///
202    /// This will essentially create a new fork at the block this transaction was mined and replays
203    /// all transactions up until the given transaction.
204    ///
205    /// # Errors
206    ///
207    /// Returns an error if not matching fork was found.
208    fn roll_fork_to_transaction(
209        &mut self,
210        id: Option<LocalForkId>,
211        transaction: B256,
212        evm_env: &mut EvmEnv<SPEC, BLOCK>,
213        tx_env: &mut TX,
214        journaled_state: &mut JournaledState,
215    ) -> eyre::Result<()>;
216
217    /// Fetches the given transaction for the fork and executes it, committing the state in the DB
218    fn transact(
219        &mut self,
220        id: Option<LocalForkId>,
221        transaction: B256,
222        evm_env: EvmEnv<SPEC, BLOCK>,
223        tx_env: TX,
224        journaled_state: &mut JournaledState,
225        inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,
226    ) -> eyre::Result<()>;
227
228    /// Executes a given TransactionRequest, commits the new state to the DB
229    fn transact_from_tx(
230        &mut self,
231        tx_env: &TX,
232        evm_env: EvmEnv<SPEC, BLOCK>,
233        journaled_state: &mut JournaledState,
234        inspector: &mut dyn EthInspectorExt<BLOCK, TX, SPEC>,
235    ) -> eyre::Result<()>;
236
237    /// Returns the `ForkId` that's currently used in the database, if fork mode is on
238    fn active_fork_id(&self) -> Option<LocalForkId>;
239
240    /// Returns the Fork url that's currently used in the database, if fork mode is on
241    fn active_fork_url(&self) -> Option<String>;
242
243    /// Whether the database is currently in forked mode.
244    fn is_forked_mode(&self) -> bool {
245        self.active_fork_id().is_some()
246    }
247
248    /// Ensures that an appropriate fork exists
249    ///
250    /// If `id` contains a requested `Fork` this will ensure it exists.
251    /// Otherwise, this returns the currently active fork.
252    ///
253    /// # Errors
254    ///
255    /// Returns an error if the given `id` does not match any forks
256    ///
257    /// Returns an error if no fork exists
258    fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId>;
259
260    /// Ensures that a corresponding `ForkId` exists for the given local `id`
261    fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId>;
262
263    /// Handling multiple accounts/new contracts in a multifork environment can be challenging since
264    /// every fork has its own standalone storage section. So this can be a common error to run
265    /// into:
266    ///
267    /// ```solidity
268    /// function testCanDeploy() public {
269    ///    vm.selectFork(mainnetFork);
270    ///    // contract created while on `mainnetFork`
271    ///    DummyContract dummy = new DummyContract();
272    ///    // this will succeed
273    ///    dummy.hello();
274    ///
275    ///    vm.selectFork(optimismFork);
276    ///
277    ///    vm.expectRevert();
278    ///    // this will revert since `dummy` contract only exists on `mainnetFork`
279    ///    dummy.hello();
280    /// }
281    /// ```
282    ///
283    /// If this happens (`dummy.hello()`), or more general, a call on an address that's not a
284    /// contract, revm will revert without useful context. This call will check in this context if
285    /// `address(dummy)` belongs to an existing contract and if not will check all other forks if
286    /// the contract is deployed there.
287    ///
288    /// Returns a more useful error message if that's the case
289    fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic>;
290
291    /// Loads the account allocs from the given `allocs` map into the passed [JournaledState].
292    ///
293    /// Returns [Ok] if all accounts were successfully inserted into the journal, [Err] otherwise.
294    fn load_allocs(
295        &mut self,
296        allocs: &BTreeMap<Address, GenesisAccount>,
297        journaled_state: &mut JournaledState,
298    ) -> Result<(), BackendError>;
299
300    /// Copies bytecode, storage, nonce and balance from the given genesis account to the target
301    /// address.
302    ///
303    /// Returns [Ok] if data was successfully inserted into the journal, [Err] otherwise.
304    fn clone_account(
305        &mut self,
306        source: &GenesisAccount,
307        target: &Address,
308        journaled_state: &mut JournaledState,
309    ) -> Result<(), BackendError>;
310
311    /// Returns true if the given account is currently marked as persistent.
312    fn is_persistent(&self, acc: &Address) -> bool;
313
314    /// Revokes persistent status from the given account.
315    fn remove_persistent_account(&mut self, account: &Address) -> bool;
316
317    /// Marks the given account as persistent.
318    fn add_persistent_account(&mut self, account: Address) -> bool;
319
320    /// Removes persistent status from all given accounts.
321    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
322    fn remove_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
323    where
324        Self: Sized,
325    {
326        for acc in accounts {
327            self.remove_persistent_account(&acc);
328        }
329    }
330
331    /// Extends the persistent accounts with the accounts the iterator yields.
332    #[auto_impl(keep_default_for(&, &mut, Rc, Arc, Box))]
333    fn extend_persistent_accounts(&mut self, accounts: impl IntoIterator<Item = Address>)
334    where
335        Self: Sized,
336    {
337        for acc in accounts {
338            self.add_persistent_account(acc);
339        }
340    }
341
342    /// Grants cheatcode access for the given `account`
343    ///
344    /// Returns true if the `account` already has access
345    fn allow_cheatcode_access(&mut self, account: Address) -> bool;
346
347    /// Revokes cheatcode access for the given account
348    ///
349    /// Returns true if the `account` was previously allowed cheatcode access
350    fn revoke_cheatcode_access(&mut self, account: &Address) -> bool;
351
352    /// Returns `true` if the given account is allowed to execute cheatcodes
353    fn has_cheatcode_access(&self, account: &Address) -> bool;
354
355    /// Ensures that `account` is allowed to execute cheatcodes
356    ///
357    /// Returns an error if [`Self::has_cheatcode_access`] returns `false`
358    fn ensure_cheatcode_access(&self, account: &Address) -> Result<(), BackendError> {
359        if !self.has_cheatcode_access(account) {
360            return Err(BackendError::NoCheats(*account));
361        }
362        Ok(())
363    }
364
365    /// Same as [`Self::ensure_cheatcode_access()`] but only enforces it if the backend is currently
366    /// in forking mode
367    fn ensure_cheatcode_access_forking_mode(&self, account: &Address) -> Result<(), BackendError> {
368        if self.is_forked_mode() {
369            return self.ensure_cheatcode_access(account);
370        }
371        Ok(())
372    }
373
374    /// Set the blockhash for a given block number.
375    ///
376    /// # Arguments
377    ///
378    /// * `number` - The block number to set the blockhash for
379    /// * `hash` - The blockhash to set
380    ///
381    /// # Note
382    ///
383    /// This function mimics the EVM limits of the `blockhash` operation:
384    /// - It sets the blockhash for blocks where `block.number - 256 <= number < block.number`
385    /// - Setting a blockhash for the current block (number == block.number) has no effect
386    /// - Setting a blockhash for future blocks (number > block.number) has no effect
387    /// - Setting a blockhash for blocks older than `block.number - 256` has no effect
388    fn set_blockhash(&mut self, block_number: U256, block_hash: B256);
389}
390
391struct _ObjectSafe(dyn DatabaseExt);
392
393/// Provides the underlying `revm::Database` implementation.
394///
395/// A `Backend` can be initialised in two forms:
396///
397/// # 1. Empty in-memory Database
398/// This is the default variant: an empty `revm::Database`
399///
400/// # 2. Forked Database
401/// A `revm::Database` that forks off a remote client
402///
403///
404/// In addition to that we support forking manually on the fly.
405/// Additional forks can be created. Each unique fork is identified by its unique `ForkId`. We treat
406/// forks as unique if they have the same `(endpoint, block number)` pair.
407///
408/// When it comes to testing, it's intended that each contract will use its own `Backend`
409/// (`Backend::clone`). This way each contract uses its own encapsulated evm state. For in-memory
410/// testing, the database is just an owned `revm::InMemoryDB`.
411///
412/// Each `Fork`, identified by a unique id, uses completely separate storage, write operations are
413/// performed only in the fork's own database, `ForkDB`.
414///
415/// A `ForkDB` consists of 2 halves:
416///   - everything fetched from the remote is readonly
417///   - all local changes (instructed by the contract) are written to the backend's `db` and don't
418///     alter the state of the remote client.
419///
420/// # Fork swapping
421///
422/// Multiple "forks" can be created `Backend::create_fork()`, however only 1 can be used by the
423/// `db`. However, their state can be hot-swapped by swapping the read half of `db` from one fork to
424/// another.
425/// When swapping forks (`Backend::select_fork()`) we also update the current `EvmEnv` of the `EVM`
426/// accordingly, so that all `block.*` config values match
427///
428/// When another for is selected [`DatabaseExt::select_fork()`] the entire storage, including
429/// `JournaledState` is swapped, but the storage of the caller's and the test contract account is
430/// _always_ cloned. This way a fork has entirely separate storage but data can still be shared
431/// across fork boundaries via stack and contract variables.
432///
433/// # Snapshotting
434///
435/// A snapshot of the current overall state can be taken at any point in time. A snapshot is
436/// identified by a unique id that's returned when a snapshot is created. A snapshot can only be
437/// reverted _once_. After a successful revert, the same snapshot id cannot be used again. Reverting
438/// a snapshot replaces the current active state with the snapshot state, the snapshot is deleted
439/// afterwards, as well as any snapshots taken after the reverted snapshot, (e.g.: reverting to id
440/// 0x1 will delete snapshots with ids 0x1, 0x2, etc.)
441///
442/// **Note:** State snapshots work across fork-swaps, e.g. if fork `A` is currently active, then a
443/// snapshot is created before fork `B` is selected, then fork `A` will be the active fork again
444/// after reverting the snapshot.
445#[derive(Clone, Debug)]
446#[must_use]
447pub struct Backend {
448    /// The access point for managing forks
449    forks: MultiFork<AnyNetwork>,
450    // The default in memory db
451    mem_db: FoundryEvmInMemoryDB,
452    /// The journaled_state to use to initialize new forks with
453    ///
454    /// The way [`JournaledState`] works is, that it holds the "hot" accounts loaded from the
455    /// underlying `Database` that feeds the Account and State data to the journaled_state so it
456    /// can apply changes to the state while the EVM executes.
457    ///
458    /// In a way the `JournaledState` is something like a cache that
459    /// 1. check if account is already loaded (hot)
460    /// 2. if not load from the `Database` (this will then retrieve the account via RPC in forking
461    ///    mode)
462    ///
463    /// To properly initialize we store the `JournaledState` before the first fork is selected
464    /// ([`DatabaseExt::select_fork`]).
465    ///
466    /// This will be an empty `JournaledState`, which will be populated with persistent accounts,
467    /// See [`Self::update_fork_db()`].
468    fork_init_journaled_state: JournaledState,
469    /// The currently active fork database
470    ///
471    /// If this is set, then the Backend is currently in forking mode
472    active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>,
473    /// holds additional Backend data
474    inner: BackendInner,
475}
476
477impl Backend {
478    /// Creates a new Backend with a spawned multi fork thread.
479    ///
480    /// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory
481    /// database.
482    pub fn spawn(fork: Option<CreateFork>) -> eyre::Result<Self> {
483        Self::new(MultiFork::spawn(), fork)
484    }
485
486    /// Creates a new instance of `Backend`
487    ///
488    /// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory
489    /// database.
490    ///
491    /// Prefer using [`spawn`](Self::spawn) instead.
492    pub fn new(forks: MultiFork<AnyNetwork>, fork: Option<CreateFork>) -> eyre::Result<Self> {
493        trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend");
494        // Note: this will take of registering the `fork`
495        let inner = BackendInner {
496            persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS),
497            ..Default::default()
498        };
499
500        let mut backend = Self {
501            forks,
502            mem_db: CacheDB::new(Default::default()),
503            fork_init_journaled_state: inner.new_journaled_state(),
504            active_fork_ids: None,
505            inner,
506        };
507
508        if let Some(fork) = fork {
509            let (fork_id, fork, _) = backend.forks.create_fork(fork)?;
510            let fork_db = ForkDB::new(fork);
511            let fork_ids = backend.inner.insert_new_fork(
512                fork_id.clone(),
513                fork_db,
514                backend.inner.new_journaled_state(),
515            );
516            backend.inner.launched_with_fork = Some((fork_id, fork_ids.0, fork_ids.1));
517            backend.active_fork_ids = Some(fork_ids);
518        }
519
520        trace!(target: "backend", forking_mode=? backend.active_fork_ids.is_some(), "created executor backend");
521
522        Ok(backend)
523    }
524
525    /// Creates a new instance of `Backend` with fork added to the fork database and sets the fork
526    /// as active
527    pub(crate) fn new_with_fork(
528        id: &ForkId,
529        fork: Fork,
530        journaled_state: JournaledState,
531    ) -> eyre::Result<Self> {
532        let mut backend = Self::spawn(None)?;
533        let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state);
534        backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1));
535        backend.active_fork_ids = Some(fork_ids);
536        Ok(backend)
537    }
538
539    /// Creates a new instance with a `BackendDatabase::InMemory` cache layer for the `CacheDB`
540    pub fn clone_empty(&self) -> Self {
541        Self {
542            forks: self.forks.clone(),
543            mem_db: CacheDB::new(Default::default()),
544            fork_init_journaled_state: self.inner.new_journaled_state(),
545            active_fork_ids: None,
546            inner: Default::default(),
547        }
548    }
549
550    pub fn insert_account_info(&mut self, address: Address, account: AccountInfo) {
551        if let Some(db) = self.active_fork_db_mut() {
552            db.insert_account_info(address, account)
553        } else {
554            self.mem_db.insert_account_info(address, account)
555        }
556    }
557
558    /// Inserts a value on an account's storage without overriding account info
559    pub fn insert_account_storage(
560        &mut self,
561        address: Address,
562        slot: U256,
563        value: U256,
564    ) -> Result<(), DatabaseError> {
565        if let Some(db) = self.active_fork_db_mut() {
566            db.insert_account_storage(address, slot, value)
567        } else {
568            self.mem_db.insert_account_storage(address, slot, value)
569        }
570    }
571
572    /// Completely replace an account's storage without overriding account info.
573    ///
574    /// When forking, this causes the backend to assume a `0` value for all
575    /// unset storage slots instead of trying to fetch it.
576    pub fn replace_account_storage(
577        &mut self,
578        address: Address,
579        storage: Map<U256, U256>,
580    ) -> Result<(), DatabaseError> {
581        if let Some(db) = self.active_fork_db_mut() {
582            db.replace_account_storage(address, storage)
583        } else {
584            self.mem_db.replace_account_storage(address, storage)
585        }
586    }
587
588    /// Returns all snapshots created in this backend
589    pub fn state_snapshots(
590        &self,
591    ) -> &StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>> {
592        &self.inner.state_snapshots
593    }
594
595    /// Sets the address of the `DSTest` contract that is being executed
596    ///
597    /// This will also mark the caller as persistent and remove the persistent status from the
598    /// previous test contract address
599    ///
600    /// This will also grant cheatcode access to the test account
601    pub fn set_test_contract(&mut self, acc: Address) -> &mut Self {
602        trace!(?acc, "setting test account");
603        self.add_persistent_account(acc);
604        self.allow_cheatcode_access(acc);
605        self
606    }
607
608    /// Sets the caller address
609    pub fn set_caller(&mut self, acc: Address) -> &mut Self {
610        trace!(?acc, "setting caller account");
611        self.inner.caller = Some(acc);
612        self.allow_cheatcode_access(acc);
613        self
614    }
615
616    /// Sets the current spec id
617    pub fn set_spec_id(&mut self, spec_id: SpecId) -> &mut Self {
618        trace!(?spec_id, "setting spec ID");
619        self.inner.spec_id = spec_id;
620        self
621    }
622
623    /// Returns the set caller address
624    pub fn caller_address(&self) -> Option<Address> {
625        self.inner.caller
626    }
627
628    /// Failures occurred in state snapshots are tracked when the state snapshot is reverted.
629    ///
630    /// If an error occurs in a restored state snapshot, the test is considered failed.
631    ///
632    /// This returns whether there was a reverted state snapshot that recorded an error.
633    pub fn has_state_snapshot_failure(&self) -> bool {
634        self.inner.has_state_snapshot_failure
635    }
636
637    /// Sets the state snapshot failure flag.
638    pub fn set_state_snapshot_failure(&mut self, has_state_snapshot_failure: bool) {
639        self.inner.has_state_snapshot_failure = has_state_snapshot_failure
640    }
641
642    /// When creating or switching forks, we update the AccountInfo of the contract
643    pub(crate) fn update_fork_db(
644        &self,
645        active_journaled_state: &mut JournaledState,
646        target_fork: &mut Fork,
647    ) {
648        self.update_fork_db_contracts(
649            self.inner.persistent_accounts.iter().copied(),
650            active_journaled_state,
651            target_fork,
652        )
653    }
654
655    /// Merges the state of all `accounts` from the currently active db into the given `fork`
656    pub(crate) fn update_fork_db_contracts(
657        &self,
658        accounts: impl IntoIterator<Item = Address>,
659        active_journaled_state: &mut JournaledState,
660        target_fork: &mut Fork,
661    ) {
662        if let Some(db) = self.active_fork_db() {
663            merge_account_data(accounts, db, active_journaled_state, target_fork)
664        } else {
665            merge_account_data(accounts, &self.mem_db, active_journaled_state, target_fork)
666        }
667    }
668
669    /// Returns the memory db used if not in forking mode
670    pub fn mem_db(&self) -> &FoundryEvmInMemoryDB {
671        &self.mem_db
672    }
673
674    /// Returns true if the `id` is currently active
675    pub fn is_active_fork(&self, id: LocalForkId) -> bool {
676        self.active_fork_ids.map(|(i, _)| i == id).unwrap_or_default()
677    }
678
679    /// Returns `true` if the `Backend` is currently in forking mode
680    pub fn is_in_forking_mode(&self) -> bool {
681        self.active_fork().is_some()
682    }
683
684    /// Returns the currently active `Fork`, if any
685    pub fn active_fork(&self) -> Option<&Fork> {
686        self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx))
687    }
688
689    /// Returns the currently active `Fork`, if any
690    pub fn active_fork_mut(&mut self) -> Option<&mut Fork> {
691        self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx))
692    }
693
694    /// Returns the currently active `ForkDB`, if any
695    pub fn active_fork_db(&self) -> Option<&ForkDB> {
696        self.active_fork().map(|f| &f.db)
697    }
698
699    /// Returns the currently active `ForkDB`, if any
700    pub fn active_fork_db_mut(&mut self) -> Option<&mut ForkDB> {
701        self.active_fork_mut().map(|f| &mut f.db)
702    }
703
704    /// Returns the current database implementation as a `&dyn` value.
705    pub fn db(&self) -> &dyn Database<Error = DatabaseError> {
706        match self.active_fork_db() {
707            Some(fork_db) => fork_db,
708            None => &self.mem_db,
709        }
710    }
711
712    /// Returns the current database implementation as a `&mut dyn` value.
713    pub fn db_mut(&mut self) -> &mut dyn Database<Error = DatabaseError> {
714        match self.active_fork_ids.map(|(_, idx)| &mut self.inner.get_fork_mut(idx).db) {
715            Some(fork_db) => fork_db,
716            None => &mut self.mem_db,
717        }
718    }
719
720    /// Creates a snapshot of the currently active database
721    pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot {
722        if let Some((id, idx)) = self.active_fork_ids {
723            let fork = self.inner.get_fork(idx).clone();
724            let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed");
725            BackendDatabaseSnapshot::Forked(id, fork_id, idx, Box::new(fork))
726        } else {
727            BackendDatabaseSnapshot::InMemory(self.mem_db.clone())
728        }
729    }
730
731    /// Since each `Fork` tracks logs separately, we need to merge them to get _all_ of them
732    pub fn merged_logs(&self, mut logs: Vec<Log>) -> Vec<Log> {
733        if let Some((_, active)) = self.active_fork_ids {
734            let mut all_logs = Vec::with_capacity(logs.len());
735
736            self.inner
737                .forks
738                .iter()
739                .enumerate()
740                .filter_map(|(idx, f)| f.as_ref().map(|f| (idx, f)))
741                .for_each(|(idx, f)| {
742                    if idx == active {
743                        all_logs.append(&mut logs);
744                    } else {
745                        all_logs.extend(f.journaled_state.logs.clone())
746                    }
747                });
748            return all_logs;
749        }
750
751        logs
752    }
753
754    /// Initializes settings we need to keep track of.
755    ///
756    /// We need to track these mainly to prevent issues when switching between different evms
757    pub(crate) fn initialize(&mut self, spec_id: SpecId, caller: Address, tx_kind: TxKind) {
758        self.set_caller(caller);
759        self.set_spec_id(spec_id);
760
761        let test_contract = match tx_kind {
762            TxKind::Call(to) => to,
763            TxKind::Create => {
764                let nonce =
765                    self.basic_ref(caller).map(|b| b.unwrap_or_default().nonce).unwrap_or_default();
766                caller.create(nonce)
767            }
768        };
769        self.set_test_contract(test_contract);
770    }
771
772    /// Executes the configured test call of the `env` without committing state changes.
773    ///
774    /// Note: in case there are any cheatcodes executed that modify the environment, this will
775    /// update the given `env` with the new values.
776    #[instrument(name = "inspect", level = "debug", skip_all)]
777    pub fn inspect<I: EthInspectorExt>(
778        &mut self,
779        evm_env: &mut EvmEnv,
780        tx_env: &mut TxEnv,
781        inspector: I,
782    ) -> eyre::Result<ResultAndState> {
783        self.initialize(evm_env.cfg_env.spec, tx_env.caller, tx_env.kind);
784        let mut evm = crate::evm::new_eth_evm_with_inspector(
785            self,
786            evm_env.to_owned(),
787            tx_env.to_owned(),
788            inspector,
789        );
790
791        let res = evm.transact(tx_env.clone()).wrap_err("EVM error")?;
792
793        *evm_env = EvmEnv::new(evm.cfg.clone(), evm.block.clone());
794        *tx_env = evm.tx.clone();
795
796        Ok(res)
797    }
798
799    /// Returns true if the address is a precompile
800    pub fn is_existing_precompile(&self, addr: &Address) -> bool {
801        self.inner.precompiles().contains(addr)
802    }
803
804    /// Sets the initial journaled state to use when initializing forks
805    #[inline]
806    fn set_init_journaled_state(&mut self, journaled_state: JournaledState) {
807        trace!("recording fork init journaled_state");
808        self.fork_init_journaled_state = journaled_state;
809    }
810
811    /// Cleans up already loaded accounts that would be initialized without the correct data from
812    /// the fork.
813    ///
814    /// It can happen that an account is loaded before the first fork is selected, like
815    /// `getNonce(addr)`, which will load an empty account by default.
816    ///
817    /// This account data then would not match the account data of a fork if it exists.
818    /// So when the first fork is initialized we replace these accounts with the actual account as
819    /// it exists on the fork.
820    fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> {
821        let loaded_accounts = self
822            .fork_init_journaled_state
823            .state
824            .iter()
825            .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr))
826            .map(|(addr, _)| addr)
827            .copied()
828            .collect::<Vec<_>>();
829
830        for fork in self.inner.forks_iter_mut() {
831            let mut journaled_state = self.fork_init_journaled_state.clone();
832            for loaded_account in loaded_accounts.iter().copied() {
833                trace!(?loaded_account, "replacing account on init");
834                let init_account =
835                    journaled_state.state.get_mut(&loaded_account).expect("exists; qed");
836
837                // here's an edge case where we need to check if this account has been created, in
838                // which case we don't need to replace it with the account from the fork because the
839                // created account takes precedence: for example contract creation in setups
840                if init_account.is_created() {
841                    trace!(?loaded_account, "skipping created account");
842                    continue;
843                }
844
845                // otherwise we need to replace the account's info with the one from the fork's
846                // database
847                let fork_account = Database::basic(&mut fork.db, loaded_account)?
848                    .ok_or(BackendError::MissingAccount(loaded_account))?;
849                init_account.info = fork_account;
850            }
851            fork.journaled_state = journaled_state;
852        }
853        Ok(())
854    }
855
856    /// Returns the block numbers required for replaying a transaction
857    fn get_block_number_and_block_for_transaction(
858        &self,
859        id: LocalForkId,
860        transaction: B256,
861    ) -> eyre::Result<(u64, AnyRpcBlock)> {
862        let fork = self.inner.get_fork_by_id(id)?;
863        let tx = fork.backend().get_transaction(transaction)?;
864
865        // get the block number we need to fork
866        if let Some(tx_block) = tx.block_number {
867            let block = fork.backend().get_full_block(tx_block)?;
868
869            // we need to subtract 1 here because we want the state before the transaction
870            // was mined
871            let fork_block = tx_block - 1;
872            Ok((fork_block, block))
873        } else {
874            let block = fork.backend().get_full_block(BlockNumberOrTag::Latest)?;
875
876            let number = block.header.number();
877
878            Ok((number, block))
879        }
880    }
881
882    /// Replays all the transactions at the forks current block that were mined before the `tx`
883    ///
884    /// Returns the _unmined_ transaction that corresponds to the given `tx_hash`
885    pub fn replay_until(
886        &mut self,
887        id: LocalForkId,
888        mut evm_env: EvmEnv,
889        mut tx_env: TxEnv,
890        tx_hash: B256,
891        journaled_state: &mut JournaledState,
892    ) -> eyre::Result<Option<Transaction<AnyTxEnvelope>>> {
893        trace!(?id, ?tx_hash, "replay until transaction");
894
895        let persistent_accounts = self.inner.persistent_accounts.clone();
896        let fork_id = self.ensure_fork_id(id)?.clone();
897
898        let fork = self.inner.get_fork_by_id_mut(id)?;
899        let full_block =
900            fork.backend().get_full_block(evm_env.block_env.number.saturating_to::<u64>())?;
901
902        for tx in full_block.inner.transactions.txns() {
903            // System transactions such as on L2s don't contain any pricing info so we skip them
904            // otherwise this would cause reverts
905            if is_known_system_sender(tx.inner().inner.signer())
906                || tx.ty() == SYSTEM_TRANSACTION_TYPE
907            {
908                trace!(tx=?tx.tx_hash(), "skipping system transaction");
909                continue;
910            }
911
912            if tx.tx_hash() == tx_hash {
913                // found the target transaction
914                return Ok(Some(tx.inner.clone()));
915            }
916            trace!(tx=?tx.tx_hash(), "committing transaction");
917
918            commit_transaction(
919                tx,
920                &mut evm_env,
921                &mut tx_env,
922                journaled_state,
923                fork,
924                &fork_id,
925                &persistent_accounts,
926                &mut NoOpInspector,
927            )?;
928        }
929
930        Ok(None)
931    }
932}
933
934impl DatabaseExt for Backend {
935    fn snapshot_state(&mut self, journaled_state: &JournaledState, evm_env: &EvmEnv) -> U256 {
936        trace!("create snapshot");
937        let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new(
938            self.create_db_snapshot(),
939            journaled_state.clone(),
940            evm_env.clone(),
941        ));
942        trace!(target: "backend", "Created new snapshot {}", id);
943        id
944    }
945
946    fn revert_state(
947        &mut self,
948        id: U256,
949        current_state: &JournaledState,
950        evm_env: &mut EvmEnv,
951        tx_env: &mut TxEnv,
952        action: RevertStateSnapshotAction,
953    ) -> Option<JournaledState> {
954        trace!(?id, "revert snapshot");
955        if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) {
956            // Re-insert snapshot to persist it
957            if action.is_keep() {
958                self.inner.state_snapshots.insert_at(snapshot.clone(), id);
959            }
960
961            // https://github.com/foundry-rs/foundry/issues/3055
962            // Check if an error occurred either during or before the snapshot.
963            // DSTest contracts don't have snapshot functionality, so this slot is enough to check
964            // for failure here.
965            if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS)
966                && let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT)
967                && !slot.present_value.is_zero()
968            {
969                self.set_state_snapshot_failure(true);
970            }
971
972            // merge additional logs
973            snapshot.merge(current_state);
974            let BackendStateSnapshot { db, mut journaled_state, snap_evm_env } = snapshot;
975            match db {
976                BackendDatabaseSnapshot::InMemory(mem_db) => {
977                    self.mem_db = mem_db;
978                }
979                BackendDatabaseSnapshot::Forked(id, fork_id, idx, mut fork) => {
980                    // there might be the case where the snapshot was created during `setUp` with
981                    // another caller, so we need to ensure the caller account is present in the
982                    // journaled state and database
983                    let caller = tx_env.caller;
984                    journaled_state.state.entry(caller).or_insert_with(|| {
985                        let caller_account = current_state
986                            .state
987                            .get(&caller)
988                            .map(|acc| acc.info.clone())
989                            .unwrap_or_default();
990
991                        if !fork.db.cache.accounts.contains_key(&caller) {
992                            // update the caller account which is required by the evm
993                            fork.db.insert_account_info(caller, caller_account.clone());
994                        }
995                        caller_account.into()
996                    });
997                    self.inner.revert_state_snapshot(id, fork_id, idx, *fork);
998                    self.active_fork_ids = Some((id, idx))
999                }
1000            }
1001
1002            update_current_env_with_fork_env(evm_env, tx_env, snap_evm_env);
1003            trace!(target: "backend", "Reverted snapshot {}", id);
1004
1005            Some(journaled_state)
1006        } else {
1007            warn!(target: "backend", "No snapshot to revert for {}", id);
1008            None
1009        }
1010    }
1011
1012    fn delete_state_snapshot(&mut self, id: U256) -> bool {
1013        self.inner.state_snapshots.remove_at(id).is_some()
1014    }
1015
1016    fn delete_state_snapshots(&mut self) {
1017        self.inner.state_snapshots.clear()
1018    }
1019
1020    fn create_fork(&mut self, create_fork: CreateFork) -> eyre::Result<LocalForkId> {
1021        trace!("create fork");
1022        let (fork_id, fork, _) = self.forks.create_fork(create_fork)?;
1023
1024        let fork_db = ForkDB::new(fork);
1025        let (id, _) =
1026            self.inner.insert_new_fork(fork_id, fork_db, self.fork_init_journaled_state.clone());
1027        Ok(id)
1028    }
1029
1030    fn create_fork_at_transaction(
1031        &mut self,
1032        fork: CreateFork,
1033        transaction: B256,
1034    ) -> eyre::Result<LocalForkId> {
1035        trace!(?transaction, "create fork at transaction");
1036        let id = self.create_fork(fork)?;
1037        let fork_id = self.ensure_fork_id(id).cloned()?;
1038        let mut evm_env = self
1039            .forks
1040            .get_evm_env(fork_id)?
1041            .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1042
1043        // we still need to roll to the transaction, but we only need an empty dummy state since we
1044        // don't need to update the active journaled state yet
1045        self.roll_fork_to_transaction(
1046            Some(id),
1047            transaction,
1048            &mut evm_env,
1049            &mut TxEnv::default(),
1050            &mut self.inner.new_journaled_state(),
1051        )?;
1052
1053        Ok(id)
1054    }
1055
1056    /// Select an existing fork by id.
1057    /// When switching forks we copy the shared state
1058    fn select_fork(
1059        &mut self,
1060        id: LocalForkId,
1061        evm_env: &mut EvmEnv,
1062        tx_env: &mut TxEnv,
1063        active_journaled_state: &mut JournaledState,
1064    ) -> eyre::Result<()> {
1065        trace!(?id, "select fork");
1066        if self.is_active_fork(id) {
1067            // nothing to do
1068            return Ok(());
1069        }
1070
1071        // Update block number and timestamp of active fork (if any) with current env values,
1072        // in order to preserve values changed by using `roll` and `warp` cheatcodes.
1073        if let Some(active_fork_id) = self.active_fork_id() {
1074            self.forks.update_block(
1075                self.ensure_fork_id(active_fork_id).cloned()?,
1076                evm_env.block_env.number,
1077                evm_env.block_env.timestamp,
1078            )?;
1079        }
1080
1081        let fork_id = self.ensure_fork_id(id).cloned()?;
1082        let idx = self.inner.ensure_fork_index(&fork_id)?;
1083        let fork_evm_env = self
1084            .forks
1085            .get_evm_env(fork_id)?
1086            .ok_or_else(|| eyre::eyre!("Requested fork `{}` does not exist", id))?;
1087
1088        // If we're currently in forking mode we need to update the journaled_state to this point,
1089        // this ensures the changes performed while the fork was active are recorded
1090        if let Some(active) = self.active_fork_mut() {
1091            active.journaled_state = active_journaled_state.clone();
1092
1093            let caller = tx_env.caller;
1094            let caller_account = active.journaled_state.state.get(&tx_env.caller).cloned();
1095            let target_fork = self.inner.get_fork_mut(idx);
1096
1097            // depth 0 will be the default value when the fork was created
1098            if target_fork.journaled_state.depth == 0 {
1099                // Initialize caller with its fork info
1100                if let Some(mut acc) = caller_account {
1101                    let fork_account = Database::basic(&mut target_fork.db, caller)?
1102                        .ok_or(BackendError::MissingAccount(caller))?;
1103
1104                    acc.info = fork_account;
1105                    target_fork.journaled_state.state.insert(caller, acc);
1106                }
1107            }
1108        } else {
1109            // this is the first time a fork is selected. This means up to this point all changes
1110            // are made in a single `JournaledState`, for example after a `setup` that only created
1111            // different forks. Since the `JournaledState` is valid for all forks until the
1112            // first fork is selected, we need to update it for all forks and use it as init state
1113            // for all future forks
1114
1115            self.set_init_journaled_state(active_journaled_state.clone());
1116            self.prepare_init_journal_state()?;
1117
1118            // Make sure that the next created fork has a depth of 0.
1119            self.fork_init_journaled_state.depth = 0;
1120        }
1121
1122        {
1123            // update the shared state and track
1124            let mut fork = self.inner.take_fork(idx);
1125
1126            // Make sure all persistent accounts on the newly selected fork reflect same state as
1127            // the active db / previous fork.
1128            // This can get out of sync when multiple forks are created on test `setUp`, then a
1129            // fork is selected and persistent contract is changed. If first action in test is to
1130            // select a different fork, then the persistent contract state won't reflect changes
1131            // done in `setUp` for the other fork.
1132            // See <https://github.com/foundry-rs/foundry/issues/10296> and <https://github.com/foundry-rs/foundry/issues/10552>.
1133            let persistent_accounts = self.inner.persistent_accounts.clone();
1134            if let Some(db) = self.active_fork_db_mut() {
1135                for addr in persistent_accounts {
1136                    let Ok(db_account) = db.load_account(addr) else { continue };
1137
1138                    let Some(fork_account) = fork.journaled_state.state.get_mut(&addr) else {
1139                        continue;
1140                    };
1141
1142                    for (key, val) in &db_account.storage {
1143                        if let Some(fork_storage) = fork_account.storage.get_mut(key) {
1144                            fork_storage.present_value = *val;
1145                        }
1146                    }
1147                }
1148            }
1149
1150            // since all forks handle their state separately, the depth can drift
1151            // this is a handover where the target fork starts at the same depth where it was
1152            // selected. This ensures that there are no gaps in depth which would
1153            // otherwise cause issues with the tracer
1154            fork.journaled_state.depth = active_journaled_state.depth;
1155
1156            // another edge case where a fork is created and selected during setup with not
1157            // necessarily the same caller as for the test, however we must always
1158            // ensure that fork's state contains the current sender
1159            let caller = tx_env.caller;
1160            fork.journaled_state.state.entry(caller).or_insert_with(|| {
1161                let caller_account = active_journaled_state
1162                    .state
1163                    .get(&tx_env.caller)
1164                    .map(|acc| acc.info.clone())
1165                    .unwrap_or_default();
1166
1167                if !fork.db.cache.accounts.contains_key(&caller) {
1168                    // update the caller account which is required by the evm
1169                    fork.db.insert_account_info(caller, caller_account.clone());
1170                }
1171                caller_account.into()
1172            });
1173
1174            self.update_fork_db(active_journaled_state, &mut fork);
1175
1176            // insert the fork back
1177            self.inner.set_fork(idx, fork);
1178        }
1179
1180        self.active_fork_ids = Some((id, idx));
1181        // Update current environment with environment of newly selected fork.
1182        update_current_env_with_fork_env(evm_env, tx_env, fork_evm_env);
1183
1184        Ok(())
1185    }
1186
1187    /// This is effectively the same as [`Self::create_select_fork()`] but updating an existing
1188    /// [ForkId] that is mapped to the [LocalForkId]
1189    fn roll_fork(
1190        &mut self,
1191        id: Option<LocalForkId>,
1192        block_number: u64,
1193        evm_env: &mut EvmEnv,
1194        tx_env: &mut TxEnv,
1195        journaled_state: &mut JournaledState,
1196    ) -> eyre::Result<()> {
1197        trace!(?id, ?block_number, "roll fork");
1198        let id = self.ensure_fork(id)?;
1199        let (fork_id, backend, fork_env) =
1200            self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?;
1201        // this will update the local mapping
1202        self.inner.roll_fork(id, fork_id, backend)?;
1203
1204        if let Some((active_id, active_idx)) = self.active_fork_ids {
1205            // the currently active fork is the targeted fork of this call
1206            if active_id == id {
1207                // need to update the block's env settings right away, which is otherwise set when
1208                // forks are selected `select_fork`
1209                update_current_env_with_fork_env(evm_env, tx_env, fork_env);
1210
1211                // we also need to update the journaled_state right away, this has essentially the
1212                // same effect as selecting (`select_fork`) by discarding
1213                // non-persistent storage from the journaled_state. This which will
1214                // reset cached state from the previous block
1215                let mut persistent_addrs = self.inner.persistent_accounts.clone();
1216                // we also want to copy the caller state here
1217                persistent_addrs.extend(self.caller_address());
1218
1219                let active = self.inner.get_fork_mut(active_idx);
1220                active.journaled_state = self.fork_init_journaled_state.clone();
1221                active.journaled_state.depth = journaled_state.depth;
1222
1223                for addr in persistent_addrs {
1224                    merge_journaled_state_data(addr, journaled_state, &mut active.journaled_state);
1225                }
1226
1227                // Ensure all previously loaded accounts are present in the journaled state to
1228                // prevent issues in the new journalstate, e.g. assumptions that accounts are loaded
1229                // if the account is not touched, we reload it, if it's touched we clone it.
1230                //
1231                // Special case for accounts that are not created: we don't merge their state but
1232                // load it in order to reflect their state at the new block (they should explicitly
1233                // be marked as persistent if it is desired to keep state between fork rolls).
1234                for (addr, acc) in &journaled_state.state {
1235                    if acc.is_created() {
1236                        if acc.is_touched() {
1237                            merge_journaled_state_data(
1238                                *addr,
1239                                journaled_state,
1240                                &mut active.journaled_state,
1241                            );
1242                        }
1243                    } else {
1244                        let _ = active.journaled_state.load_account(&mut active.db, *addr);
1245                    }
1246                }
1247
1248                *journaled_state = active.journaled_state.clone();
1249            }
1250        }
1251        Ok(())
1252    }
1253
1254    fn roll_fork_to_transaction(
1255        &mut self,
1256        id: Option<LocalForkId>,
1257        transaction: B256,
1258        evm_env: &mut EvmEnv,
1259        tx_env: &mut TxEnv,
1260        journaled_state: &mut JournaledState,
1261    ) -> eyre::Result<()> {
1262        trace!(?id, ?transaction, "roll fork to transaction");
1263        let id = self.ensure_fork(id)?;
1264
1265        let (fork_block, block) =
1266            self.get_block_number_and_block_for_transaction(id, transaction)?;
1267
1268        // roll the fork to the transaction's parent block or latest if it's pending, because we
1269        // need to fork off the parent block's state for tx level forking and then replay the txs
1270        // before the tx in that block to get the state at the tx
1271        self.roll_fork(Some(id), fork_block, evm_env, tx_env, journaled_state)?;
1272
1273        // we need to update the env to the block
1274        update_env_block(evm_env, block.header());
1275
1276        // after we forked at the fork block we need to properly update the block env to the block
1277        // env of the tx's block
1278        let _ = self
1279            .forks
1280            .update_block_env(self.inner.ensure_fork_id(id).cloned()?, evm_env.block_env.clone());
1281
1282        // replay all transactions that came before
1283        self.replay_until(id, evm_env.clone(), tx_env.clone(), transaction, journaled_state)?;
1284
1285        Ok(())
1286    }
1287
1288    fn transact(
1289        &mut self,
1290        maybe_id: Option<LocalForkId>,
1291        transaction: B256,
1292        mut evm_env: EvmEnv,
1293        mut tx_env: TxEnv,
1294        journaled_state: &mut JournaledState,
1295        inspector: &mut dyn EthInspectorExt,
1296    ) -> eyre::Result<()> {
1297        trace!(?maybe_id, ?transaction, "execute transaction");
1298        let persistent_accounts = self.inner.persistent_accounts.clone();
1299        let id = self.ensure_fork(maybe_id)?;
1300        let fork_id = self.ensure_fork_id(id).cloned()?;
1301
1302        let tx = {
1303            let fork = self.inner.get_fork_by_id_mut(id)?;
1304            fork.backend().get_transaction(transaction)?
1305        };
1306
1307        // This is a bit ambiguous because the user wants to transact an arbitrary transaction in
1308        // the current context, but we're assuming the user wants to transact the transaction as it
1309        // was mined. Usually this is used in a combination of a fork at the transaction's parent
1310        // transaction in the block and then the transaction is transacted:
1311        // <https://github.com/foundry-rs/foundry/issues/6538>
1312        // So we modify the env to match the transaction's block.
1313        let (_fork_block, block) =
1314            self.get_block_number_and_block_for_transaction(id, transaction)?;
1315        update_env_block(&mut evm_env, block.header());
1316
1317        let fork = self.inner.get_fork_by_id_mut(id)?;
1318        commit_transaction(
1319            &tx,
1320            &mut evm_env,
1321            &mut tx_env,
1322            journaled_state,
1323            fork,
1324            &fork_id,
1325            &persistent_accounts,
1326            inspector,
1327        )
1328    }
1329
1330    fn transact_from_tx(
1331        &mut self,
1332        tx_env: &TxEnv,
1333        evm_env: EvmEnv,
1334        journaled_state: &mut JournaledState,
1335        inspector: &mut dyn EthInspectorExt,
1336    ) -> eyre::Result<()> {
1337        trace!(?tx_env, "execute signed transaction");
1338
1339        self.commit(journaled_state.state.clone());
1340
1341        let res = {
1342            let mut db = self.clone();
1343            let mut evm =
1344                new_eth_evm_with_inspector(&mut db, evm_env, tx_env.to_owned(), inspector);
1345            evm.journaled_state.depth = journaled_state.depth + 1;
1346            evm.transact_raw(tx_env.to_owned())?
1347        };
1348
1349        self.commit(res.state);
1350        update_state(&mut journaled_state.state, self, None)?;
1351
1352        Ok(())
1353    }
1354
1355    fn active_fork_id(&self) -> Option<LocalForkId> {
1356        self.active_fork_ids.map(|(id, _)| id)
1357    }
1358
1359    fn active_fork_url(&self) -> Option<String> {
1360        let fork = self.inner.issued_local_fork_ids.get(&self.active_fork_id()?)?;
1361        self.forks.get_fork_url(fork.clone()).ok()?
1362    }
1363
1364    fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
1365        if let Some(id) = id {
1366            if self.inner.issued_local_fork_ids.contains_key(&id) {
1367                return Ok(id);
1368            }
1369            eyre::bail!("Requested fork `{}` does not exist", id)
1370        }
1371        if let Some(id) = self.active_fork_id() { Ok(id) } else { eyre::bail!("No fork active") }
1372    }
1373
1374    fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1375        self.inner.ensure_fork_id(id)
1376    }
1377
1378    fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {
1379        let active_id = self.active_fork_id()?;
1380        let active_fork = self.active_fork()?;
1381
1382        if self.inner.forks.len() == 1 {
1383            // we only want to provide additional diagnostics here when in multifork mode with > 1
1384            // forks
1385            return None;
1386        }
1387
1388        if !active_fork.is_contract(callee) && !is_contract_in_state(evm_state, callee) {
1389            // no contract for `callee` available on current fork, check if available on other forks
1390            let mut available_on = Vec::new();
1391            for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) {
1392                trace!(?id, address=?callee, "checking if account exists");
1393                if fork.is_contract(callee) {
1394                    available_on.push(id);
1395                }
1396            }
1397
1398            return if available_on.is_empty() {
1399                Some(RevertDiagnostic::ContractDoesNotExist {
1400                    contract: callee,
1401                    active: active_id,
1402                    persistent: self.is_persistent(&callee),
1403                })
1404            } else {
1405                // likely user error: called a contract that's not available on active fork but is
1406                // present other forks
1407                Some(RevertDiagnostic::ContractExistsOnOtherForks {
1408                    contract: callee,
1409                    active: active_id,
1410                    available_on,
1411                })
1412            };
1413        }
1414        None
1415    }
1416
1417    /// Loads the account allocs from the given `allocs` map into the passed [JournaledState].
1418    ///
1419    /// Returns [Ok] if all accounts were successfully inserted into the journal, [Err] otherwise.
1420    fn load_allocs(
1421        &mut self,
1422        allocs: &BTreeMap<Address, GenesisAccount>,
1423        journaled_state: &mut JournaledState,
1424    ) -> Result<(), BackendError> {
1425        // Loop through all of the allocs defined in the map and commit them to the journal.
1426        for (addr, acc) in allocs {
1427            self.clone_account(acc, addr, journaled_state)?;
1428        }
1429
1430        Ok(())
1431    }
1432
1433    /// Copies bytecode, storage, nonce and balance from the given genesis account to the target
1434    /// address.
1435    ///
1436    /// Returns [Ok] if data was successfully inserted into the journal, [Err] otherwise.
1437    fn clone_account(
1438        &mut self,
1439        source: &GenesisAccount,
1440        target: &Address,
1441        journaled_state: &mut JournaledState,
1442    ) -> Result<(), BackendError> {
1443        // Fetch the account from the journaled state. Will create a new account if it does
1444        // not already exist.
1445        let mut state_acc = journaled_state.load_account_mut(self, *target)?;
1446
1447        // Set the account's bytecode and code hash, if the `bytecode` field is present.
1448        if let Some(bytecode) = source.code.as_ref() {
1449            let bytecode_hash = keccak256(bytecode);
1450            let bytecode = Bytecode::new_raw(bytecode.0.clone().into());
1451            state_acc.set_code(bytecode_hash, bytecode);
1452        }
1453
1454        // Set the account's balance.
1455        state_acc.set_balance(source.balance);
1456
1457        // Set the account's storage, if the `storage` field is present.
1458        if let Some(acc) = journaled_state.state.get_mut(target) {
1459            if let Some(storage) = source.storage.as_ref() {
1460                for (slot, value) in storage {
1461                    let slot = U256::from_be_bytes(slot.0);
1462                    acc.storage.insert(
1463                        slot,
1464                        EvmStorageSlot::new_changed(
1465                            acc.storage.get(&slot).map(|s| s.present_value).unwrap_or_default(),
1466                            U256::from_be_bytes(value.0),
1467                            0,
1468                        ),
1469                    );
1470                }
1471            }
1472
1473            // Set the account's nonce.
1474            acc.info.nonce = source.nonce.unwrap_or_default();
1475        };
1476
1477        // Touch the account to ensure the loaded information persists if called in `setUp`.
1478        journaled_state.touch(*target);
1479
1480        Ok(())
1481    }
1482
1483    fn add_persistent_account(&mut self, account: Address) -> bool {
1484        trace!(?account, "add persistent account");
1485        self.inner.persistent_accounts.insert(account)
1486    }
1487
1488    fn remove_persistent_account(&mut self, account: &Address) -> bool {
1489        trace!(?account, "remove persistent account");
1490        self.inner.persistent_accounts.remove(account)
1491    }
1492
1493    fn is_persistent(&self, acc: &Address) -> bool {
1494        self.inner.persistent_accounts.contains(acc)
1495    }
1496
1497    fn allow_cheatcode_access(&mut self, account: Address) -> bool {
1498        trace!(?account, "allow cheatcode access");
1499        self.inner.cheatcode_access_accounts.insert(account)
1500    }
1501
1502    fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
1503        trace!(?account, "revoke cheatcode access");
1504        self.inner.cheatcode_access_accounts.remove(account)
1505    }
1506
1507    fn has_cheatcode_access(&self, account: &Address) -> bool {
1508        self.inner.cheatcode_access_accounts.contains(account)
1509    }
1510
1511    fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
1512        if let Some(db) = self.active_fork_db_mut() {
1513            db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1514        } else {
1515            self.mem_db.cache.block_hashes.insert(block_number.saturating_to(), block_hash);
1516        }
1517    }
1518}
1519
1520impl DatabaseRef for Backend {
1521    type Error = DatabaseError;
1522
1523    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1524        if let Some(db) = self.active_fork_db() {
1525            db.basic_ref(address)
1526        } else {
1527            Ok(self.mem_db.basic_ref(address)?)
1528        }
1529    }
1530
1531    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1532        if let Some(db) = self.active_fork_db() {
1533            db.code_by_hash_ref(code_hash)
1534        } else {
1535            Ok(self.mem_db.code_by_hash_ref(code_hash)?)
1536        }
1537    }
1538
1539    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
1540        if let Some(db) = self.active_fork_db() {
1541            DatabaseRef::storage_ref(db, address, index)
1542        } else {
1543            Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
1544        }
1545    }
1546
1547    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
1548        if let Some(db) = self.active_fork_db() {
1549            db.block_hash_ref(number)
1550        } else {
1551            Ok(self.mem_db.block_hash_ref(number)?)
1552        }
1553    }
1554}
1555
1556impl DatabaseCommit for Backend {
1557    fn commit(&mut self, changes: Map<Address, Account>) {
1558        if let Some(db) = self.active_fork_db_mut() {
1559            db.commit(changes)
1560        } else {
1561            self.mem_db.commit(changes)
1562        }
1563    }
1564}
1565
1566impl Database for Backend {
1567    type Error = DatabaseError;
1568    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
1569        if let Some(db) = self.active_fork_db_mut() {
1570            Ok(db.basic(address)?)
1571        } else {
1572            Ok(self.mem_db.basic(address)?)
1573        }
1574    }
1575
1576    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
1577        if let Some(db) = self.active_fork_db_mut() {
1578            Ok(db.code_by_hash(code_hash)?)
1579        } else {
1580            Ok(self.mem_db.code_by_hash(code_hash)?)
1581        }
1582    }
1583
1584    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
1585        if let Some(db) = self.active_fork_db_mut() {
1586            Ok(Database::storage(db, address, index)?)
1587        } else {
1588            Ok(Database::storage(&mut self.mem_db, address, index)?)
1589        }
1590    }
1591
1592    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
1593        if let Some(db) = self.active_fork_db_mut() {
1594            Ok(db.block_hash(number)?)
1595        } else {
1596            Ok(self.mem_db.block_hash(number)?)
1597        }
1598    }
1599}
1600
1601/// Variants of a [revm::Database]
1602#[derive(Clone, Debug)]
1603pub enum BackendDatabaseSnapshot {
1604    /// Simple in-memory [revm::Database]
1605    InMemory(FoundryEvmInMemoryDB),
1606    /// Contains the entire forking mode database
1607    Forked(LocalForkId, ForkId, ForkLookupIndex, Box<Fork>),
1608}
1609
1610/// Represents a fork
1611#[derive(Clone, Debug)]
1612pub struct Fork {
1613    db: ForkDB,
1614    journaled_state: JournaledState,
1615}
1616
1617impl Fork {
1618    /// Returns a reference to the underlying [`SharedBackend`].
1619    pub fn backend(&self) -> &SharedBackend {
1620        &self.db.db
1621    }
1622
1623    /// Returns true if the account is a contract
1624    pub fn is_contract(&self, acc: Address) -> bool {
1625        if let Ok(Some(acc)) = self.db.basic_ref(acc)
1626            && acc.code_hash != KECCAK_EMPTY
1627        {
1628            return true;
1629        }
1630        is_contract_in_state(&self.journaled_state.state, acc)
1631    }
1632}
1633
1634/// Container type for various Backend related data
1635#[derive(Clone, Debug)]
1636pub struct BackendInner {
1637    /// Stores the `ForkId` of the fork the `Backend` launched with from the start.
1638    ///
1639    /// In other words if [`Backend::spawn()`] was called with a `CreateFork` command, to launch
1640    /// directly in fork mode, this holds the corresponding fork identifier of this fork.
1641    pub launched_with_fork: Option<(ForkId, LocalForkId, ForkLookupIndex)>,
1642    /// This tracks numeric fork ids and the `ForkId` used by the handler.
1643    ///
1644    /// This is necessary, because there can be multiple `Backends` associated with a single
1645    /// `ForkId` which is only a pair of endpoint + block. Since an existing fork can be
1646    /// modified (e.g. `roll_fork`), but this should only affect the fork that's unique for the
1647    /// test and not the `ForkId`
1648    ///
1649    /// This ensures we can treat forks as unique from the context of a test, so rolling to another
1650    /// is basically creating(or reusing) another `ForkId` that's then mapped to the previous
1651    /// issued _local_ numeric identifier, that remains constant, even if the underlying fork
1652    /// backend changes.
1653    pub issued_local_fork_ids: HashMap<LocalForkId, ForkId>,
1654    /// tracks all the created forks
1655    /// Contains the index of the corresponding `ForkDB` in the `forks` vec
1656    pub created_forks: HashMap<ForkId, ForkLookupIndex>,
1657    /// Holds all created fork databases
1658    // Note: data is stored in an `Option` so we can remove it without reshuffling
1659    pub forks: Vec<Option<Fork>>,
1660    /// Contains state snapshots made at a certain point
1661    pub state_snapshots: StateSnapshots<BackendStateSnapshot<BackendDatabaseSnapshot>>,
1662    /// Tracks whether there was a failure in a snapshot that was reverted
1663    ///
1664    /// The Test contract contains a bool variable that is set to true when an `assert` function
1665    /// failed. When a snapshot is reverted, it reverts the state of the evm, but we still want
1666    /// to know if there was an `assert` that failed after the snapshot was taken so that we can
1667    /// check if the test function passed all asserts even across snapshots. When a snapshot is
1668    /// reverted we get the _current_ `revm::JournaledState` which contains the state that we can
1669    /// check if the `_failed` variable is set,
1670    /// additionally
1671    pub has_state_snapshot_failure: bool,
1672    /// Tracks the caller of the test function
1673    pub caller: Option<Address>,
1674    /// Tracks numeric identifiers for forks
1675    pub next_fork_id: LocalForkId,
1676    /// All accounts that should be kept persistent when switching forks.
1677    /// This means all accounts stored here _don't_ use a separate storage section on each fork
1678    /// instead the use only one that's persistent across fork swaps.
1679    pub persistent_accounts: HashSet<Address>,
1680    /// The configured spec id
1681    pub spec_id: SpecId,
1682    /// All accounts that are allowed to execute cheatcodes
1683    pub cheatcode_access_accounts: HashSet<Address>,
1684}
1685
1686impl BackendInner {
1687    pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
1688        self.issued_local_fork_ids
1689            .get(&id)
1690            .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1691    }
1692
1693    pub fn ensure_fork_index(&self, id: &ForkId) -> eyre::Result<ForkLookupIndex> {
1694        self.created_forks
1695            .get(id)
1696            .copied()
1697            .ok_or_else(|| eyre::eyre!("No matching fork found for {}", id))
1698    }
1699
1700    pub fn ensure_fork_index_by_local_id(&self, id: LocalForkId) -> eyre::Result<ForkLookupIndex> {
1701        self.ensure_fork_index(self.ensure_fork_id(id)?)
1702    }
1703
1704    /// Returns the underlying fork mapped to the index
1705    #[track_caller]
1706    fn get_fork(&self, idx: ForkLookupIndex) -> &Fork {
1707        debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1708        self.forks[idx].as_ref().unwrap()
1709    }
1710
1711    /// Returns the underlying fork mapped to the index
1712    #[track_caller]
1713    fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork {
1714        debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1715        self.forks[idx].as_mut().unwrap()
1716    }
1717
1718    /// Returns the underlying fork corresponding to the id
1719    #[track_caller]
1720    fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> {
1721        let idx = self.ensure_fork_index_by_local_id(id)?;
1722        Ok(self.get_fork_mut(idx))
1723    }
1724
1725    /// Returns the underlying fork corresponding to the id
1726    #[track_caller]
1727    fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> {
1728        let idx = self.ensure_fork_index_by_local_id(id)?;
1729        Ok(self.get_fork(idx))
1730    }
1731
1732    /// Removes the fork
1733    fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork {
1734        debug_assert!(idx < self.forks.len(), "fork lookup index must exist");
1735        self.forks[idx].take().unwrap()
1736    }
1737
1738    fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) {
1739        self.forks[idx] = Some(fork)
1740    }
1741
1742    /// Returns an iterator over Forks
1743    pub fn forks_iter(&self) -> impl Iterator<Item = (LocalForkId, &Fork)> + '_ {
1744        self.issued_local_fork_ids
1745            .iter()
1746            .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id])))
1747    }
1748
1749    /// Returns a mutable iterator over all Forks
1750    pub fn forks_iter_mut(&mut self) -> impl Iterator<Item = &mut Fork> + '_ {
1751        self.forks.iter_mut().filter_map(|f| f.as_mut())
1752    }
1753
1754    /// Reverts the entire fork database
1755    pub fn revert_state_snapshot(
1756        &mut self,
1757        id: LocalForkId,
1758        fork_id: ForkId,
1759        idx: ForkLookupIndex,
1760        fork: Fork,
1761    ) {
1762        self.created_forks.insert(fork_id.clone(), idx);
1763        self.issued_local_fork_ids.insert(id, fork_id);
1764        self.set_fork(idx, fork)
1765    }
1766
1767    /// Updates the fork and the local mapping and returns the new index for the `fork_db`
1768    pub fn update_fork_mapping(
1769        &mut self,
1770        id: LocalForkId,
1771        fork_id: ForkId,
1772        db: ForkDB,
1773        journaled_state: JournaledState,
1774    ) -> ForkLookupIndex {
1775        let idx = self.forks.len();
1776        self.issued_local_fork_ids.insert(id, fork_id.clone());
1777        self.created_forks.insert(fork_id, idx);
1778
1779        let fork = Fork { db, journaled_state };
1780        self.forks.push(Some(fork));
1781        idx
1782    }
1783
1784    pub fn roll_fork(
1785        &mut self,
1786        id: LocalForkId,
1787        new_fork_id: ForkId,
1788        backend: SharedBackend,
1789    ) -> eyre::Result<ForkLookupIndex> {
1790        let fork_id = self.ensure_fork_id(id)?;
1791        let idx = self.ensure_fork_index(fork_id)?;
1792
1793        if let Some(active) = self.forks[idx].as_mut() {
1794            // we initialize a _new_ `ForkDB` but keep the state of persistent accounts
1795            let mut new_db = ForkDB::new(backend);
1796            for addr in self.persistent_accounts.iter().copied() {
1797                merge_db_account_data(addr, &active.db, &mut new_db);
1798            }
1799            active.db = new_db;
1800        }
1801        // update mappings
1802        self.issued_local_fork_ids.insert(id, new_fork_id.clone());
1803        self.created_forks.insert(new_fork_id, idx);
1804        Ok(idx)
1805    }
1806
1807    /// Inserts a _new_ `ForkDB` and issues a new local fork identifier
1808    ///
1809    /// Also returns the index where the `ForDB` is stored
1810    pub fn insert_new_fork(
1811        &mut self,
1812        fork_id: ForkId,
1813        db: ForkDB,
1814        journaled_state: JournaledState,
1815    ) -> (LocalForkId, ForkLookupIndex) {
1816        let idx = self.forks.len();
1817        self.created_forks.insert(fork_id.clone(), idx);
1818        let id = self.next_id();
1819        self.issued_local_fork_ids.insert(id, fork_id);
1820        let fork = Fork { db, journaled_state };
1821        self.forks.push(Some(fork));
1822        (id, idx)
1823    }
1824
1825    fn next_id(&mut self) -> U256 {
1826        let id = self.next_fork_id;
1827        self.next_fork_id += U256::from(1);
1828        id
1829    }
1830
1831    /// Returns the number of issued ids
1832    pub fn len(&self) -> usize {
1833        self.issued_local_fork_ids.len()
1834    }
1835
1836    /// Returns true if no forks are issued
1837    pub fn is_empty(&self) -> bool {
1838        self.issued_local_fork_ids.is_empty()
1839    }
1840
1841    pub fn precompiles(&self) -> &'static Precompiles {
1842        Precompiles::new(PrecompileSpecId::from_spec_id(self.spec_id))
1843    }
1844
1845    /// Returns a new, empty, `JournaledState` with set precompiles
1846    pub fn new_journaled_state(&self) -> JournaledState {
1847        let mut journal = {
1848            let mut journal_inner = JournalInner::new();
1849            journal_inner.set_spec_id(self.spec_id);
1850            journal_inner
1851        };
1852        journal
1853            .warm_addresses
1854            .set_precompile_addresses(self.precompiles().addresses().copied().collect());
1855        journal
1856    }
1857}
1858
1859impl Default for BackendInner {
1860    fn default() -> Self {
1861        Self {
1862            launched_with_fork: None,
1863            issued_local_fork_ids: Default::default(),
1864            created_forks: Default::default(),
1865            forks: vec![],
1866            state_snapshots: Default::default(),
1867            has_state_snapshot_failure: false,
1868            caller: None,
1869            next_fork_id: Default::default(),
1870            persistent_accounts: Default::default(),
1871            spec_id: SpecId::default(),
1872            // grant the cheatcode,default test and caller address access to execute cheatcodes
1873            // itself
1874            cheatcode_access_accounts: HashSet::from([
1875                CHEATCODE_ADDRESS,
1876                TEST_CONTRACT_ADDRESS,
1877                CALLER,
1878            ]),
1879        }
1880    }
1881}
1882
1883/// This updates the currently used env with the fork's environment
1884pub(crate) fn update_current_env_with_fork_env<
1885    SPEC,
1886    BLOCK: FoundryBlock,
1887    TX: FoundryTransaction,
1888>(
1889    evm_env: &mut EvmEnv<SPEC, BLOCK>,
1890    tx_env: &mut TX,
1891    fork_evm_env: EvmEnv<SPEC, BLOCK>,
1892) {
1893    tx_env.set_chain_id(Some(fork_evm_env.cfg_env.chain_id));
1894    *evm_env = fork_evm_env;
1895}
1896
1897/// Clones the data of the given `accounts` from the `active` database into the `fork_db`
1898/// This includes the data held in storage (`CacheDB`) and kept in the `JournaledState`.
1899pub(crate) fn merge_account_data<ExtDB: DatabaseRef>(
1900    accounts: impl IntoIterator<Item = Address>,
1901    active: &CacheDB<ExtDB>,
1902    active_journaled_state: &mut JournaledState,
1903    target_fork: &mut Fork,
1904) {
1905    for addr in accounts.into_iter() {
1906        merge_db_account_data(addr, active, &mut target_fork.db);
1907        merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state);
1908    }
1909
1910    *active_journaled_state = target_fork.journaled_state.clone();
1911}
1912
1913/// Clones the account data from the `active_journaled_state`  into the `fork_journaled_state`
1914fn merge_journaled_state_data(
1915    addr: Address,
1916    active_journaled_state: &JournaledState,
1917    fork_journaled_state: &mut JournaledState,
1918) {
1919    if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() {
1920        trace!(?addr, "updating journaled_state account data");
1921        if let Some(fork_account) = fork_journaled_state.state.get_mut(&addr) {
1922            // This will merge the fork's tracked storage with active storage and update values
1923            fork_account.storage.extend(std::mem::take(&mut acc.storage));
1924            // swap them so we can insert the account as whole in the next step
1925            std::mem::swap(&mut fork_account.storage, &mut acc.storage);
1926        }
1927        fork_journaled_state.state.insert(addr, acc);
1928    }
1929}
1930
1931/// Clones the account data from the `active` db into the `ForkDB`
1932fn merge_db_account_data<ExtDB: DatabaseRef>(
1933    addr: Address,
1934    active: &CacheDB<ExtDB>,
1935    fork_db: &mut ForkDB,
1936) {
1937    trace!(?addr, "merging database data");
1938
1939    let Some(acc) = active.cache.accounts.get(&addr) else { return };
1940
1941    // port contract cache over
1942    if let Some(code) = active.cache.contracts.get(&acc.info.code_hash) {
1943        trace!("merging contract cache");
1944        fork_db.cache.contracts.insert(acc.info.code_hash, code.clone());
1945    }
1946
1947    // port account storage over
1948    use std::collections::hash_map::Entry;
1949    match fork_db.cache.accounts.entry(addr) {
1950        Entry::Vacant(vacant) => {
1951            trace!("target account not present - inserting from active");
1952            // if the fork_db doesn't have the target account
1953            // insert the entire thing
1954            vacant.insert(acc.clone());
1955        }
1956        Entry::Occupied(mut occupied) => {
1957            trace!("target account present - merging storage slots");
1958            // if the fork_db does have the system,
1959            // extend the existing storage (overriding)
1960            let fork_account = occupied.get_mut();
1961            fork_account.storage.extend(&acc.storage);
1962        }
1963    }
1964}
1965
1966/// Returns true of the address is a contract
1967fn is_contract_in_state(evm_state: &EvmState, acc: Address) -> bool {
1968    evm_state.get(&acc).map(|acc| acc.info.code_hash != KECCAK_EMPTY).unwrap_or_default()
1969}
1970
1971/// Updates the evm env's block with the block's data
1972fn update_env_block<SPEC, BLOCK: FoundryBlock>(
1973    evm_env: &mut EvmEnv<SPEC, BLOCK>,
1974    header: &impl BlockHeader,
1975) {
1976    let block_env = &mut evm_env.block_env;
1977    block_env.set_timestamp(U256::from(header.timestamp()));
1978    block_env.set_beneficiary(header.beneficiary());
1979    block_env.set_difficulty(header.difficulty());
1980    block_env.set_prevrandao(header.mix_hash());
1981    block_env.set_basefee(header.base_fee_per_gas().unwrap_or_default());
1982    block_env.set_gas_limit(header.gas_limit());
1983    block_env.set_number(U256::from(header.number()));
1984
1985    if let Some(excess_blob_gas) = header.excess_blob_gas() {
1986        evm_env.block_env.set_blob_excess_gas_and_price(
1987            excess_blob_gas,
1988            get_blob_base_fee_update_fraction(evm_env.cfg_env.chain_id, header.timestamp()),
1989        );
1990    }
1991}
1992
1993/// Executes the given transaction and commits state changes to the database _and_ the journaled
1994/// state, with an inspector.
1995#[allow(clippy::too_many_arguments)]
1996fn commit_transaction(
1997    tx: &AnyRpcTransaction,
1998    evm_env: &mut EvmEnv,
1999    tx_env: &mut TxEnv,
2000    journaled_state: &mut JournaledState,
2001    fork: &mut Fork,
2002    fork_id: &ForkId,
2003    persistent_accounts: &HashSet<Address>,
2004    inspector: &mut dyn EthInspectorExt,
2005) -> eyre::Result<()> {
2006    if let Some(tx_envelope) = tx.as_envelope() {
2007        *tx_env = TxEnv::from_recovered_tx(tx_envelope, tx.from());
2008    }
2009
2010    let now = Instant::now();
2011    let res = {
2012        let fork = fork.clone();
2013        let journaled_state = journaled_state.clone();
2014        let depth = journaled_state.depth;
2015        let mut db = Backend::new_with_fork(fork_id, fork, journaled_state)?;
2016
2017        let mut evm = crate::evm::new_eth_evm_with_inspector(
2018            &mut db as _,
2019            evm_env.to_owned(),
2020            tx_env.to_owned(),
2021            inspector,
2022        );
2023        // Adjust inner EVM depth to ensure that inspectors receive accurate data.
2024        evm.journaled_state.depth = depth + 1;
2025        evm.transact(tx_env.clone()).wrap_err("backend: failed committing transaction")?
2026    };
2027    trace!(elapsed = ?now.elapsed(), "transacted transaction");
2028
2029    apply_state_changeset(res.state, journaled_state, fork, persistent_accounts)?;
2030    Ok(())
2031}
2032
2033/// Helper method which updates data in the state with the data from the database.
2034/// Does not change state for persistent accounts (for roll fork to transaction and transact).
2035pub fn update_state<DB: Database>(
2036    state: &mut EvmState,
2037    db: &mut DB,
2038    persistent_accounts: Option<&HashSet<Address>>,
2039) -> Result<(), DB::Error> {
2040    for (addr, acc) in state.iter_mut() {
2041        if !persistent_accounts.is_some_and(|accounts| accounts.contains(addr)) {
2042            acc.info = db.basic(*addr)?.unwrap_or_default();
2043            for (key, val) in &mut acc.storage {
2044                val.present_value = db.storage(*addr, *key)?;
2045            }
2046        }
2047    }
2048
2049    Ok(())
2050}
2051
2052/// Applies the changeset of a transaction to the active journaled state and also commits it in the
2053/// forked db
2054fn apply_state_changeset(
2055    state: Map<revm::primitives::Address, Account>,
2056    journaled_state: &mut JournaledState,
2057    fork: &mut Fork,
2058    persistent_accounts: &HashSet<Address>,
2059) -> Result<(), BackendError> {
2060    // commit the state and update the loaded accounts
2061    fork.db.commit(state);
2062
2063    update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2064    update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?;
2065
2066    Ok(())
2067}
2068
2069#[cfg(test)]
2070mod tests {
2071    use crate::{backend::Backend, opts::EvmOpts};
2072    use alloy_primitives::{U256, address};
2073    use alloy_provider::Provider;
2074    use foundry_common::provider::get_http_provider;
2075    use foundry_config::{Config, NamedChain};
2076    use foundry_fork_db::cache::{BlockchainDb, BlockchainDbMeta};
2077    use revm::database::DatabaseRef;
2078
2079    #[tokio::test(flavor = "multi_thread")]
2080    async fn can_read_write_cache() {
2081        let endpoint = &*foundry_test_utils::rpc::next_http_rpc_endpoint();
2082        let provider = get_http_provider(endpoint);
2083
2084        let block_num = provider.get_block_number().await.unwrap();
2085
2086        let mut evm_opts = Config::figment().extract::<EvmOpts>().unwrap();
2087        evm_opts.fork_url = Some(endpoint.to_string());
2088        evm_opts.fork_block_number = Some(block_num);
2089
2090        let (evm_env, _) = evm_opts.env().await.unwrap();
2091
2092        let fork = evm_opts.get_fork(&Config::default(), evm_env.clone()).unwrap();
2093
2094        let backend = Backend::spawn(Some(fork)).unwrap();
2095
2096        // some rng contract from etherscan
2097        let address = address!("0x63091244180ae240c87d1f528f5f269134cb07b3");
2098
2099        let num_slots = 5;
2100        let _account = backend.basic_ref(address);
2101        for idx in 0..num_slots {
2102            let _ = backend.storage_ref(address, U256::from(idx));
2103        }
2104        drop(backend);
2105
2106        let meta = BlockchainDbMeta {
2107            chain: None,
2108            block_env: evm_env.block_env,
2109            hosts: Default::default(),
2110        };
2111
2112        let db = BlockchainDb::new(
2113            meta,
2114            Some(Config::foundry_block_cache_dir(NamedChain::Mainnet, block_num).unwrap()),
2115        );
2116        assert!(db.accounts().read().contains_key(&address));
2117        assert!(db.storage().read().contains_key(&address));
2118        assert_eq!(db.storage().read().get(&address).unwrap().len(), num_slots as usize);
2119    }
2120}