diff --git a/Cargo.lock b/Cargo.lock index a96ecd6ede093..b50ccae171862 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3587,7 +3587,7 @@ dependencies = [ [[package]] name = "revm" version = "1.2.0" -source = "git+https://github.com/bluealloy/revm#7a5a2cdddf253c8500ba46eef3f05c1f1c59f0d1" +source = "git+https://github.com/bluealloy/revm#cb5fbb9adc36c8ee127dce92259356cecbb829b8" dependencies = [ "arrayref", "auto_impl", @@ -3603,7 +3603,7 @@ dependencies = [ [[package]] name = "revm_precompiles" version = "0.4.0" -source = "git+https://github.com/bluealloy/revm#7a5a2cdddf253c8500ba46eef3f05c1f1c59f0d1" +source = "git+https://github.com/bluealloy/revm#cb5fbb9adc36c8ee127dce92259356cecbb829b8" dependencies = [ "bytes", "k256", diff --git a/evm/src/executor/inspector/cheatcodes/mod.rs b/evm/src/executor/inspector/cheatcodes/mod.rs index 52878cd302d9b..ede29a022c0aa 100644 --- a/evm/src/executor/inspector/cheatcodes/mod.rs +++ b/evm/src/executor/inspector/cheatcodes/mod.rs @@ -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 @@ -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( diff --git a/evm/src/executor/inspector/logs.rs b/evm/src/executor/inspector/logs.rs index 33390c5e8f97b..f215fcab10e64 100644 --- a/evm/src/executor/inspector/logs.rs +++ b/evm/src/executor/inspector/logs.rs @@ -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. /// @@ -45,17 +45,8 @@ impl Inspector 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( @@ -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 { - 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 }) -} diff --git a/evm/src/executor/inspector/stack.rs b/evm/src/executor/inspector/stack.rs index b651d5a4666ed..1b42f16f1cdcf 100644 --- a/evm/src/executor/inspector/stack.rs +++ b/evm/src/executor/inspector/stack.rs @@ -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 @@ -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, diff --git a/evm/src/executor/inspector/tracer.rs b/evm/src/executor/inspector/tracer.rs index c6da35b8e34e4..00976becb4be9 100644 --- a/evm/src/executor/inspector/tracer.rs +++ b/evm/src/executor/inspector/tracer.rs @@ -1,4 +1,3 @@ -use super::logs::extract_log; use crate::{ executor::{ inspector::utils::{gas_used, get_create_address}, @@ -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)] @@ -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( diff --git a/evm/src/executor/inspector/utils.rs b/evm/src/executor/inspector/utils.rs index ccac891631623..5ea3a39e87321 100644 --- a/evm/src/executor/inspector/utils.rs +++ b/evm/src/executor/inspector/utils.rs @@ -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 {