Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: rename FuzzBackendWrapper to CowBackend #7349

Merged
merged 1 commit into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading