foundry_evm_core/backend/
mod.rs

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