Skip to content
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
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