From d92ad5765eeba1cd9657a54e5bec99c98b6a69dc Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Wed, 18 Dec 2024 12:28:58 +0400 Subject: [PATCH] chore: snapshot --- crates/evm/core/src/backend/cow.rs | 52 +++-- crates/evm/core/src/backend/mod.rs | 270 +++++++++++------------- crates/evm/core/src/backend/snapshot.rs | 14 +- crates/evm/core/src/backend/strategy.rs | 155 +++++++++----- 4 files changed, 265 insertions(+), 226 deletions(-) diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 2f7b7bd90..5fbb94362 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -1,6 +1,6 @@ //! A wrapper around `Backend` that is clone-on-write used for fuzzing. -use super::{strategy::BackendStrategyExt, BackendError, ForkInfo}; +use super::{strategy::BackendStrategy, BackendError, ForkInfo}; use crate::{ backend::{ diagnostic::RevertDiagnostic, Backend, DatabaseExt, LocalForkId, RevertStateSnapshotAction, @@ -15,7 +15,7 @@ use foundry_fork_db::DatabaseError; use revm::{ db::DatabaseRef, primitives::{Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, HashMap as Map, SpecId}, - Database, DatabaseCommit, JournaledState, + Database, DatabaseCommit, }; use std::{borrow::Cow, collections::BTreeMap}; @@ -36,24 +36,24 @@ use std::{borrow::Cow, collections::BTreeMap}; /// which would add significant overhead for large fuzz sets even if the Database is not big after /// setup. #[derive(Clone, Debug)] -pub struct CowBackend<'a> { +pub struct CowBackend<'a, S: BackendStrategy> { /// The underlying `Backend`. /// /// No calls on the `CowBackend` will ever persistently modify the `backend`'s state. - pub backend: Cow<'a, Backend>, + pub backend: Cow<'a, Backend>, /// Keeps track of whether the backed is already initialized pub is_initialized: bool, /// The [SpecId] of the current backend. pub spec_id: SpecId, } -impl<'a> CowBackend<'a> { +impl<'a, S: BackendStrategy> CowBackend<'a, S> { /// Creates a new `CowBackend` with the given `Backend`. - pub fn new(backend: &'a Backend) -> Self { + pub fn new(backend: &'a Backend) -> Self { Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST } } - pub fn new_borrowed(backend: &'a Backend) -> Self { + pub fn new_borrowed(backend: &'a Backend) -> Self { Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST } } @@ -67,7 +67,7 @@ impl<'a> CowBackend<'a> { /// Returns a mutable instance of the Backend. /// /// If this is the first time this is called, the backed is cloned and initialized. - fn backend_mut(&mut self, env: &Env) -> &mut Backend { + fn backend_mut(&mut self, env: &Env) -> &mut Backend { if !self.is_initialized { let backend = self.backend.to_mut(); let env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), self.spec_id); @@ -79,7 +79,7 @@ impl<'a> CowBackend<'a> { } /// Returns a mutable instance of the Backend if it is initialized. - fn initialized_backend_mut(&mut self) -> Option<&mut Backend> { + fn initialized_backend_mut(&mut self) -> Option<&mut Backend> { if self.is_initialized { return Some(self.backend.to_mut()) } @@ -87,26 +87,22 @@ impl<'a> CowBackend<'a> { } } -impl DatabaseExt for CowBackend<'_> { +impl DatabaseExt for CowBackend<'_, S> { fn get_fork_info(&mut self, id: LocalForkId) -> eyre::Result { self.backend.to_mut().get_fork_info(id) } - fn get_strategy(&mut self) -> &mut dyn BackendStrategyExt { - self.backend.to_mut().strategy.as_mut() - } - - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256 { + fn snapshot_state(&mut self, journaled_state: &S::JournaledState, env: &Env) -> U256 { self.backend_mut(env).snapshot_state(journaled_state, env) } fn revert_state( &mut self, id: U256, - journaled_state: &JournaledState, + journaled_state: &S::JournaledState, current: &mut Env, action: RevertStateSnapshotAction, - ) -> Option { + ) -> Option { self.backend_mut(current).revert_state(id, journaled_state, current, action) } @@ -140,7 +136,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, id: LocalForkId, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).select_fork(id, env, journaled_state) } @@ -150,7 +146,7 @@ impl DatabaseExt for CowBackend<'_> { id: Option, block_number: u64, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).roll_fork(id, block_number, env, journaled_state) } @@ -160,7 +156,7 @@ impl DatabaseExt for CowBackend<'_> { id: Option, transaction: B256, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { self.backend_mut(env).roll_fork_to_transaction(id, transaction, env, journaled_state) } @@ -170,7 +166,7 @@ impl DatabaseExt for CowBackend<'_> { id: Option, transaction: B256, env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { self.backend_mut(&env).transact(id, transaction, env, journaled_state, inspector) @@ -180,7 +176,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, transaction: &TransactionRequest, env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { self.backend_mut(&env).transact_from_tx(transaction, env, journaled_state, inspector) @@ -205,7 +201,7 @@ impl DatabaseExt for CowBackend<'_> { fn diagnose_revert( &self, callee: Address, - journaled_state: &JournaledState, + journaled_state: &S::JournaledState, ) -> Option { self.backend.diagnose_revert(callee, journaled_state) } @@ -213,7 +209,7 @@ impl DatabaseExt for CowBackend<'_> { fn load_allocs( &mut self, allocs: &BTreeMap, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError> { self.backend_mut(&Env::default()).load_allocs(allocs, journaled_state) } @@ -222,7 +218,7 @@ impl DatabaseExt for CowBackend<'_> { &mut self, source: &GenesisAccount, target: &Address, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError> { self.backend_mut(&Env::default()).clone_account(source, target, journaled_state) } @@ -264,7 +260,7 @@ impl DatabaseExt for CowBackend<'_> { } } -impl DatabaseRef for CowBackend<'_> { +impl DatabaseRef for CowBackend<'_, S> { type Error = DatabaseError; fn basic_ref(&self, address: Address) -> Result, Self::Error> { @@ -284,7 +280,7 @@ impl DatabaseRef for CowBackend<'_> { } } -impl Database for CowBackend<'_> { +impl Database for CowBackend<'_, S> { type Error = DatabaseError; fn basic(&mut self, address: Address) -> Result, Self::Error> { @@ -304,7 +300,7 @@ impl Database for CowBackend<'_> { } } -impl DatabaseCommit for CowBackend<'_> { +impl DatabaseCommit for CowBackend<'_, S> { fn commit(&mut self, changes: Map) { self.backend.to_mut().commit(changes) } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 9c4aba6f9..d5e23fa4e 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -24,13 +24,13 @@ use revm::{ Account, AccountInfo, BlobExcessGasAndPrice, Bytecode, Env, EnvWithHandlerCfg, EvmState, EvmStorageSlot, HashMap as Map, Log, SpecId, KECCAK_EMPTY, }, - Database, DatabaseCommit, JournaledState, + Database, DatabaseCommit, }; use std::{ collections::{BTreeMap, HashSet}, time::Instant, }; -use strategy::{BackendStrategyExt, BackendStrategyForkInfo}; +use strategy::{BackendStrategy, BackendStrategyForkInfo, EvmBackendStrategy, JournaledState as _}; mod diagnostic; pub use diagnostic::RevertDiagnostic; @@ -86,13 +86,15 @@ pub struct ForkInfo { /// An extension trait that allows us to easily extend the `revm::Inspector` capabilities #[auto_impl::auto_impl(&mut)] -pub trait DatabaseExt: Database + DatabaseCommit { +pub trait DatabaseExt: + Database + DatabaseCommit +{ /// Creates a new state snapshot at the current point of execution. /// /// A state snapshot is associated with a new unique id that's created for the snapshot. /// State snapshots can be reverted: [DatabaseExt::revert_state], however, depending on the /// [RevertStateSnapshotAction], it will keep the snapshot alive or delete it. - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256; + fn snapshot_state(&mut self, journaled_state: &S::JournaledState, env: &Env) -> U256; /// Retrieves information about a fork /// @@ -101,9 +103,6 @@ pub trait DatabaseExt: Database + DatabaseCommit { /// and the the fork environment. fn get_fork_info(&mut self, id: LocalForkId) -> eyre::Result; - /// Retrieve the strategy. - fn get_strategy(&mut self) -> &mut dyn BackendStrategyExt; - /// Reverts the snapshot if it exists /// /// Returns `true` if the snapshot was successfully reverted, `false` if no snapshot for that id @@ -119,10 +118,10 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn revert_state( &mut self, id: U256, - journaled_state: &JournaledState, + journaled_state: &S::JournaledState, env: &mut Env, action: RevertStateSnapshotAction, - ) -> Option; + ) -> Option; /// Deletes the state snapshot with the given `id` /// @@ -140,7 +139,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, fork: CreateFork, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result { let id = self.create_fork(fork)?; self.select_fork(id, env, journaled_state)?; @@ -154,7 +153,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, fork: CreateFork, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, transaction: B256, ) -> eyre::Result { let id = self.create_fork_at_transaction(fork, transaction)?; @@ -185,7 +184,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, id: LocalForkId, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()>; /// Updates the fork to given block number. @@ -200,7 +199,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { id: Option, block_number: u64, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()>; /// Updates the fork to given transaction hash @@ -216,7 +215,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { id: Option, transaction: B256, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()>; /// Fetches the given transaction for the fork and executes it, committing the state in the DB @@ -225,7 +224,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { id: Option, transaction: B256, env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()>; @@ -234,7 +233,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, transaction: &TransactionRequest, env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()>; @@ -293,7 +292,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn diagnose_revert( &self, callee: Address, - journaled_state: &JournaledState, + journaled_state: &S::JournaledState, ) -> Option; /// Loads the account allocs from the given `allocs` map into the passed [JournaledState]. @@ -302,7 +301,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn load_allocs( &mut self, allocs: &BTreeMap, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError>; /// Copies bytecode, storage, nonce and balance from the given genesis account to the target @@ -313,7 +312,7 @@ pub trait DatabaseExt: Database + DatabaseCommit { &mut self, source: &GenesisAccount, target: &Address, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError>; /// Returns true if the given account is currently marked as persistent. @@ -402,8 +401,6 @@ pub trait DatabaseExt: Database + DatabaseCommit { fn set_blockhash(&mut self, block_number: U256, block_hash: B256); } -struct _ObjectSafe(dyn DatabaseExt); - /// Provides the underlying `revm::Database` implementation. /// /// A `Backend` can be initialised in two forms: @@ -458,10 +455,7 @@ struct _ObjectSafe(dyn DatabaseExt); /// after reverting the snapshot. #[derive(Debug)] #[must_use] -pub struct Backend { - /// The behavior strategy. - pub strategy: Box, - +pub struct Backend { /// The access point for managing forks forks: MultiFork, // The default in memory db @@ -482,38 +476,40 @@ pub struct Backend { /// /// This will be an empty `JournaledState`, which will be populated with persistent accounts, /// See [`Self::update_fork_db()`]. - fork_init_journaled_state: JournaledState, + fork_init_journaled_state: S::JournaledState, /// The currently active fork database /// /// If this is set, then the Backend is currently in forking mode active_fork_ids: Option<(LocalForkId, ForkLookupIndex)>, /// holds additional Backend data - inner: BackendInner, + inner: BackendInner, /// Keeps track of the fork type fork_url_type: CachedForkType, + /// Strategy used with this backend. + _strategy: std::marker::PhantomData, } -impl Clone for Backend { +impl Clone for Backend { fn clone(&self) -> Self { Self { - strategy: self.strategy.new_cloned_ext(), forks: self.forks.clone(), mem_db: self.mem_db.clone(), fork_init_journaled_state: self.fork_init_journaled_state.clone(), active_fork_ids: self.active_fork_ids, inner: self.inner.clone(), fork_url_type: self.fork_url_type.clone(), + _strategy: self._strategy, } } } -impl Backend { +impl Backend { /// Creates a new Backend with a spawned multi fork thread. /// /// If `fork` is `Some` this will use a `fork` database, otherwise with an in-memory /// database. - pub fn spawn(fork: Option, strategy: Box) -> Self { - Self::new(MultiFork::spawn(), fork, strategy) + pub fn spawn(fork: Option) -> Self { + Self::new(MultiFork::spawn(), fork) } /// Creates a new instance of `Backend` @@ -522,14 +518,10 @@ impl Backend { /// database. /// /// Prefer using [`spawn`](Self::spawn) instead. - pub fn new( - forks: MultiFork, - fork: Option, - strategy: Box, - ) -> Self { + pub fn new(forks: MultiFork, fork: Option) -> Self { trace!(target: "backend", forking_mode=?fork.is_some(), "creating executor backend"); // Note: this will take of registering the `fork` - let inner = BackendInner { + let inner = BackendInner:: { persistent_accounts: HashSet::from(DEFAULT_PERSISTENT_ACCOUNTS), ..Default::default() }; @@ -537,11 +529,11 @@ impl Backend { let mut backend = Self { forks, mem_db: CacheDB::new(Default::default()), - fork_init_journaled_state: inner.new_journaled_state(), + fork_init_journaled_state: S::new_journaled_state(&inner), active_fork_ids: None, inner, fork_url_type: Default::default(), - strategy, + _strategy: Default::default(), }; if let Some(fork) = fork { @@ -566,11 +558,10 @@ impl Backend { /// as active pub(crate) fn new_with_fork( id: &ForkId, - fork: Fork, - journaled_state: JournaledState, - strategy: Box, + fork: Fork, + journaled_state: S::JournaledState, ) -> Self { - let mut backend = Self::spawn(None, strategy); + let mut backend = Self::spawn(None); let fork_ids = backend.inner.insert_new_fork(id.clone(), fork.db, journaled_state); backend.inner.launched_with_fork = Some((id.clone(), fork_ids.0, fork_ids.1)); backend.active_fork_ids = Some(fork_ids); @@ -582,11 +573,11 @@ impl Backend { Self { forks: self.forks.clone(), mem_db: CacheDB::new(Default::default()), - fork_init_journaled_state: self.inner.new_journaled_state(), + fork_init_journaled_state: S::new_journaled_state(&self.inner), active_fork_ids: None, inner: Default::default(), fork_url_type: Default::default(), - strategy: self.strategy.new_cloned_ext(), + _strategy: self._strategy, } } @@ -631,7 +622,7 @@ impl Backend { /// Returns all snapshots created in this backend pub fn state_snapshots( &self, - ) -> &StateSnapshots> { + ) -> &StateSnapshots, S>> { &self.inner.state_snapshots } @@ -704,12 +695,12 @@ impl Backend { } /// Returns the currently active `Fork`, if any - pub fn active_fork(&self) -> Option<&Fork> { + pub fn active_fork(&self) -> Option<&Fork> { self.active_fork_ids.map(|(_, idx)| self.inner.get_fork(idx)) } /// Returns the currently active `Fork`, if any - pub fn active_fork_mut(&mut self) -> Option<&mut Fork> { + pub fn active_fork_mut(&mut self) -> Option<&mut Fork> { self.active_fork_ids.map(|(_, idx)| self.inner.get_fork_mut(idx)) } @@ -742,7 +733,7 @@ impl Backend { } /// Creates a snapshot of the currently active database - pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot { + pub(crate) fn create_db_snapshot(&self) -> BackendDatabaseSnapshot { if let Some((id, idx)) = self.active_fork_ids { let fork = self.inner.get_fork(idx).clone(); let fork_id = self.inner.ensure_fork_id(id).cloned().expect("Exists; qed"); @@ -766,7 +757,7 @@ impl Backend { if idx == active { all_logs.append(&mut logs); } else { - all_logs.extend(f.journaled_state.logs.clone()) + all_logs.extend(f.journaled_state.logs().to_owned()) } }); return all_logs; @@ -795,7 +786,7 @@ impl Backend { /// Sets the initial journaled state to use when initializing forks #[inline] - fn set_init_journaled_state(&mut self, journaled_state: JournaledState) { + fn set_init_journaled_state(&mut self, journaled_state: S::JournaledState) { trace!("recording fork init journaled_state"); self.fork_init_journaled_state = journaled_state; } @@ -812,7 +803,7 @@ impl Backend { fn prepare_init_journal_state(&mut self) -> Result<(), BackendError> { let loaded_accounts = self .fork_init_journaled_state - .state + .evm_state() .iter() .filter(|(addr, _)| !self.is_existing_precompile(addr) && !self.is_persistent(addr)) .map(|(addr, _)| addr) @@ -824,7 +815,7 @@ impl Backend { for loaded_account in loaded_accounts.iter().copied() { trace!(?loaded_account, "replacing account on init"); let init_account = - journaled_state.state.get_mut(&loaded_account).expect("exists; qed"); + journaled_state.evm_state_mut().get_mut(&loaded_account).expect("exists; qed"); // here's an edge case where we need to check if this account has been created, in // which case we don't need to replace it with the account from the fork because the @@ -879,7 +870,7 @@ impl Backend { id: LocalForkId, env: Env, tx_hash: B256, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result>> { trace!(?id, ?tx_hash, "replay until transaction"); @@ -906,7 +897,7 @@ impl Backend { } trace!(tx=?tx.tx_hash(), "committing transaction"); - commit_transaction( + commit_transaction::( &tx.inner, env.clone(), journaled_state, @@ -914,7 +905,6 @@ impl Backend { &fork_id, &persistent_accounts, &mut NoOpInspector, - self.strategy.as_mut(), )?; } @@ -922,7 +912,7 @@ impl Backend { } } -impl DatabaseExt for Backend { +impl DatabaseExt for Backend { fn get_fork_info(&mut self, id: LocalForkId) -> eyre::Result { let fork_id = self.ensure_fork_id(id).cloned()?; let fork_env = self @@ -938,11 +928,7 @@ impl DatabaseExt for Backend { Ok(ForkInfo { fork_type, fork_env }) } - fn get_strategy(&mut self) -> &mut dyn BackendStrategyExt { - self.strategy.as_mut() - } - - fn snapshot_state(&mut self, journaled_state: &JournaledState, env: &Env) -> U256 { + fn snapshot_state(&mut self, journaled_state: &S::JournaledState, env: &Env) -> U256 { trace!("create snapshot"); let id = self.inner.state_snapshots.insert(BackendStateSnapshot::new( self.create_db_snapshot(), @@ -956,10 +942,10 @@ impl DatabaseExt for Backend { fn revert_state( &mut self, id: U256, - current_state: &JournaledState, + current_state: &S::JournaledState, current: &mut Env, action: RevertStateSnapshotAction, - ) -> Option { + ) -> Option { trace!(?id, "revert snapshot"); if let Some(mut snapshot) = self.inner.state_snapshots.remove_at(id) { // Re-insert snapshot to persist it @@ -971,7 +957,7 @@ impl DatabaseExt for Backend { // Check if an error occurred either during or before the snapshot. // DSTest contracts don't have snapshot functionality, so this slot is enough to check // for failure here. - if let Some(account) = current_state.state.get(&CHEATCODE_ADDRESS) { + if let Some(account) = current_state.evm_state().get(&CHEATCODE_ADDRESS) { if let Some(slot) = account.storage.get(&GLOBAL_FAIL_SLOT) { if !slot.present_value.is_zero() { self.set_state_snapshot_failure(true); @@ -991,9 +977,9 @@ impl DatabaseExt for Backend { // another caller, so we need to ensure the caller account is present in the // journaled state and database let caller = current.tx.caller; - journaled_state.state.entry(caller).or_insert_with(|| { + journaled_state.evm_state_mut().entry(caller).or_insert_with(|| { let caller_account = current_state - .state + .evm_state() .get(&caller) .map(|acc| acc.info.clone()) .unwrap_or_default(); @@ -1056,7 +1042,7 @@ impl DatabaseExt for Backend { Some(id), transaction, &mut env, - &mut self.inner.new_journaled_state(), + &mut S::new_journaled_state(&self.inner), )?; Ok(id) } @@ -1067,7 +1053,7 @@ impl DatabaseExt for Backend { &mut self, id: LocalForkId, env: &mut Env, - active_journaled_state: &mut JournaledState, + active_journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { trace!(?id, "select fork"); if self.is_active_fork(id) { @@ -1113,18 +1099,18 @@ impl DatabaseExt for Backend { active.journaled_state = active_journaled_state.clone(); let caller = env.tx.caller; - let caller_account = active.journaled_state.state.get(&env.tx.caller).cloned(); + let caller_account = active.journaled_state.evm_state().get(&env.tx.caller).cloned(); let target_fork = self.inner.get_fork_mut(idx); // depth 0 will be the default value when the fork was created - if target_fork.journaled_state.depth == 0 { + if target_fork.journaled_state.depth() == 0 { // Initialize caller with its fork info if let Some(mut acc) = caller_account { let fork_account = Database::basic(&mut target_fork.db, caller)? .ok_or(BackendError::MissingAccount(caller))?; acc.info = fork_account; - target_fork.journaled_state.state.insert(caller, acc); + target_fork.journaled_state.evm_state_mut().insert(caller, acc); } } } else { @@ -1138,7 +1124,7 @@ impl DatabaseExt for Backend { self.prepare_init_journal_state()?; // Make sure that the next created fork has a depth of 0. - self.fork_init_journaled_state.depth = 0; + self.fork_init_journaled_state.set_depth(0); } { @@ -1149,15 +1135,15 @@ impl DatabaseExt for Backend { // this is a handover where the target fork starts at the same depth where it was // selected. This ensures that there are no gaps in depth which would // otherwise cause issues with the tracer - fork.journaled_state.depth = active_journaled_state.depth; + fork.journaled_state.set_depth(active_journaled_state.depth()); // another edge case where a fork is created and selected during setup with not // necessarily the same caller as for the test, however we must always // ensure that fork's state contains the current sender let caller = env.tx.caller; - fork.journaled_state.state.entry(caller).or_insert_with(|| { + fork.journaled_state.evm_state_mut().entry(caller).or_insert_with(|| { let caller_account = active_journaled_state - .state + .evm_state() .get(&env.tx.caller) .map(|acc| acc.info.clone()) .unwrap_or_default(); @@ -1169,8 +1155,8 @@ impl DatabaseExt for Backend { caller_account.into() }); - self.strategy.update_fork_db( - BackendStrategyForkInfo { + S::update_fork_db( + BackendStrategyForkInfo:: { active_fork: self.active_fork(), active_type: current_fork_type, target_type: target_fork_type, @@ -1199,14 +1185,14 @@ impl DatabaseExt for Backend { id: Option, block_number: u64, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { trace!(?id, ?block_number, "roll fork"); let id = self.ensure_fork(id)?; let (fork_id, backend, fork_env) = self.forks.roll_fork(self.inner.ensure_fork_id(id).cloned()?, block_number)?; // this will update the local mapping - self.inner.roll_fork(id, fork_id, backend, self.strategy.as_mut())?; + self.inner.roll_fork(id, fork_id, backend)?; if let Some((active_id, active_idx)) = self.active_fork_ids { // the currently active fork is the targeted fork of this call @@ -1226,9 +1212,9 @@ impl DatabaseExt for Backend { let active = self.inner.get_fork_mut(active_idx); active.journaled_state = self.fork_init_journaled_state.clone(); - active.journaled_state.depth = journaled_state.depth; + active.journaled_state.set_depth(journaled_state.depth()); for addr in persistent_addrs { - self.strategy.merge_journaled_state_data( + S::merge_journaled_state_data( addr, journaled_state, &mut active.journaled_state, @@ -1242,10 +1228,10 @@ impl DatabaseExt for Backend { // Special case for accounts that are not created: we don't merge their state but // load it in order to reflect their state at the new block (they should explicitly // be marked as persistent if it is desired to keep state between fork rolls). - for (addr, acc) in journaled_state.state.iter() { + for (addr, acc) in journaled_state.evm_state().iter() { if acc.is_created() { if acc.is_touched() { - self.strategy.merge_journaled_state_data( + S::merge_journaled_state_data( *addr, journaled_state, &mut active.journaled_state, @@ -1267,7 +1253,7 @@ impl DatabaseExt for Backend { id: Option, transaction: B256, env: &mut Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> eyre::Result<()> { trace!(?id, ?transaction, "roll fork to transaction"); let id = self.ensure_fork(id)?; @@ -1293,7 +1279,7 @@ impl DatabaseExt for Backend { maybe_id: Option, transaction: B256, mut env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { trace!(?maybe_id, ?transaction, "execute transaction"); @@ -1318,7 +1304,7 @@ impl DatabaseExt for Backend { let env = self.env_with_handler_cfg(env); let fork = self.inner.get_fork_by_id_mut(id)?; - commit_transaction( + commit_transaction::( &tx, env, journaled_state, @@ -1326,7 +1312,6 @@ impl DatabaseExt for Backend { &fork_id, &persistent_accounts, inspector, - self.strategy.as_mut(), ) } @@ -1334,12 +1319,12 @@ impl DatabaseExt for Backend { &mut self, tx: &TransactionRequest, mut env: Env, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, inspector: &mut dyn InspectorExt, ) -> eyre::Result<()> { trace!(?tx, "execute signed transaction"); - self.commit(journaled_state.state.clone()); + self.commit(journaled_state.evm_state().clone()); let res = { configure_tx_req_env(&mut env, tx)?; @@ -1347,12 +1332,12 @@ impl DatabaseExt for Backend { let mut db = self.clone(); let mut evm = new_evm_with_inspector(&mut db, env, inspector); - evm.context.evm.journaled_state.depth = journaled_state.depth + 1; + evm.context.evm.journaled_state.set_depth(journaled_state.depth() + 1); evm.transact()? }; self.commit(res.state); - update_state(&mut journaled_state.state, self, None)?; + update_state(journaled_state.evm_state_mut(), self, None)?; Ok(()) } @@ -1387,7 +1372,7 @@ impl DatabaseExt for Backend { fn diagnose_revert( &self, callee: Address, - journaled_state: &JournaledState, + journaled_state: &S::JournaledState, ) -> Option { let active_id = self.active_fork_id()?; let active_fork = self.active_fork()?; @@ -1398,7 +1383,7 @@ impl DatabaseExt for Backend { return None; } - if !active_fork.is_contract(callee) && !is_contract_in_state(journaled_state, callee) { + if !active_fork.is_contract(callee) && !is_contract_in_state::(journaled_state, callee) { // no contract for `callee` available on current fork, check if available on other forks let mut available_on = Vec::new(); for (id, fork) in self.inner.forks_iter().filter(|(id, _)| *id != active_id) { @@ -1433,7 +1418,7 @@ impl DatabaseExt for Backend { fn load_allocs( &mut self, allocs: &BTreeMap, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError> { // Loop through all of the allocs defined in the map and commit them to the journal. for (addr, acc) in allocs.iter() { @@ -1451,7 +1436,7 @@ impl DatabaseExt for Backend { &mut self, source: &GenesisAccount, target: &Address, - journaled_state: &mut JournaledState, + journaled_state: &mut S::JournaledState, ) -> Result<(), BackendError> { // Fetch the account from the journaled state. Will create a new account if it does // not already exist. @@ -1539,7 +1524,7 @@ impl DatabaseExt for Backend { } } -impl DatabaseRef for Backend { +impl DatabaseRef for Backend { type Error = DatabaseError; fn basic_ref(&self, address: Address) -> Result, Self::Error> { @@ -1575,7 +1560,7 @@ impl DatabaseRef for Backend { } } -impl DatabaseCommit for Backend { +impl DatabaseCommit for Backend { fn commit(&mut self, changes: Map) { if let Some(db) = self.active_fork_db_mut() { db.commit(changes) @@ -1585,7 +1570,7 @@ impl DatabaseCommit for Backend { } } -impl Database for Backend { +impl Database for Backend { type Error = DatabaseError; fn basic(&mut self, address: Address) -> Result, Self::Error> { if let Some(db) = self.active_fork_db_mut() { @@ -1622,21 +1607,21 @@ impl Database for Backend { /// Variants of a [revm::Database] #[derive(Clone, Debug)] -pub enum BackendDatabaseSnapshot { +pub enum BackendDatabaseSnapshot { /// Simple in-memory [revm::Database] InMemory(FoundryEvmInMemoryDB), /// Contains the entire forking mode database - Forked(LocalForkId, ForkId, ForkLookupIndex, Box), + Forked(LocalForkId, ForkId, ForkLookupIndex, Box>), } /// Represents a fork #[derive(Clone, Debug)] -pub struct Fork { +pub struct Fork { pub db: ForkDB, - pub journaled_state: JournaledState, + pub journaled_state: S::JournaledState, } -impl Fork { +impl Fork { /// Returns true if the account is a contract pub fn is_contract(&self, acc: Address) -> bool { if let Ok(Some(acc)) = self.db.basic_ref(acc) { @@ -1644,13 +1629,13 @@ impl Fork { return true; } } - is_contract_in_state(&self.journaled_state, acc) + is_contract_in_state::(&self.journaled_state, acc) } } /// Container type for various Backend related data #[derive(Clone, Debug)] -pub struct BackendInner { +pub struct BackendInner { /// Stores the `ForkId` of the fork the `Backend` launched with from the start. /// /// In other words if [`Backend::spawn()`] was called with a `CreateFork` command, to launch @@ -1673,9 +1658,9 @@ pub struct BackendInner { pub created_forks: HashMap, /// Holds all created fork databases // Note: data is stored in an `Option` so we can remove it without reshuffling - pub forks: Vec>, + pub forks: Vec>>, /// Contains state snapshots made at a certain point - pub state_snapshots: StateSnapshots>, + pub state_snapshots: StateSnapshots, S>>, /// Tracks whether there was a failure in a snapshot that was reverted /// /// The Test contract contains a bool variable that is set to true when an `assert` function @@ -1703,9 +1688,11 @@ pub struct BackendInner { pub spec_id: SpecId, /// All accounts that are allowed to execute cheatcodes pub cheatcode_access_accounts: HashSet
, + + _phantom: std::marker::PhantomData, } -impl BackendInner { +impl BackendInner { pub fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> { self.issued_local_fork_ids .get(&id) @@ -1725,51 +1712,51 @@ impl BackendInner { /// Returns the underlying fork mapped to the index #[track_caller] - fn get_fork(&self, idx: ForkLookupIndex) -> &Fork { + fn get_fork(&self, idx: ForkLookupIndex) -> &Fork { debug_assert!(idx < self.forks.len(), "fork lookup index must exist"); self.forks[idx].as_ref().unwrap() } /// Returns the underlying fork mapped to the index #[track_caller] - fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork { + fn get_fork_mut(&mut self, idx: ForkLookupIndex) -> &mut Fork { debug_assert!(idx < self.forks.len(), "fork lookup index must exist"); self.forks[idx].as_mut().unwrap() } /// Returns the underlying fork corresponding to the id #[track_caller] - fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> { + fn get_fork_by_id_mut(&mut self, id: LocalForkId) -> eyre::Result<&mut Fork> { let idx = self.ensure_fork_index_by_local_id(id)?; Ok(self.get_fork_mut(idx)) } /// Returns the underlying fork corresponding to the id #[track_caller] - fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> { + fn get_fork_by_id(&self, id: LocalForkId) -> eyre::Result<&Fork> { let idx = self.ensure_fork_index_by_local_id(id)?; Ok(self.get_fork(idx)) } /// Removes the fork - fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork { + fn take_fork(&mut self, idx: ForkLookupIndex) -> Fork { debug_assert!(idx < self.forks.len(), "fork lookup index must exist"); self.forks[idx].take().unwrap() } - fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) { + fn set_fork(&mut self, idx: ForkLookupIndex, fork: Fork) { self.forks[idx] = Some(fork) } /// Returns an iterator over Forks - pub fn forks_iter(&self) -> impl Iterator + '_ { + pub fn forks_iter(&self) -> impl Iterator)> + '_ { self.issued_local_fork_ids .iter() .map(|(id, fork_id)| (*id, self.get_fork(self.created_forks[fork_id]))) } /// Returns a mutable iterator over all Forks - pub fn forks_iter_mut(&mut self) -> impl Iterator + '_ { + pub fn forks_iter_mut(&mut self) -> impl Iterator> + '_ { self.forks.iter_mut().filter_map(|f| f.as_mut()) } @@ -1779,7 +1766,7 @@ impl BackendInner { id: LocalForkId, fork_id: ForkId, idx: ForkLookupIndex, - fork: Fork, + fork: Fork, ) { self.created_forks.insert(fork_id.clone(), idx); self.issued_local_fork_ids.insert(id, fork_id); @@ -1792,7 +1779,7 @@ impl BackendInner { id: LocalForkId, fork_id: ForkId, db: ForkDB, - journaled_state: JournaledState, + journaled_state: S::JournaledState, ) -> ForkLookupIndex { let idx = self.forks.len(); self.issued_local_fork_ids.insert(id, fork_id.clone()); @@ -1808,7 +1795,6 @@ impl BackendInner { id: LocalForkId, new_fork_id: ForkId, backend: SharedBackend, - strategy: &mut dyn BackendStrategyExt, ) -> eyre::Result { let fork_id = self.ensure_fork_id(id)?; let idx = self.ensure_fork_index(fork_id)?; @@ -1817,7 +1803,7 @@ impl BackendInner { // we initialize a _new_ `ForkDB` but keep the state of persistent accounts let mut new_db = ForkDB::new(backend); for addr in self.persistent_accounts.iter().copied() { - strategy.merge_db_account_data(addr, &active.db, &mut new_db); + S::merge_db_account_data(addr, &active.db, &mut new_db); } active.db = new_db; } @@ -1834,7 +1820,7 @@ impl BackendInner { &mut self, fork_id: ForkId, db: ForkDB, - journaled_state: JournaledState, + journaled_state: S::JournaledState, ) -> (LocalForkId, ForkLookupIndex) { let idx = self.forks.len(); self.created_forks.insert(fork_id.clone(), idx); @@ -1866,12 +1852,12 @@ impl BackendInner { } /// Returns a new, empty, `JournaledState` with set precompiles - pub fn new_journaled_state(&self) -> JournaledState { - JournaledState::new(self.spec_id, self.precompiles().addresses().copied().collect()) + pub fn new_journaled_state(&self) -> S::JournaledState { + S::new_journaled_state(self) } } -impl Default for BackendInner { +impl Default for BackendInner { fn default() -> Self { Self { launched_with_fork: None, @@ -1892,6 +1878,7 @@ impl Default for BackendInner { TEST_CONTRACT_ADDRESS, CALLER, ]), + _phantom: Default::default(), } } } @@ -1904,9 +1891,12 @@ pub(crate) fn update_current_env_with_fork_env(current: &mut Env, fork: Env) { } /// Returns true of the address is a contract -fn is_contract_in_state(journaled_state: &JournaledState, acc: Address) -> bool { +fn is_contract_in_state( + journaled_state: &S::JournaledState, + acc: Address, +) -> bool { journaled_state - .state + .evm_state() .get(&acc) .map(|acc| acc.info.code_hash != KECCAK_EMPTY) .unwrap_or_default() @@ -1929,15 +1919,14 @@ fn update_env_block(env: &mut Env, block: &AnyRpcBlock) { /// Executes the given transaction and commits state changes to the database _and_ the journaled /// state, with an inspector. #[allow(clippy::too_many_arguments)] -fn commit_transaction( +fn commit_transaction( tx: &Transaction, mut env: EnvWithHandlerCfg, - journaled_state: &mut JournaledState, - fork: &mut Fork, + journaled_state: &mut S::JournaledState, + fork: &mut Fork, fork_id: &ForkId, persistent_accounts: &HashSet
, inspector: &mut dyn InspectorExt, - strategy: &mut dyn BackendStrategyExt, ) -> eyre::Result<()> { // TODO: Remove after https://github.com/foundry-rs/foundry/pull/9131 // if the tx has the blob_versioned_hashes field, we assume it's a Cancun block @@ -1951,9 +1940,8 @@ fn commit_transaction( let res = { let fork = fork.clone(); let journaled_state = journaled_state.clone(); - let depth = journaled_state.depth; - let mut db = - Backend::new_with_fork(fork_id, fork, journaled_state, strategy.new_cloned_ext()); + let depth = journaled_state.depth(); + let mut db = Backend::::new_with_fork(fork_id, fork, journaled_state); let mut evm = crate::utils::new_evm_with_inspector(&mut db as _, env, inspector); // Adjust inner EVM depth to ensure that inspectors receive accurate data. @@ -1987,17 +1975,17 @@ pub fn update_state( /// Applies the changeset of a transaction to the active journaled state and also commits it in the /// forked db -fn apply_state_changeset( +fn apply_state_changeset( state: Map, - journaled_state: &mut JournaledState, - fork: &mut Fork, + journaled_state: &mut S::JournaledState, + fork: &mut Fork, persistent_accounts: &HashSet
, ) -> Result<(), BackendError> { // commit the state and update the loaded accounts fork.db.commit(state); - update_state(&mut journaled_state.state, &mut fork.db, Some(persistent_accounts))?; - update_state(&mut fork.journaled_state.state, &mut fork.db, Some(persistent_accounts))?; + update_state(journaled_state.evm_state_mut(), &mut fork.db, Some(persistent_accounts))?; + update_state(fork.journaled_state.evm_state_mut(), &mut fork.db, Some(persistent_accounts))?; Ok(()) } @@ -2040,7 +2028,7 @@ mod tests { evm_opts, }; - let backend = Backend::spawn(Some(fork), Box::new(EvmBackendStrategy)); + let backend = Backend::::spawn(Some(fork)); // some rng contract from etherscan let address: Address = "63091244180ae240c87d1f528f5f269134cb07b3".parse().unwrap(); diff --git a/crates/evm/core/src/backend/snapshot.rs b/crates/evm/core/src/backend/snapshot.rs index 36c4657c2..ed4a0a9a5 100644 --- a/crates/evm/core/src/backend/snapshot.rs +++ b/crates/evm/core/src/backend/snapshot.rs @@ -5,6 +5,8 @@ use revm::{ }; use serde::{Deserialize, Serialize}; +use super::strategy::{BackendStrategy, EvmBackendStrategy, JournaledState as _}; + /// A minimal abstraction of a state at a certain point in time #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct StateSnapshot { @@ -15,17 +17,17 @@ pub struct StateSnapshot { /// Represents a state snapshot taken during evm execution #[derive(Clone, Debug)] -pub struct BackendStateSnapshot { +pub struct BackendStateSnapshot { pub db: T, /// The journaled_state state at a specific point - pub journaled_state: JournaledState, + pub journaled_state: S::JournaledState, /// Contains the env at the time of the snapshot pub env: Env, } -impl BackendStateSnapshot { +impl BackendStateSnapshot { /// Takes a new state snapshot. - pub fn new(db: T, journaled_state: JournaledState, env: Env) -> Self { + pub fn new(db: T, journaled_state: S::JournaledState, env: Env) -> Self { Self { db, journaled_state, env } } @@ -36,8 +38,8 @@ impl BackendStateSnapshot { /// those logs that are missing in the snapshot's journaled_state, since the current /// journaled_state includes the same logs, we can simply replace use that See also /// `DatabaseExt::revert`. - pub fn merge(&mut self, current: &JournaledState) { - self.journaled_state.logs.clone_from(¤t.logs); + pub fn merge(&mut self, current: &S::JournaledState) { + *self.journaled_state.logs_mut() = current.logs().to_vec(); } } diff --git a/crates/evm/core/src/backend/strategy.rs b/crates/evm/core/src/backend/strategy.rs index 1776c03a9..2352d36c2 100644 --- a/crates/evm/core/src/backend/strategy.rs +++ b/crates/evm/core/src/backend/strategy.rs @@ -1,47 +1,110 @@ -use std::{ - fmt::Debug, - sync::{Arc, Mutex}, -}; +use std::fmt::Debug; use super::{BackendInner, Fork, ForkDB, ForkType, FoundryEvmInMemoryDB}; -use alloy_primitives::{Address, U256}; -use revm::{db::CacheDB, primitives::HashSet, DatabaseRef, JournaledState}; -use serde::{Deserialize, Serialize}; +use alloy_primitives::{Address, Log, U256}; +use revm::{ + db::CacheDB, + primitives::{EvmState, HashSet}, + DatabaseRef, +}; + +/// A backend-agnostic trait that defines the behavior of a journaled state. +pub trait JournaledState: Sized + Clone + Debug { + // TODO: Probably should be VM-agnostic as well, e.g. we should not expose the state + // directly, but rather a set of methods to interact with it. + fn evm_state(&self) -> &EvmState; + fn evm_state_mut(&mut self) -> &mut EvmState; + + fn logs(&self) -> &[Log]; + fn logs_mut(&mut self) -> &mut Vec; + + fn depth(&self) -> usize; + fn set_depth(&mut self, depth: usize); + + fn load_account( + &mut self, + address: Address, + db: &mut DB, + ) -> Result< + revm::interpreter::StateLoad<&mut revm::primitives::Account>, + revm::primitives::EVMError, + >; + + fn touch(&mut self, address: &Address); +} + +impl JournaledState for revm::JournaledState { + fn evm_state(&self) -> &EvmState { + &self.state + } + + fn evm_state_mut(&mut self) -> &mut EvmState { + &mut self.state + } + + fn logs(&self) -> &[Log] { + &self.logs + } + + fn logs_mut(&mut self) -> &mut Vec { + &mut self.logs + } + + fn depth(&self) -> usize { + self.depth + } -pub struct BackendStrategyForkInfo<'a> { - pub active_fork: Option<&'a Fork>, + fn set_depth(&mut self, depth: usize) { + self.depth = depth; + } + + fn load_account( + &mut self, + address: Address, + db: &mut DB, + ) -> Result< + revm::interpreter::StateLoad<&mut revm::primitives::Account>, + revm::primitives::EVMError, + > { + self.load_account(address, db) + } + + fn touch(&mut self, address: &Address) { + self.touch(address) + } +} + +pub struct BackendStrategyForkInfo<'a, S: BackendStrategy> { + pub active_fork: Option<&'a Fork>, pub active_type: ForkType, pub target_type: ForkType, } -pub trait BackendStrategy: Debug + Send + Sync { - fn name(&self) -> &'static str; - - fn new_cloned(&self) -> Arc>; +pub trait BackendStrategy: Debug + Send + Sync + Clone + Copy { + type JournaledState: JournaledState; /// When creating or switching forks, we update the AccountInfo of the contract fn update_fork_db( - &self, - fork_info: BackendStrategyForkInfo<'_>, + fork_info: BackendStrategyForkInfo<'_, Self>, mem_db: &FoundryEvmInMemoryDB, - backend_inner: &BackendInner, - active_journaled_state: &mut JournaledState, - target_fork: &mut Fork, + backend_inner: &BackendInner, + active_journaled_state: &mut Self::JournaledState, + target_fork: &mut Fork, ); /// Clones the account data from the `active_journaled_state` into the `fork_journaled_state` fn merge_journaled_state_data( - &self, addr: Address, - active_journaled_state: &JournaledState, - fork_journaled_state: &mut JournaledState, + active_journaled_state: &Self::JournaledState, + fork_journaled_state: &mut Self::JournaledState, ); - fn merge_db_account_data(&self, addr: Address, active: &ForkDB, fork_db: &mut ForkDB); + fn merge_db_account_data(addr: Address, active: &ForkDB, fork_db: &mut ForkDB); + + fn new_journaled_state(backend_inner: &BackendInner) -> Self::JournaledState; } pub trait BackendStrategyExt: BackendStrategy { - fn new_cloned_ext(&self) -> Box; /// Saves the storage keys for immutable variables per address. /// /// These are required during fork to help merge the persisted addresses, as they are stored @@ -51,29 +114,20 @@ pub trait BackendStrategyExt: BackendStrategy { fn zksync_save_immutable_storage(&mut self, _addr: Address, _keys: HashSet) {} } -struct _ObjectSafe(dyn BackendStrategy); - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Copy)] pub struct EvmBackendStrategy; impl BackendStrategy for EvmBackendStrategy { - fn name(&self) -> &'static str { - "evm" - } - - fn new_cloned(&self) -> Arc> { - Arc::new(Mutex::new(self.clone())) - } + type JournaledState = revm::JournaledState; fn update_fork_db( - &self, - fork_info: BackendStrategyForkInfo<'_>, + fork_info: BackendStrategyForkInfo<'_, Self>, mem_db: &FoundryEvmInMemoryDB, backend_inner: &BackendInner, - active_journaled_state: &mut JournaledState, + active_journaled_state: &mut Self::JournaledState, target_fork: &mut Fork, ) { - self.update_fork_db_contracts( + Self::update_fork_db_contracts( fork_info, mem_db, backend_inner, @@ -83,10 +137,9 @@ impl BackendStrategy for EvmBackendStrategy { } fn merge_journaled_state_data( - &self, addr: Address, - active_journaled_state: &JournaledState, - fork_journaled_state: &mut JournaledState, + active_journaled_state: &Self::JournaledState, + fork_journaled_state: &mut Self::JournaledState, ) { EvmBackendMergeStrategy::merge_journaled_state_data( addr, @@ -95,25 +148,25 @@ impl BackendStrategy for EvmBackendStrategy { ); } - fn merge_db_account_data(&self, addr: Address, active: &ForkDB, fork_db: &mut ForkDB) { + fn merge_db_account_data(addr: Address, active: &ForkDB, fork_db: &mut ForkDB) { EvmBackendMergeStrategy::merge_db_account_data(addr, active, fork_db); } -} -impl BackendStrategyExt for EvmBackendStrategy { - fn new_cloned_ext(&self) -> Box { - Box::new(self.clone()) + fn new_journaled_state(backend_inner: &BackendInner) -> Self::JournaledState { + revm::JournaledState::new( + backend_inner.spec_id, + backend_inner.precompiles().addresses().copied().collect(), + ) } } impl EvmBackendStrategy { /// Merges the state of all `accounts` from the currently active db into the given `fork` pub(crate) fn update_fork_db_contracts( - &self, - fork_info: BackendStrategyForkInfo<'_>, + fork_info: BackendStrategyForkInfo<'_, Self>, mem_db: &FoundryEvmInMemoryDB, backend_inner: &BackendInner, - active_journaled_state: &mut JournaledState, + active_journaled_state: &mut revm::JournaledState, target_fork: &mut Fork, ) { let accounts = backend_inner.persistent_accounts.iter().copied(); @@ -141,7 +194,7 @@ impl EvmBackendMergeStrategy { pub fn merge_account_data( accounts: impl IntoIterator, active: &CacheDB, - active_journaled_state: &mut JournaledState, + active_journaled_state: &mut revm::JournaledState, target_fork: &mut Fork, ) { for addr in accounts.into_iter() { @@ -165,8 +218,8 @@ impl EvmBackendMergeStrategy { /// Clones the account data from the `active_journaled_state` into the `fork_journaled_state` pub fn merge_journaled_state_data( addr: Address, - active_journaled_state: &JournaledState, - fork_journaled_state: &mut JournaledState, + active_journaled_state: &revm::JournaledState, + fork_journaled_state: &mut revm::JournaledState, ) { if let Some(mut acc) = active_journaled_state.state.get(&addr).cloned() { trace!(?addr, "updating journaled_state account data");