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

feat: gas snapshots over arbitrary sections #8952

Merged
merged 56 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
4ef2ac6
update internal naming
zerosnacks Sep 24, 2024
d90a09e
further internals
zerosnacks Sep 24, 2024
3d326d2
deprecate cheats
zerosnacks Sep 24, 2024
72b4e15
update Solidity tests and add dedicated test for testing deprecated c…
zerosnacks Sep 24, 2024
7fed284
clarify gas snapshots
zerosnacks Sep 24, 2024
d544326
fix build
zerosnacks Sep 24, 2024
8492c71
final fixes
zerosnacks Sep 24, 2024
a8f2ec5
fix build
zerosnacks Sep 24, 2024
2cca2c7
fix repro 6355 rename
zerosnacks Sep 24, 2024
9602aec
add gas snapshot setup from #8755
zerosnacks Sep 24, 2024
1ced509
fix build + clippy warnings
zerosnacks Sep 24, 2024
9348062
fix cheatcodes
zerosnacks Sep 24, 2024
094a4bb
account for fixed CREATE / CALL gas cost
zerosnacks Sep 24, 2024
e9bd560
remove import
zerosnacks Sep 24, 2024
836a400
add stipend
zerosnacks Sep 24, 2024
45ae718
Merge branch 'master' into zerosnacks/add-gas-section-snapshot-cheatc…
zerosnacks Sep 25, 2024
1ebd5c3
recalculate after a - b setup
zerosnacks Sep 25, 2024
9f8ea19
clear call_stipend, update tests
zerosnacks Sep 25, 2024
fd97339
Merge branch 'master' into zerosnacks/rename-state-snapshot
zerosnacks Sep 25, 2024
4114b07
Merge branch 'zerosnacks/rename-state-snapshot' into zerosnacks/add-g…
zerosnacks Sep 25, 2024
55d43f4
avoid double counting external calls
zerosnacks Sep 25, 2024
eb3f0ae
Merge branch 'zerosnacks/add-gas-section-snapshot-cheatcodes' of gith…
zerosnacks Sep 25, 2024
fe9822f
update cheatcodes, remove debug prints
zerosnacks Sep 25, 2024
1b2439c
enable assertions
zerosnacks Sep 25, 2024
aaee5d4
clean up tests
zerosnacks Sep 25, 2024
1bb65a7
clean up test names
zerosnacks Sep 25, 2024
040a2bf
Merge branch 'master' into zerosnacks/add-gas-section-snapshot-cheatc…
zerosnacks Sep 25, 2024
162ab95
remove snapshot directory on `forge clean`
zerosnacks Sep 25, 2024
50b8e54
Merge branch 'master' into zerosnacks/rename-state-snapshot
zerosnacks Sep 25, 2024
b78bd56
do not remove all snapshots by default due to multiple test suites be…
zerosnacks Sep 25, 2024
dd7c457
Merge branch 'zerosnacks/rename-state-snapshot' into zerosnacks/add-g…
zerosnacks Sep 25, 2024
7ae5dee
handle edge case where we ask to compare but file does not exist, rem…
zerosnacks Sep 25, 2024
54ea324
Merge branch 'zerosnacks/add-gas-section-snapshot-cheatcodes' of gith…
zerosnacks Sep 25, 2024
41800da
fix path issue when attempting removal
zerosnacks Sep 25, 2024
6408bb1
Update crates/cheatcodes/src/evm.rs
zerosnacks Sep 26, 2024
6c05e09
Update crates/cheatcodes/src/inspector.rs
zerosnacks Sep 26, 2024
fcd43e4
refactor, apply recommended changes for last_snapshot_group, last_sna…
zerosnacks Sep 26, 2024
c6b19b3
remove gas snapshots from fuzz tests for now: this is largely due to …
zerosnacks Sep 26, 2024
bca712f
fix clippy
zerosnacks Sep 26, 2024
d040ea7
Merge branch 'master' into zerosnacks/rename-state-snapshot-bu
zerosnacks Sep 26, 2024
6e0d85f
Merge branch 'zerosnacks/rename-state-snapshot-bu' into zerosnacks/ad…
zerosnacks Sep 26, 2024
23fdf66
avoid setting to 0 unnecessarily
zerosnacks Sep 26, 2024
86060d3
use if let Some
zerosnacks Sep 26, 2024
92384b2
improve comments, clarify use of last_gas_used != 0
zerosnacks Sep 26, 2024
b1e2567
merge in master
zerosnacks Sep 27, 2024
23d4410
Merge branch 'master' into zerosnacks/add-gas-section-snapshot-cheatc…
zerosnacks Sep 30, 2024
f789e3d
fix merge conflict issue
zerosnacks Sep 30, 2024
8f62030
fix arg ordering to address group naming regression
zerosnacks Sep 30, 2024
731cbe3
fix merge conflicts
zerosnacks Sep 30, 2024
d3d1229
fix import
zerosnacks Sep 30, 2024
ab2cded
move snapshot name derivation to helper
zerosnacks Oct 1, 2024
d3310f2
only skip initial call w/ overhead, no special handling for call frames
zerosnacks Oct 1, 2024
73b4f81
add flare test
zerosnacks Oct 1, 2024
b74ae33
style nits + use helper method
zerosnacks Oct 2, 2024
0511d24
Merge branch 'master' into zerosnacks/add-gas-section-snapshot-cheatc…
zerosnacks Oct 2, 2024
e7c9bf9
Merge branch 'master' into zerosnacks/add-gas-section-snapshot-cheatc…
zerosnacks Oct 2, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_STORE
/target
out/
snapshots/
out.json
.idea
.vscode
7 changes: 3 additions & 4 deletions crates/anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1913,7 +1913,6 @@ impl EthApi {
pub async fn anvil_metadata(&self) -> Result<Metadata> {
node_info!("anvil_metadata");
let fork_config = self.backend.get_fork();
let snapshots = self.backend.list_snapshots();

Ok(Metadata {
client_version: CLIENT_VERSION.to_string(),
Expand All @@ -1926,7 +1925,7 @@ impl EthApi {
fork_block_number: cfg.block_number(),
fork_block_hash: cfg.block_hash(),
}),
snapshots,
snapshots: self.backend.list_state_snapshots(),
})
}

Expand Down Expand Up @@ -2059,7 +2058,7 @@ impl EthApi {
/// Handler for RPC call: `evm_snapshot`
pub async fn evm_snapshot(&self) -> Result<U256> {
node_info!("evm_snapshot");
Ok(self.backend.create_snapshot().await)
Ok(self.backend.create_state_snapshot().await)
}

/// Revert the state of the blockchain to a previous snapshot.
Expand All @@ -2068,7 +2067,7 @@ impl EthApi {
/// Handler for RPC call: `evm_revert`
pub async fn evm_revert(&self, id: U256) -> Result<bool> {
node_info!("evm_revert");
self.backend.revert_snapshot(id).await
self.backend.revert_state_snapshot(id).await
}

/// Jump forward in time by the given amount of time, in seconds.
Expand Down
61 changes: 31 additions & 30 deletions crates/anvil/src/eth/backend/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use anvil_core::eth::{
use foundry_common::errors::FsPathError;
use foundry_evm::{
backend::{
BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertSnapshotAction, StateSnapshot,
BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction,
StateSnapshot,
},
revm::{
db::{CacheDB, DatabaseRef, DbAccount},
Expand All @@ -35,19 +36,19 @@ pub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> {
None
}

/// Clear the state and move it into a new `StateSnapshot`
fn clear_into_snapshot(&mut self) -> StateSnapshot;
/// Clear the state and move it into a new `StateSnapshot`.
fn clear_into_state_snapshot(&mut self) -> StateSnapshot;

/// Read the state snapshot
/// Read the state snapshot.
///
/// This clones all the states and returns a new `StateSnapshot`
fn read_as_snapshot(&self) -> StateSnapshot;
/// This clones all the states and returns a new `StateSnapshot`.
fn read_as_state_snapshot(&self) -> StateSnapshot;

/// Clears the entire database
fn clear(&mut self);

/// Reverses `clear_into_snapshot` by initializing the db's state with the snapshot
fn init_from_snapshot(&mut self, snapshot: StateSnapshot);
/// Reverses `clear_into_snapshot` by initializing the db's state with the state snapshot.
fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);
}

impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
Expand All @@ -62,17 +63,17 @@ where
T::maybe_as_full_db(self)
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
unreachable!("never called for DatabaseRef")
}

fn read_as_snapshot(&self) -> StateSnapshot {
fn read_as_state_snapshot(&self) -> StateSnapshot {
unreachable!("never called for DatabaseRef")
}

fn clear(&mut self) {}

fn init_from_snapshot(&mut self, _snapshot: StateSnapshot) {}
fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
}

/// Helper trait to reset the DB if it's forked
Expand Down Expand Up @@ -176,13 +177,13 @@ pub trait Db:
Ok(true)
}

/// Creates a new snapshot
fn snapshot(&mut self) -> U256;
/// Creates a new state snapshot.
fn snapshot_state(&mut self) -> U256;

/// Reverts a snapshot
/// Reverts a state snapshot.
///
/// Returns `true` if the snapshot was reverted
fn revert(&mut self, snapshot: U256, action: RevertSnapshotAction) -> bool;
/// Returns `true` if the state snapshot was reverted.
fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;

/// Returns the state root if possible to compute
fn maybe_state_root(&self) -> Option<B256> {
Expand Down Expand Up @@ -228,11 +229,11 @@ impl<T: DatabaseRef<Error = DatabaseError> + Send + Sync + Clone + fmt::Debug> D
Ok(None)
}

fn snapshot(&mut self) -> U256 {
fn snapshot_state(&mut self) -> U256 {
U256::ZERO
}

fn revert(&mut self, _snapshot: U256, _action: RevertSnapshotAction) -> bool {
fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
false
}

Expand All @@ -250,7 +251,7 @@ impl<T: DatabaseRef<Error = DatabaseError>> MaybeFullDatabase for CacheDB<T> {
Some(&self.accounts)
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
let db_accounts = std::mem::take(&mut self.accounts);
let mut accounts = HashMap::new();
let mut account_storage = HashMap::new();
Expand All @@ -265,7 +266,7 @@ impl<T: DatabaseRef<Error = DatabaseError>> MaybeFullDatabase for CacheDB<T> {
StateSnapshot { accounts, storage: account_storage, block_hashes }
}

fn read_as_snapshot(&self) -> StateSnapshot {
fn read_as_state_snapshot(&self) -> StateSnapshot {
let db_accounts = self.accounts.clone();
let mut accounts = HashMap::new();
let mut account_storage = HashMap::new();
Expand All @@ -282,11 +283,11 @@ impl<T: DatabaseRef<Error = DatabaseError>> MaybeFullDatabase for CacheDB<T> {
}

fn clear(&mut self) {
self.clear_into_snapshot();
self.clear_into_state_snapshot();
}

fn init_from_snapshot(&mut self, snapshot: StateSnapshot) {
let StateSnapshot { accounts, mut storage, block_hashes } = snapshot;
fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;

for (addr, mut acc) in accounts {
if let Some(code) = acc.code.take() {
Expand Down Expand Up @@ -330,7 +331,7 @@ impl StateDb {
pub fn serialize_state(&mut self) -> StateSnapshot {
// Using read_as_snapshot makes sures we don't clear the historical state from the current
// instance.
self.read_as_snapshot()
self.read_as_state_snapshot()
}
}

Expand Down Expand Up @@ -362,20 +363,20 @@ impl MaybeFullDatabase for StateDb {
self.0.maybe_as_full_db()
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
self.0.clear_into_snapshot()
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
self.0.clear_into_state_snapshot()
}

fn read_as_snapshot(&self) -> StateSnapshot {
self.0.read_as_snapshot()
fn read_as_state_snapshot(&self) -> StateSnapshot {
self.0.read_as_state_snapshot()
}

fn clear(&mut self) {
self.0.clear()
}

fn init_from_snapshot(&mut self, snapshot: StateSnapshot) {
self.0.init_from_snapshot(snapshot)
fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
self.0.init_from_state_snapshot(state_snapshot)
}
}

Expand Down
42 changes: 22 additions & 20 deletions crates/anvil/src/eth/backend/mem/fork_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use crate::{
use alloy_primitives::{Address, B256, U256, U64};
use alloy_rpc_types::BlockId;
use foundry_evm::{
backend::{BlockchainDb, DatabaseError, DatabaseResult, RevertSnapshotAction, StateSnapshot},
fork::database::ForkDbSnapshot,
backend::{
BlockchainDb, DatabaseError, DatabaseResult, RevertStateSnapshotAction, StateSnapshot,
},
fork::database::ForkDbStateSnapshot,
revm::{primitives::BlockEnv, Database},
};
use revm::DatabaseRef;
Expand Down Expand Up @@ -72,16 +74,16 @@ impl Db for ForkedDatabase {
}))
}

fn snapshot(&mut self) -> U256 {
self.insert_snapshot()
fn snapshot_state(&mut self) -> U256 {
self.insert_state_snapshot()
}

fn revert(&mut self, id: U256, action: RevertSnapshotAction) -> bool {
self.revert_snapshot(id, action)
fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {
self.revert_state_snapshot(id, action)
}

fn current_state(&self) -> StateDb {
StateDb::new(self.create_snapshot())
StateDb::new(self.create_state_snapshot())
}
}

Expand All @@ -90,15 +92,15 @@ impl MaybeFullDatabase for ForkedDatabase {
self
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
let db = self.inner().db();
let accounts = std::mem::take(&mut *db.accounts.write());
let storage = std::mem::take(&mut *db.storage.write());
let block_hashes = std::mem::take(&mut *db.block_hashes.write());
StateSnapshot { accounts, storage, block_hashes }
}

fn read_as_snapshot(&self) -> StateSnapshot {
fn read_as_state_snapshot(&self) -> StateSnapshot {
let db = self.inner().db();
let accounts = db.accounts.read().clone();
let storage = db.storage.read().clone();
Expand All @@ -108,38 +110,38 @@ impl MaybeFullDatabase for ForkedDatabase {

fn clear(&mut self) {
self.flush_cache();
self.clear_into_snapshot();
self.clear_into_state_snapshot();
}

fn init_from_snapshot(&mut self, snapshot: StateSnapshot) {
fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
let db = self.inner().db();
let StateSnapshot { accounts, storage, block_hashes } = snapshot;
let StateSnapshot { accounts, storage, block_hashes } = state_snapshot;
*db.accounts.write() = accounts;
*db.storage.write() = storage;
*db.block_hashes.write() = block_hashes;
}
}

impl MaybeFullDatabase for ForkDbSnapshot {
impl MaybeFullDatabase for ForkDbStateSnapshot {
fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
self
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
std::mem::take(&mut self.snapshot)
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
std::mem::take(&mut self.state_snapshot)
}

fn read_as_snapshot(&self) -> StateSnapshot {
self.snapshot.clone()
fn read_as_state_snapshot(&self) -> StateSnapshot {
self.state_snapshot.clone()
}

fn clear(&mut self) {
std::mem::take(&mut self.snapshot);
std::mem::take(&mut self.state_snapshot);
self.local.clear()
}

fn init_from_snapshot(&mut self, snapshot: StateSnapshot) {
self.snapshot = snapshot;
fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
self.state_snapshot = state_snapshot;
}
}

Expand Down
32 changes: 16 additions & 16 deletions crates/anvil/src/eth/backend/mem/in_memory_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use foundry_evm::{

// reexport for convenience
pub use foundry_evm::{backend::MemDb, revm::db::DatabaseRef};
use foundry_evm::{backend::RevertSnapshotAction, revm::primitives::BlockEnv};
use foundry_evm::{backend::RevertStateSnapshotAction, revm::primitives::BlockEnv};

impl Db for MemDb {
fn insert_account(&mut self, address: Address, account: AccountInfo) {
Expand Down Expand Up @@ -74,22 +74,22 @@ impl Db for MemDb {
}

/// Creates a new snapshot
fn snapshot(&mut self) -> U256 {
let id = self.snapshots.insert(self.inner.clone());
trace!(target: "backend::memdb", "Created new snapshot {}", id);
fn snapshot_state(&mut self) -> U256 {
let id = self.state_snapshots.insert(self.inner.clone());
trace!(target: "backend::memdb", "Created new state snapshot {}", id);
id
}

fn revert(&mut self, id: U256, action: RevertSnapshotAction) -> bool {
if let Some(snapshot) = self.snapshots.remove(id) {
fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {
if let Some(state_snapshot) = self.state_snapshots.remove(id) {
if action.is_keep() {
self.snapshots.insert_at(snapshot.clone(), id);
self.state_snapshots.insert_at(state_snapshot.clone(), id);
}
self.inner = snapshot;
trace!(target: "backend::memdb", "Reverted snapshot {}", id);
self.inner = state_snapshot;
trace!(target: "backend::memdb", "Reverted state snapshot {}", id);
true
} else {
warn!(target: "backend::memdb", "No snapshot to revert for {}", id);
warn!(target: "backend::memdb", "No state snapshot to revert for {}", id);
false
}
}
Expand All @@ -112,20 +112,20 @@ impl MaybeFullDatabase for MemDb {
Some(&self.inner.accounts)
}

fn clear_into_snapshot(&mut self) -> StateSnapshot {
self.inner.clear_into_snapshot()
fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
self.inner.clear_into_state_snapshot()
}

fn read_as_snapshot(&self) -> StateSnapshot {
self.inner.read_as_snapshot()
fn read_as_state_snapshot(&self) -> StateSnapshot {
self.inner.read_as_state_snapshot()
}

fn clear(&mut self) {
self.inner.clear();
}

fn init_from_snapshot(&mut self, snapshot: StateSnapshot) {
self.inner.init_from_snapshot(snapshot)
fn init_from_state_snapshot(&mut self, snapshot: StateSnapshot) {
self.inner.init_from_state_snapshot(snapshot)
}
}

Expand Down
Loading
Loading