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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 7 additions & 9 deletions evm/src/executor/inspector/cheatcodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ use self::expect::{handle_expect_emit, handle_expect_revert};
use crate::{abi::HEVMCalls, executor::CHEATCODE_ADDRESS};
use bytes::Bytes;
use ethers::{
abi::{AbiDecode, AbiEncode},
types::Address,
abi::{AbiDecode, AbiEncode, RawLog},
types::{Address, H256},
};
use revm::{
opcode, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Interpreter, Return,
};
use std::collections::BTreeMap;

use super::logs::extract_log;

/// An inspector that handles calls to various cheatcodes, each with their own behavior.
///
/// Cheatcodes can be called by contracts during execution to modify the VM environment, such as
Expand Down Expand Up @@ -169,14 +167,14 @@ where
}
}

Return::Continue
}

fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) {
// Match logs if `expectEmit` has been called
if !self.expected_emits.is_empty() {
if let Some(log) = extract_log(interpreter) {
handle_expect_emit(self, log)
}
handle_expect_emit(self, RawLog { topics: topics.to_vec(), data: data.to_vec() });
}

Return::Continue
}

fn call_end(
Expand Down
60 changes: 4 additions & 56 deletions evm/src/executor/inspector/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::executor::{
use bytes::Bytes;
use ethers::{
abi::{AbiDecode, RawLog, Token},
types::H256,
types::{Address, H256},
};
use revm::{db::Database, opcode, CallInputs, EVMData, Gas, Inspector, Interpreter, Return};
use revm::{db::Database, CallInputs, EVMData, Gas, Inspector, Return};

/// An inspector that collects logs during execution.
///
Expand Down Expand Up @@ -45,17 +45,8 @@ impl<DB> Inspector<DB> for LogCollector
where
DB: Database,
{
fn step(
&mut self,
interpreter: &mut Interpreter,
_: &mut EVMData<'_, DB>,
_is_static: bool,
) -> Return {
if let Some(log) = extract_log(interpreter) {
self.logs.push(log);
}

Return::Continue
fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) {
self.logs.push(RawLog { topics: topics.to_vec(), data: data.to_vec() });
}

fn call(
Expand Down Expand Up @@ -85,46 +76,3 @@ fn convert_hh_log_to_event(call: HardhatConsoleCalls) -> RawLog {
data: ethers::abi::encode(&[Token::String(call.to_string())]),
}
}

/// Extracts a log from the interpreter if there is any.
pub fn extract_log(interpreter: &Interpreter) -> Option<RawLog> {
let num_topics = match interpreter.contract.code[interpreter.program_counter()] {
opcode::LOG0 => 0,
opcode::LOG1 => 1,
opcode::LOG2 => 2,
opcode::LOG3 => 3,
opcode::LOG4 => 4,
_ => return None,
};

let (offset, len) = (
as_usize_or_return!(interpreter.stack().peek(0).ok()?, None),
as_usize_or_return!(interpreter.stack().peek(1).ok()?, None),
);
let data = if len == 0 {
Vec::new()
} else {
// If we're trying to access more memory than exists, we will pretend like that memory is
// zeroed. We could resize the memory here, but it would mess up the gas accounting REVM
// does for memory resizes.
if offset > interpreter.memory.len() {
vec![0; len]
} else if offset + len > interpreter.memory.len() {
let mut data =
Vec::from(interpreter.memory.get_slice(offset, interpreter.memory.len()));
data.resize(offset + len, 0);
data
} else {
interpreter.memory.get_slice(offset, len).to_vec()
}
};

let mut topics = Vec::with_capacity(num_topics);
for i in 0..num_topics {
let mut topic = H256::zero();
interpreter.stack.peek(2 + i).ok()?.to_big_endian(topic.as_bytes_mut());
topics.push(topic);
}

Some(RawLog { topics, data })
}
14 changes: 13 additions & 1 deletion evm/src/executor/inspector/stack.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{Cheatcodes, Debugger, LogCollector, Tracer};
use bytes::Bytes;
use ethers::types::Address;
use ethers::types::{Address, H256};
use revm::{db::Database, CallInputs, CreateInputs, EVMData, Gas, Inspector, Interpreter, Return};

/// Helper macro to call the same method on multiple inspectors without resorting to dynamic
Expand Down Expand Up @@ -83,6 +83,18 @@ where
Return::Continue
}

fn log(
&mut self,
evm_data: &mut EVMData<'_, DB>,
address: &Address,
topics: &[H256],
data: &Bytes,
) {
call_inspectors!(inspector, [&mut self.tracer, &mut self.logs, &mut self.cheatcodes], {
inspector.log(evm_data, address, topics, data);
});
}

fn step_end(
&mut self,
interpreter: &mut Interpreter,
Expand Down
26 changes: 9 additions & 17 deletions evm/src/executor/inspector/tracer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::logs::extract_log;
use crate::{
executor::{
inspector::utils::{gas_used, get_create_address},
Expand All @@ -10,10 +9,11 @@ use crate::{
},
};
use bytes::Bytes;
use ethers::types::{Address, U256};
use revm::{
return_ok, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Interpreter, Return,
use ethers::{
abi::RawLog,
types::{Address, H256, U256},
};
use revm::{return_ok, CallInputs, CreateInputs, Database, EVMData, Gas, Inspector, Return};

/// An inspector that collects call traces.
#[derive(Default, Debug)]
Expand Down Expand Up @@ -81,19 +81,11 @@ where
(Return::Continue, Gas::new(call.gas_limit), Bytes::new())
}

fn step(
&mut self,
interpreter: &mut Interpreter,
_: &mut EVMData<'_, DB>,
_is_static: bool,
) -> Return {
if let Some(log) = extract_log(interpreter) {
let node = &mut self.traces.arena[*self.trace_stack.last().expect("no ongoing trace")];
node.ordering.push(LogCallOrder::Log(node.logs.len()));
node.logs.push(RawOrDecodedLog::Raw(log));
}

Return::Continue
fn log(&mut self, _: &mut EVMData<'_, DB>, _: &Address, topics: &[H256], data: &Bytes) {
let node = &mut self.traces.arena[*self.trace_stack.last().expect("no ongoing trace")];
node.ordering.push(LogCallOrder::Log(node.logs.len()));
node.logs
.push(RawOrDecodedLog::Raw(RawLog { topics: topics.to_vec(), data: data.to_vec() }));
}

fn call_end(
Expand Down
21 changes: 0 additions & 21 deletions evm/src/executor/inspector/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,6 @@ macro_rules! try_or_continue {
};
}

/// Tries to convert a U256 to a usize and returns from the function on an error.
///
/// This is useful for opcodes that deal with the stack where parameters might be invalid and you
/// want to defer error handling to the VM itself.
macro_rules! as_usize_or_return {
($v:expr) => {
if $v.0[1] != 0 || $v.0[2] != 0 || $v.0[3] != 0 {
return
} else {
$v.0[0] as usize
}
};
($v:expr, $r:expr) => {
if $v.0[1] != 0 || $v.0[2] != 0 || $v.0[3] != 0 {
return $r
} else {
$v.0[0] as usize
}
};
}

/// Get the address of a contract creation
pub fn get_create_address(call: &CreateInputs, nonce: u64) -> Address {
match call.scheme {
Expand Down