Skip to content

Commit 2a052c6

Browse files
authored
Merge pull request #805 from matter-labs/popzxc-move-cheatcodes
refactor: Move custom cheatcode logic into a generic handler
2 parents ddf8b75 + b38a46c commit 2a052c6

File tree

8 files changed

+274
-517
lines changed

8 files changed

+274
-517
lines changed

crates/cheatcodes/src/evm.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
};
88
use alloy_consensus::TxEnvelope;
99
use alloy_genesis::{Genesis, GenesisAccount};
10-
use alloy_primitives::{Address, B256, U256};
10+
use alloy_primitives::{Address, Bytes, B256, U256};
1111
use alloy_rlp::Decodable;
1212
use alloy_sol_types::SolValue;
1313
use foundry_common::fs::{read_json_file, write_json_file};
@@ -18,7 +18,7 @@ use foundry_evm_core::{
1818
};
1919
use foundry_evm_traces::StackSnapshotType;
2020
use rand::Rng;
21-
use revm::primitives::{Account, SpecId};
21+
use revm::primitives::{Account, Bytecode, SpecId, KECCAK_EMPTY};
2222
use std::{collections::BTreeMap, path::Path};
2323
mod record_debug_step;
2424
use record_debug_step::{convert_call_trace_to_debug_step, flatten_call_trace};
@@ -63,8 +63,7 @@ impl Cheatcode for addrCall {
6363
impl Cheatcode for getNonce_0Call {
6464
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
6565
let Self { account } = self;
66-
67-
ccx.state.strategy.runner.clone().cheatcode_get_nonce(ccx, *account)
66+
get_nonce(ccx, account)
6867
}
6968
}
7069

@@ -350,7 +349,8 @@ impl Cheatcode for getBlobhashesCall {
350349
impl Cheatcode for rollCall {
351350
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
352351
let Self { newHeight } = self;
353-
ccx.state.strategy.runner.clone().cheatcode_roll(ccx, *newHeight)
352+
ccx.ecx.env.block.number = *newHeight;
353+
Ok(Default::default())
354354
}
355355
}
356356

@@ -372,7 +372,8 @@ impl Cheatcode for txGasPriceCall {
372372
impl Cheatcode for warpCall {
373373
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
374374
let Self { newTimestamp } = self;
375-
ccx.state.strategy.runner.clone().cheatcode_warp(ccx, *newTimestamp)
375+
ccx.ecx.env.block.timestamp = *newTimestamp;
376+
Ok(Default::default())
376377
}
377378
}
378379

@@ -407,38 +408,65 @@ impl Cheatcode for dealCall {
407408
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
408409
let Self { account: address, newBalance: new_balance } = *self;
409410

410-
ccx.state.strategy.runner.clone().cheatcode_deal(ccx, address, new_balance)
411+
let account = journaled_account(ccx.ecx, address)?;
412+
let old_balance = std::mem::replace(&mut account.info.balance, new_balance);
413+
let record = DealRecord { address, old_balance, new_balance };
414+
ccx.state.eth_deals.push(record);
415+
Ok(Default::default())
411416
}
412417
}
413418

414419
impl Cheatcode for etchCall {
415420
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
416421
let Self { target, newRuntimeBytecode } = self;
417422

418-
ccx.state.strategy.runner.clone().cheatcode_etch(ccx, *target, newRuntimeBytecode)
423+
ensure_not_precompile!(&target, ccx);
424+
ccx.ecx.load_account(*target)?;
425+
let bytecode = Bytecode::new_raw(Bytes::copy_from_slice(newRuntimeBytecode));
426+
ccx.ecx.journaled_state.set_code(*target, bytecode);
427+
Ok(Default::default())
419428
}
420429
}
421430

422431
impl Cheatcode for resetNonceCall {
423432
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
424433
let Self { account } = self;
425-
ccx.state.strategy.runner.clone().cheatcode_reset_nonce(ccx, *account)
434+
let account = journaled_account(ccx.ecx, *account)?;
435+
// Per EIP-161, EOA nonces start at 0, but contract nonces
436+
// start at 1. Comparing by code_hash instead of code
437+
// to avoid hitting the case where account's code is None.
438+
let empty = account.info.code_hash == KECCAK_EMPTY;
439+
let nonce = if empty { 0 } else { 1 };
440+
account.info.nonce = nonce;
441+
debug!(target: "cheatcodes", nonce, "reset");
442+
Ok(Default::default())
426443
}
427444
}
428445

429446
impl Cheatcode for setNonceCall {
430447
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
431448
let Self { account, newNonce } = *self;
432449

433-
ccx.state.strategy.runner.clone().cheatcode_set_nonce(ccx, account, newNonce)
450+
let account = journaled_account(ccx.ecx, account)?;
451+
// nonce must increment only
452+
let current = account.info.nonce;
453+
ensure!(
454+
newNonce >= current,
455+
"new nonce ({newNonce}) must be strictly equal to or higher than the \
456+
account's current nonce ({current})"
457+
);
458+
account.info.nonce = newNonce;
459+
Ok(Default::default())
434460
}
435461
}
436462

437463
impl Cheatcode for setNonceUnsafeCall {
438464
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
439465
let Self { account, newNonce } = *self;
440466

441-
ccx.state.strategy.runner.clone().cheatcode_set_nonce_unsafe(ccx, account, newNonce)
467+
let account = journaled_account(ccx.ecx, account)?;
468+
account.info.nonce = newNonce;
469+
Ok(Default::default())
442470
}
443471
}
444472

crates/cheatcodes/src/evm/mock.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ impl Cheatcode for clearMockedCallsCall {
1515
impl Cheatcode for mockCall_0Call {
1616
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
1717
let Self { callee, data, returnData } = self;
18-
ccx.state.strategy.runner.clone().cheatcode_mock_call(ccx, *callee, data, returnData)
18+
let _ = make_acc_non_empty(callee, ccx.ecx)?;
19+
mock_call(ccx.state, callee, data, None, returnData, InstructionResult::Return);
20+
Ok(Default::default())
1921
}
2022
}
2123

@@ -83,7 +85,10 @@ impl Cheatcode for mockCalls_1Call {
8385
impl Cheatcode for mockCallRevert_0Call {
8486
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
8587
let Self { callee, data, revertData } = self;
86-
ccx.state.strategy.runner.clone().cheatcode_mock_call_revert(ccx, *callee, data, revertData)
88+
89+
let _ = make_acc_non_empty(callee, ccx.ecx)?;
90+
mock_call(ccx.state, callee, data, None, revertData, InstructionResult::Revert);
91+
Ok(Default::default())
8792
}
8893
}
8994

crates/cheatcodes/src/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ impl Cheatcode for getArtifactPathByDeployedCodeCall {
283283
impl Cheatcode for getCodeCall {
284284
fn apply(&self, state: &mut Cheatcodes) -> Result {
285285
let Self { artifactPath: path } = self;
286-
state.strategy.runner.get_artifact_code(state, path, false)
286+
Ok(get_artifact_code(state, path, false)?.abi_encode())
287287
}
288288
}
289289

crates/cheatcodes/src/inspector.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2256,7 +2256,8 @@ fn apply_dispatch(
22562256
}
22572257

22582258
// Apply the cheatcode.
2259-
let mut result = cheat.dyn_apply(ccx, executor);
2259+
let runner = ccx.state.strategy.runner.new_cloned();
2260+
let mut result = runner.apply_full(cheat, ccx, executor);
22602261

22612262
// Format the error message to include the cheatcode name.
22622263
if let Err(e) = &mut result {

crates/cheatcodes/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,14 @@ pub(crate) trait Cheatcode: CheatcodeDef + DynCheatcode {
9696
}
9797
}
9898

99-
pub(crate) trait DynCheatcode: 'static {
99+
pub trait DynCheatcode: 'static + std::any::Any {
100100
fn cheatcode(&self) -> &'static spec::Cheatcode<'static>;
101101

102102
fn as_debug(&self) -> &dyn std::fmt::Debug;
103103

104104
fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result;
105+
106+
fn as_any(&self) -> &dyn std::any::Any;
105107
}
106108

107109
impl<T: Cheatcode> DynCheatcode for T {
@@ -119,6 +121,11 @@ impl<T: Cheatcode> DynCheatcode for T {
119121
fn dyn_apply(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
120122
self.apply_full(ccx, executor)
121123
}
124+
125+
#[inline]
126+
fn as_any(&self) -> &dyn std::any::Any {
127+
self
128+
}
122129
}
123130

124131
impl dyn DynCheatcode {

0 commit comments

Comments
 (0)