Skip to main content

foundry_evm_core/backend/
mod.rs

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