Skip to content

Commit

Permalink
refactor: clean up evm inspectors (#5675)
Browse files Browse the repository at this point in the history
* refactor: clean up evm inspectors

* tests
  • Loading branch information
DaniPopes authored Aug 19, 2023
1 parent 628686d commit 2e90e35
Show file tree
Hide file tree
Showing 30 changed files with 596 additions and 676 deletions.
110 changes: 36 additions & 74 deletions crates/anvil/src/eth/backend/mem/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,15 @@ use foundry_evm::{
executor::inspector::{LogCollector, Tracer},
revm,
revm::{
inspectors::GasInspector,
interpreter::{CallInputs, CreateInputs, Gas, InstructionResult, Interpreter},
primitives::{B160, B256},
EVMData,
},
};
use std::{cell::RefCell, rc::Rc};

/// The [`revm::Inspector`] used when transacting in the evm
#[derive(Debug, Clone, Default)]
pub struct Inspector {
pub gas: Option<Rc<RefCell<GasInspector>>>,
pub tracer: Option<Tracer>,
/// collects all `console.sol` logs
pub log_collector: LogCollector,
Expand All @@ -42,109 +39,83 @@ impl Inspector {
self
}

/// Enables steps recording for `Tracer` and attaches `GasInspector` to it
/// If `Tracer` wasn't configured before, configures it automatically
/// Enables steps recording for `Tracer`.
pub fn with_steps_tracing(mut self) -> Self {
if self.tracer.is_none() {
self = self.with_tracing()
}
let gas_inspector = Rc::new(RefCell::new(GasInspector::default()));
self.gas = Some(gas_inspector.clone());
self.tracer = self.tracer.map(|tracer| tracer.with_steps_recording(gas_inspector));

let tracer = self.tracer.get_or_insert_with(Default::default);
tracer.record_steps();
self
}
}

impl<DB: Database> revm::Inspector<DB> for Inspector {
#[inline]
fn initialize_interp(
&mut self,
interp: &mut Interpreter,
data: &mut EVMData<'_, DB>,
is_static: bool,
) -> InstructionResult {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{ inspector.initialize_interp(interp, data, is_static) }
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.initialize_interp(interp, data, is_static);
});
InstructionResult::Continue
}

#[inline]
fn step(
&mut self,
interp: &mut Interpreter,
data: &mut EVMData<'_, DB>,
is_static: bool,
) -> InstructionResult {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{
inspector.step(interp, data, is_static);
}
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.step(interp, data, is_static);
});
InstructionResult::Continue
}

#[inline]
fn log(
&mut self,
evm_data: &mut EVMData<'_, DB>,
address: &B160,
topics: &[B256],
data: &Bytes,
) {
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.tracer,
Some(&mut self.log_collector)
],
{
inspector.log(evm_data, address, topics, data);
}
);
call_inspectors!([&mut self.tracer, Some(&mut self.log_collector)], |inspector| {
inspector.log(evm_data, address, topics, data);
});
}

#[inline]
fn step_end(
&mut self,
interp: &mut Interpreter,
data: &mut EVMData<'_, DB>,
is_static: bool,
eval: InstructionResult,
) -> InstructionResult {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{
inspector.step_end(interp, data, is_static, eval);
}
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.step_end(interp, data, is_static, eval);
});
eval
}

#[inline]
fn call(
&mut self,
data: &mut EVMData<'_, DB>,
call: &mut CallInputs,
is_static: bool,
) -> (InstructionResult, Gas, Bytes) {
call_inspectors!(
inspector,
[
&mut self.gas.as_deref().map(|gas| gas.borrow_mut()),
&mut self.tracer,
Some(&mut self.log_collector)
],
{
inspector.call(data, call, is_static);
}
);
call_inspectors!([&mut self.tracer, Some(&mut self.log_collector)], |inspector| {
inspector.call(data, call, is_static);
});

(InstructionResult::Continue, Gas::new(call.gas_limit), Bytes::new())
}

#[inline]
fn call_end(
&mut self,
data: &mut EVMData<'_, DB>,
Expand All @@ -154,32 +125,26 @@ impl<DB: Database> revm::Inspector<DB> for Inspector {
out: Bytes,
is_static: bool,
) -> (InstructionResult, Gas, Bytes) {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{
inspector.call_end(data, inputs, remaining_gas, ret, out.clone(), is_static);
}
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.call_end(data, inputs, remaining_gas, ret, out.clone(), is_static);
});
(ret, remaining_gas, out)
}

#[inline]
fn create(
&mut self,
data: &mut EVMData<'_, DB>,
call: &mut CreateInputs,
) -> (InstructionResult, Option<B160>, Gas, Bytes) {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{
inspector.create(data, call);
}
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.create(data, call);
});

(InstructionResult::Continue, None, Gas::new(call.gas_limit), Bytes::new())
}

#[inline]
fn create_end(
&mut self,
data: &mut EVMData<'_, DB>,
Expand All @@ -189,18 +154,15 @@ impl<DB: Database> revm::Inspector<DB> for Inspector {
gas: Gas,
retdata: Bytes,
) -> (InstructionResult, Option<B160>, Gas, Bytes) {
call_inspectors!(
inspector,
[&mut self.gas.as_deref().map(|gas| gas.borrow_mut()), &mut self.tracer],
{
inspector.create_end(data, inputs, status, address, gas, retdata.clone());
}
);
call_inspectors!([&mut self.tracer], |inspector| {
inspector.create_end(data, inputs, status, address, gas, retdata.clone());
});
(status, address, gas, retdata)
}
}

/// Prints all the logs
#[inline]
pub fn print_logs(logs: &[Log]) {
for log in decode_console_logs(logs) {
node_info!("{}", log);
Expand Down
12 changes: 6 additions & 6 deletions crates/anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ impl Backend {
}

pub fn precompiles(&self) -> Vec<Address> {
get_precompiles_for(self.env().read().cfg.spec_id)
get_precompiles_for(self.env.read().cfg.spec_id)
}

/// Resets the fork to a fresh state
Expand Down Expand Up @@ -541,12 +541,12 @@ impl Backend {

/// Returns the block gas limit
pub fn gas_limit(&self) -> U256 {
self.env().read().block.gas_limit.into()
self.env.read().block.gas_limit.into()
}

/// Sets the block gas limit
pub fn set_gas_limit(&self, gas_limit: U256) {
self.env().write().block.gas_limit = gas_limit.into();
self.env.write().block.gas_limit = gas_limit.into();
}

/// Returns the current base fee
Expand Down Expand Up @@ -791,7 +791,7 @@ impl Backend {
let (outcome, header, block_hash) = {
let current_base_fee = self.base_fee();

let mut env = self.env().read().clone();
let mut env = self.env.read().clone();

if env.block.basefee == revm::primitives::U256::ZERO {
// this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`
Expand Down Expand Up @@ -1631,7 +1631,7 @@ impl Backend {
// So this provides calls the given provided function `f` with a genesis aware database
if let Some(fork) = self.get_fork() {
if block_number == U256::from(fork.block_number()) {
let mut block = self.env().read().block.clone();
let mut block = self.env.read().block.clone();
let db = self.db.read().await;
let gen_db = self.genesis.state_db_at_genesis(Box::new(&*db));

Expand All @@ -1651,7 +1651,7 @@ impl Backend {
}

let db = self.db.read().await;
let block = self.env().read().block.clone();
let block = self.env.read().block.clone();
Ok(f(Box::new(&*db), block))
}

Expand Down
17 changes: 9 additions & 8 deletions crates/chisel/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,15 @@ impl SessionSource {
};

// Build a new executor
let executor = ExecutorBuilder::default()
.with_config(env)
.with_chisel_state(final_pc)
.set_tracing(true)
.with_spec(foundry_evm::utils::evm_spec(&self.config.foundry_config.evm_version))
.with_gas_limit(self.config.evm_opts.gas_limit())
.with_cheatcodes(CheatsConfig::new(&self.config.foundry_config, &self.config.evm_opts))
.build(backend);
let executor = ExecutorBuilder::new()
.inspectors(|stack| {
stack.chisel_state(final_pc).trace(true).cheatcodes(
CheatsConfig::new(&self.config.foundry_config, &self.config.evm_opts).into(),
)
})
.gas_limit(self.config.evm_opts.gas_limit())
.spec(foundry_evm::utils::evm_spec(self.config.foundry_config.evm_version))
.build(env, backend);

// Create a [ChiselRunner] with a default balance of [U256::MAX] and
// the sender [Address::zero].
Expand Down
23 changes: 11 additions & 12 deletions crates/chisel/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,19 @@ impl ChiselRunner {
value: U256,
commit: bool,
) -> eyre::Result<ChiselResult> {
let fs_commit_changed =
if let Some(ref mut cheatcodes) = self.executor.inspector_config_mut().cheatcodes {
let original_fs_commit = cheatcodes.fs_commit;
cheatcodes.fs_commit = false;
original_fs_commit != cheatcodes.fs_commit
} else {
false
};
let fs_commit_changed = if let Some(cheatcodes) = &mut self.executor.inspector.cheatcodes {
let original_fs_commit = cheatcodes.fs_commit;
cheatcodes.fs_commit = false;
original_fs_commit != cheatcodes.fs_commit
} else {
false
};

let mut res = self.executor.call_raw(from, to, calldata.0.clone(), value)?;
let mut gas_used = res.gas_used;
if matches!(res.exit_reason, return_ok!()) {
// store the current gas limit and reset it later
let init_gas_limit = self.executor.env_mut().tx.gas_limit;
let init_gas_limit = self.executor.env.tx.gas_limit;

// the executor will return the _exact_ gas value this transaction consumed, setting
// this value as gas limit will result in `OutOfGas` so to come up with a
Expand All @@ -156,7 +155,7 @@ impl ChiselRunner {
let mut last_highest_gas_limit = highest_gas_limit;
while (highest_gas_limit - lowest_gas_limit) > 1 {
let mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
self.executor.env_mut().tx.gas_limit = mid_gas_limit;
self.executor.env.tx.gas_limit = mid_gas_limit;
let res = self.executor.call_raw(from, to, calldata.0.clone(), value)?;
match res.exit_reason {
InstructionResult::Revert |
Expand All @@ -182,13 +181,13 @@ impl ChiselRunner {
}
}
// reset gas limit in the
self.executor.env_mut().tx.gas_limit = init_gas_limit;
self.executor.env.tx.gas_limit = init_gas_limit;
}

// if we changed `fs_commit` during gas limit search, re-execute the call with original
// value
if fs_commit_changed {
if let Some(ref mut cheatcodes) = self.executor.inspector_config_mut().cheatcodes {
if let Some(cheatcodes) = &mut self.executor.inspector.cheatcodes {
cheatcodes.fs_commit = !cheatcodes.fs_commit;
}

Expand Down
Loading

0 comments on commit 2e90e35

Please sign in to comment.