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