foundry_evm_core/backend/
mod.rs

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