Skip to content

Commit

Permalink
chore: rename FuzzBackendWrapper to CowBackend (#7349)
Browse files Browse the repository at this point in the history
Name what it is not what it's used for, or something like that
  • Loading branch information
DaniPopes authored Mar 8, 2024
1 parent 0ab9e3c commit 2c6955c
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,25 @@ use std::{borrow::Cow, collections::HashMap};
/// function via immutable raw (no state changes) calls.
///
/// **N.B.**: we're assuming cheatcodes that alter the state (like multi fork swapping) are niche.
/// If they executed during fuzzing, it will require a clone of the initial input database. This way
/// we can support these cheatcodes in fuzzing cheaply without adding overhead for fuzz tests that
/// If they executed, it will require a clone of the initial input database.
/// This way we can support these cheatcodes cheaply without adding overhead for tests that
/// don't make use of them. Alternatively each test case would require its own `Backend` clone,
/// which would add significant overhead for large fuzz sets even if the Database is not big after
/// setup.
#[derive(Clone, Debug)]
pub struct FuzzBackendWrapper<'a> {
/// The underlying immutable `Backend`
pub struct CowBackend<'a> {
/// The underlying `Backend`.
///
/// No calls on the `FuzzBackendWrapper` will ever persistently modify the `backend`'s state.
/// No calls on the `CowBackend` will ever persistently modify the `backend`'s state.
pub backend: Cow<'a, Backend>,
/// Keeps track of whether the backed is already initialized
is_initialized: bool,
/// The [SpecId] of the current backend.
spec_id: SpecId,
}

impl<'a> FuzzBackendWrapper<'a> {
impl<'a> CowBackend<'a> {
/// Creates a new `CowBackend` with the given `Backend`.
pub fn new(backend: &'a Backend) -> Self {
Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST }
}
Expand All @@ -75,7 +76,7 @@ impl<'a> FuzzBackendWrapper<'a> {
Ok(res)
}

/// Returns whether there was a snapshot failure in the fuzz backend.
/// Returns whether there was a snapshot failure in the backend.
///
/// This is bubbled up from the underlying Copy-On-Write backend when a revert occurs.
pub fn has_snapshot_failure(&self) -> bool {
Expand Down Expand Up @@ -105,9 +106,8 @@ impl<'a> FuzzBackendWrapper<'a> {
}
}

impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
impl<'a> DatabaseExt for CowBackend<'a> {
fn snapshot(&mut self, journaled_state: &JournaledState, env: &Env) -> U256 {
trace!("fuzz: create snapshot");
self.backend_mut(env).snapshot(journaled_state, env)
}

Expand All @@ -118,7 +118,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
current: &mut Env,
action: RevertSnapshotAction,
) -> Option<JournaledState> {
trace!(?id, "fuzz: revert snapshot");
self.backend_mut(current).revert(id, journaled_state, current, action)
}

Expand All @@ -137,7 +136,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
}

fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {
trace!("fuzz: create fork");
self.backend.to_mut().create_fork(fork)
}

Expand All @@ -146,7 +144,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
fork: CreateFork,
transaction: B256,
) -> eyre::Result<LocalForkId> {
trace!(?transaction, "fuzz: create fork at");
self.backend.to_mut().create_fork_at_transaction(fork, transaction)
}

Expand All @@ -156,7 +153,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
env: &mut Env,
journaled_state: &mut JournaledState,
) -> eyre::Result<()> {
trace!(?id, "fuzz: select fork");
self.backend_mut(env).select_fork(id, env, journaled_state)
}

Expand All @@ -167,7 +163,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
env: &mut Env,
journaled_state: &mut JournaledState,
) -> eyre::Result<()> {
trace!(?id, ?block_number, "fuzz: roll fork");
self.backend_mut(env).roll_fork(id, block_number, env, journaled_state)
}

Expand All @@ -178,7 +173,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
env: &mut Env,
journaled_state: &mut JournaledState,
) -> eyre::Result<()> {
trace!(?id, ?transaction, "fuzz: roll fork to transaction");
self.backend_mut(env).roll_fork_to_transaction(id, transaction, env, journaled_state)
}

Expand All @@ -190,7 +184,6 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
journaled_state: &mut JournaledState,
inspector: &mut I,
) -> eyre::Result<()> {
trace!(?id, ?transaction, "fuzz: execute transaction");
self.backend_mut(env).transact(id, transaction, env, journaled_state, inspector)
}

Expand Down Expand Up @@ -251,7 +244,7 @@ impl<'a> DatabaseExt for FuzzBackendWrapper<'a> {
}
}

impl<'a> DatabaseRef for FuzzBackendWrapper<'a> {
impl<'a> DatabaseRef for CowBackend<'a> {
type Error = DatabaseError;

fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
Expand All @@ -271,7 +264,7 @@ impl<'a> DatabaseRef for FuzzBackendWrapper<'a> {
}
}

impl<'a> Database for FuzzBackendWrapper<'a> {
impl<'a> Database for CowBackend<'a> {
type Error = DatabaseError;

fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
Expand All @@ -291,7 +284,7 @@ impl<'a> Database for FuzzBackendWrapper<'a> {
}
}

impl<'a> DatabaseCommit for FuzzBackendWrapper<'a> {
impl<'a> DatabaseCommit for CowBackend<'a> {
fn commit(&mut self, changes: Map<Address, Account>) {
self.backend.to_mut().commit(changes)
}
Expand Down
4 changes: 2 additions & 2 deletions crates/evm/core/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ pub use diagnostic::RevertDiagnostic;
mod error;
pub use error::{DatabaseError, DatabaseResult};

mod fuzz;
pub use fuzz::FuzzBackendWrapper;
mod cow;
pub use cow::CowBackend;

mod in_memory_db;
pub use in_memory_db::{EmptyDBWrapper, FoundryEvmInMemoryDB, MemDb};
Expand Down
21 changes: 11 additions & 10 deletions crates/evm/evm/src/executors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use alloy_json_abi::Function;
use alloy_primitives::{Address, Bytes, Log, U256};
use foundry_common::{abi::IntoFunction, evm::Breakpoints};
use foundry_evm_core::{
backend::{Backend, DatabaseError, DatabaseExt, DatabaseResult, FuzzBackendWrapper},
backend::{Backend, CowBackend, DatabaseError, DatabaseExt, DatabaseResult},
constants::{
CALLER, CHEATCODE_ADDRESS, DEFAULT_CREATE2_DEPLOYER, DEFAULT_CREATE2_DEPLOYER_CODE,
},
Expand Down Expand Up @@ -309,7 +309,7 @@ impl Executor {
let mut inspector = self.inspector.clone();
// Build VM
let mut env = self.build_test_env(from, TransactTo::Call(to), calldata, value);
let mut db = FuzzBackendWrapper::new(&self.backend);
let mut db = CowBackend::new(&self.backend);
let result = db.inspect(&mut env, &mut inspector)?;

// Persist the snapshot failure recorded on the fuzz backend wrapper.
Expand Down Expand Up @@ -483,15 +483,16 @@ impl Executor {
///
/// ## Background
///
/// Executing and failure checking [Executor::ensure_success] are two steps, for ds-test
/// Executing and failure checking [`Executor::ensure_success`] are two steps, for ds-test
/// legacy reasons failures can be stored in a global variables and needs to be called via a
/// solidity call `failed()(bool)`. For fuzz tests we’re using the
/// `FuzzBackendWrapper` which is a Cow of the executor’s backend which lazily clones the
/// backend when it’s mutated via cheatcodes like `snapshot`. Snapshots make it even
/// more complicated because now we also need to keep track of that global variable when we
/// revert to a snapshot (because it is stored in state). Now, the problem is that
/// the `FuzzBackendWrapper` is dropped after every call, so we need to keep track of the
/// snapshot failure in the [RawCallResult] instead.
/// solidity call `failed()(bool)`.
///
/// For fuzz tests we’re using the `CowBackend` which is a Cow of the executor’s backend which
/// lazily clones the backend when it’s mutated via cheatcodes like `snapshot`. Snapshots
/// make it even more complicated because now we also need to keep track of that global
/// variable when we revert to a snapshot (because it is stored in state). Now, the problem
/// is that the `CowBackend` is dropped after every call, so we need to keep track of the
/// snapshot failure in the [`RawCallResult`] instead.
pub fn is_raw_call_success(
&self,
address: Address,
Expand Down
2 changes: 1 addition & 1 deletion crates/forge/src/multi_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ impl MultiContractRunnerBuilder {
}

if let Some(bytes) = linked_contract.get_deployed_bytecode_bytes() {
known_contracts.insert(id.clone(), (abi.clone(), bytes.to_vec()));
known_contracts.insert(id.clone(), (abi.clone(), bytes.into_owned().into()));
}
}

Expand Down

0 comments on commit 2c6955c

Please sign in to comment.