From 628869cfc4b4979e102b555e2999ab4aa0f039c8 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 22 Jan 2024 13:17:35 +0100 Subject: [PATCH 1/9] feat: migrate to new inspector API --- Cargo.toml | 2 +- src/access_list.rs | 14 ++-- src/stack/maybe_owned.rs | 87 +++++++++------------- src/stack/mod.rs | 100 +++++++++++-------------- src/tracing/fourbyte.rs | 21 +++--- src/tracing/js/bindings.rs | 4 +- src/tracing/js/mod.rs | 117 +++++++++++++++-------------- src/tracing/mod.rs | 149 ++++++++++++++++++------------------- src/tracing/opcount.rs | 4 +- src/tracing/types.rs | 3 +- 10 files changed, 234 insertions(+), 267 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c171e8fc..c0fe8c21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy" } alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy" } # revm = "3.4" -revm = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze", default-features = false, features = ["std"] } +revm = { git = "https://github.com/bluealloy/revm", default-features = false, features = ["std"] } # js-tracing-inspector boa_engine = { version = "0.17", optional = true } diff --git a/src/access_list.rs b/src/access_list.rs index e2bdd405..7034432d 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -2,7 +2,7 @@ use alloy_primitives::{Address, B256}; use alloy_rpc_types::{AccessList, AccessListItem}; use revm::{ interpreter::{opcode, Interpreter}, - Database, EVMData, Inspector, + Database, EvmContext, Inspector, }; use std::collections::{BTreeSet, HashMap, HashSet}; @@ -62,11 +62,11 @@ impl Inspector for AccessListInspector where DB: Database, { - fn step(&mut self, interpreter: &mut Interpreter<'_>, _data: &mut EVMData<'_, DB>) { - match interpreter.current_opcode() { + fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { + match interp.current_opcode() { opcode::SLOAD | opcode::SSTORE => { - if let Ok(slot) = interpreter.stack().peek(0) { - let cur_contract = interpreter.contract.address; + if let Ok(slot) = interp.stack().peek(0) { + let cur_contract = interp.contract.address; self.access_list .entry(cur_contract) .or_default() @@ -78,7 +78,7 @@ where | opcode::EXTCODESIZE | opcode::BALANCE | opcode::SELFDESTRUCT => { - if let Ok(slot) = interpreter.stack().peek(0) { + if let Ok(slot) = interp.stack().peek(0) { let addr = Address::from_word(B256::from(slot.to_be_bytes())); if !self.excluded.contains(&addr) { self.access_list.entry(addr).or_default(); @@ -86,7 +86,7 @@ where } } opcode::DELEGATECALL | opcode::CALL | opcode::STATICCALL | opcode::CALLCODE => { - if let Ok(slot) = interpreter.stack().peek(1) { + if let Ok(slot) = interp.stack().peek(1) { let addr = Address::from_word(B256::from(slot.to_be_bytes())); if !self.excluded.contains(&addr) { self.access_list.entry(addr).or_default(); diff --git a/src/stack/maybe_owned.rs b/src/stack/maybe_owned.rs index c02ce6e4..9f50a16b 100644 --- a/src/stack/maybe_owned.rs +++ b/src/stack/maybe_owned.rs @@ -1,8 +1,10 @@ -use alloy_primitives::U256; +use alloy_primitives::{Log, U256}; use revm::{ - interpreter::{CallInputs, CreateInputs, Gas, InstructionResult, Interpreter}, - primitives::{db::Database, Address, Bytes, B256}, - EVMData, Inspector, + interpreter::{ + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, + }, + primitives::{db::Database, Address}, + EvmContext, Inspector, }; use std::{ cell::{Ref, RefCell}, @@ -69,102 +71,81 @@ where DB: Database, INSP: Inspector, { - fn initialize_interp(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { match self { - MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().initialize_interp(interp, data), + MaybeOwnedInspector::Owned(insp) => { + insp.borrow_mut().initialize_interp(interp, context) + } MaybeOwnedInspector::Stacked(_) => {} } } - fn step(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { match self { - MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().step(interp, data), + MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().step(interp, context), MaybeOwnedInspector::Stacked(_) => {} } } - fn log( - &mut self, - evm_data: &mut EVMData<'_, DB>, - address: &Address, - topics: &[B256], - data: &Bytes, - ) { + fn log(&mut self, context: &mut EvmContext, log: &Log) { match self { - MaybeOwnedInspector::Owned(insp) => { - return insp.borrow_mut().log(evm_data, address, topics, data) - } + MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().log(context, log), MaybeOwnedInspector::Stacked(_) => {} } } - fn step_end(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { match self { - MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().step_end(interp, data), + MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().step_end(interp, context), MaybeOwnedInspector::Stacked(_) => {} } } fn call( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes) { + ) -> Option { match self { - MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().call(data, inputs), - MaybeOwnedInspector::Stacked(_) => {} + MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().call(context, inputs), + MaybeOwnedInspector::Stacked(_) => None, } - - (InstructionResult::Continue, Gas::new(0), Bytes::new()) } fn call_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CallInputs, - remaining_gas: Gas, - ret: InstructionResult, - out: Bytes, - ) -> (InstructionResult, Gas, Bytes) { + context: &mut EvmContext, + result: InterpreterResult, + ) -> InterpreterResult { match self { - MaybeOwnedInspector::Owned(insp) => { - return insp.borrow_mut().call_end(data, inputs, remaining_gas, ret, out) - } - MaybeOwnedInspector::Stacked(_) => {} + MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().call_end(context, result), + MaybeOwnedInspector::Stacked(_) => result, } - (ret, remaining_gas, out) } fn create( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CreateInputs, - ) -> (InstructionResult, Option
, Gas, Bytes) { + ) -> Option { match self { - MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().create(data, inputs), - MaybeOwnedInspector::Stacked(_) => {} + MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().create(context, inputs), + MaybeOwnedInspector::Stacked(_) => None, } - - (InstructionResult::Continue, None, Gas::new(0), Bytes::default()) } fn create_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CreateInputs, - ret: InstructionResult, + context: &mut EvmContext, + result: InterpreterResult, address: Option
, - remaining_gas: Gas, - out: Bytes, - ) -> (InstructionResult, Option
, Gas, Bytes) { + ) -> CreateOutcome { match self { MaybeOwnedInspector::Owned(insp) => { - return insp.borrow_mut().create_end(data, inputs, ret, address, remaining_gas, out) + return insp.borrow_mut().create_end(context, result, address) } - MaybeOwnedInspector::Stacked(_) => {} + MaybeOwnedInspector::Stacked(_) => CreateOutcome::new(result, address), } - - (ret, address, remaining_gas, out) } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { diff --git a/src/stack/mod.rs b/src/stack/mod.rs index 50105517..4024ba85 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -1,9 +1,11 @@ -use alloy_primitives::{Address, Bytes, B256, U256}; +use alloy_primitives::{Address, Log, B256, U256}; use revm::{ inspectors::CustomPrintTracer, - interpreter::{CallInputs, CreateInputs, Gas, InstructionResult, Interpreter}, + interpreter::{ + CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, + }, primitives::Env, - Database, EVMData, Inspector, + Database, EvmContext, Inspector, }; use std::fmt::Debug; @@ -15,7 +17,7 @@ pub use maybe_owned::MaybeOwnedInspector; /// - Block: Hook on block execution /// - BlockWithIndex: Hook on block execution transaction index /// - Transaction: Hook on a specific transaction hash -#[derive(Debug, Default, Clone, Copy)] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] pub enum Hook { #[default] /// No hook. @@ -100,111 +102,97 @@ impl Inspector for InspectorStack where DB: Database, { - fn initialize_interp(&mut self, interpreter: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.initialize_interp(interpreter, data); + inspector.initialize_interp(interp, context); }); } - fn step(&mut self, interpreter: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.step(interpreter, data); + inspector.step(interp, context); }); } - fn log( - &mut self, - evm_data: &mut EVMData<'_, DB>, - address: &Address, - topics: &[B256], - data: &Bytes, - ) { + fn log(&mut self, context: &mut EvmContext, log: &Log) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.log(evm_data, address, topics, data); + inspector.log(context, log); }); } - fn step_end(&mut self, interpreter: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.step_end(interpreter, data); + inspector.step_end(interp, context); }); } fn call( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes) { + ) -> Option { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let (status, gas, retdata) = inspector.call(data, inputs); - - // Allow inspectors to exit early - if status != InstructionResult::Continue { - return (status, gas, retdata); + if let Some(outcome) = inspector.call(context, inputs) { + return Some(outcome); } }); - (InstructionResult::Continue, Gas::new(inputs.gas_limit), Bytes::new()) + None } fn call_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CallInputs, - remaining_gas: Gas, - ret: InstructionResult, - out: Bytes, - ) -> (InstructionResult, Gas, Bytes) { + context: &mut EvmContext, + result: InterpreterResult, + ) -> InterpreterResult { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let (new_ret, new_gas, new_out) = - inspector.call_end(data, inputs, remaining_gas, ret, out.clone()); + let new_ret = inspector.call_end(context, result.clone()); // If the inspector returns a different ret or a revert with a non-empty message, // we assume it wants to tell us something - if new_ret != ret || (new_ret == InstructionResult::Revert && new_out != out) { - return (new_ret, new_gas, new_out); + if new_ret.result != result.result + || (new_ret.result.is_revert() && new_ret.output != result.output) + { + return new_ret; } }); - (ret, remaining_gas, out) + result } fn create( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CreateInputs, - ) -> (InstructionResult, Option
, Gas, Bytes) { + ) -> Option { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let (status, addr, gas, retdata) = inspector.create(data, inputs); - - // Allow inspectors to exit early - if status != InstructionResult::Continue { - return (status, addr, gas, retdata); + if let Some(out) = inspector.create(context, inputs) { + return Some(out); } }); - (InstructionResult::Continue, None, Gas::new(inputs.gas_limit), Bytes::new()) + None } fn create_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CreateInputs, - ret: InstructionResult, + context: &mut EvmContext, + result: InterpreterResult, address: Option
, - remaining_gas: Gas, - out: Bytes, - ) -> (InstructionResult, Option
, Gas, Bytes) { + ) -> CreateOutcome { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let (new_ret, new_address, new_gas, new_retdata) = - inspector.create_end(data, inputs, ret, address, remaining_gas, out.clone()); + let new_ret = inspector.create_end(context, result.clone(), address); - if new_ret != ret { - return (new_ret, new_address, new_gas, new_retdata); + // If the inspector returns a different ret or a revert with a non-empty message, + // we assume it wants to tell us something + if new_ret.result.result != result.result + || (new_ret.result.result.is_revert() && new_ret.result.output != result.output) + { + return new_ret; } }); - (ret, address, remaining_gas, out) + CreateOutcome::new(result, address) } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index c5b96db8..a54134e6 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -21,11 +21,11 @@ //! //! See also -use alloy_primitives::{hex, Bytes, Selector}; +use alloy_primitives::{hex, Selector}; use alloy_rpc_trace_types::geth::FourByteFrame; use revm::{ - interpreter::{CallInputs, Gas, InstructionResult}, - Database, EVMData, Inspector, + interpreter::{CallInputs, CallOutcome}, + Database, EvmContext, Inspector, }; use std::collections::HashMap; @@ -49,16 +49,17 @@ where { fn call( &mut self, - _data: &mut EVMData<'_, DB>, - call: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes) { - if call.input.len() >= 4 { - let selector = Selector::try_from(&call.input[..4]).expect("input is at least 4 bytes"); - let calldata_size = call.input[4..].len(); + _context: &mut EvmContext, + inputs: &mut CallInputs, + ) -> Option { + if inputs.input.len() >= 4 { + let selector = + Selector::try_from(&inputs.input[..4]).expect("input is at least 4 bytes"); + let calldata_size = inputs.input[4..].len(); *self.inner.entry((selector, calldata_size)).or_default() += 1; } - (InstructionResult::Continue, Gas::new(0), Bytes::new()) + None } } diff --git a/src/tracing/js/bindings.rs b/src/tracing/js/bindings.rs index 1f65127e..ed230781 100644 --- a/src/tracing/js/bindings.rs +++ b/src/tracing/js/bindings.rs @@ -644,7 +644,7 @@ impl CallFrame { } /// The `ctx` object that represents the context in which the transaction is executed. -pub(crate) struct EvmContext { +pub(crate) struct JsEvmContext { /// String, one of the two values CALL and CREATE pub(crate) r#type: String, /// Sender of the transaction @@ -670,7 +670,7 @@ pub(crate) struct EvmContext { pub(crate) transaction_ctx: TransactionContext, } -impl EvmContext { +impl JsEvmContext { pub(crate) fn into_js_object(self, ctx: &mut Context<'_>) -> JsResult { let Self { r#type, diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 752a17c3..682c250a 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -3,22 +3,23 @@ use crate::tracing::{ js::{ bindings::{ - CallFrame, Contract, EvmContext, EvmDbRef, FrameResult, MemoryRef, StackRef, StepLog, + CallFrame, Contract, EvmDbRef, FrameResult, JsEvmContext, MemoryRef, StackRef, StepLog, }, builtins::{register_builtins, PrecompileList}, }, types::CallKind, }; -use alloy_primitives::{Address, Bytes, B256, U256}; +use alloy_primitives::{Address, Bytes, Log, B256, U256}; pub use boa_engine::vm::RuntimeLimits; use boa_engine::{Context, JsError, JsObject, JsResult, JsValue, Source}; use revm::{ interpreter::{ - return_revert, CallInputs, CallScheme, CreateInputs, Gas, InstructionResult, Interpreter, + return_revert, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, + InstructionResult, Interpreter, InterpreterResult, }, precompile::Precompiles, primitives::{Env, ExecutionResult, Output, ResultAndState, TransactTo}, - Database, DatabaseRef, EVMData, Inspector, + Database, DatabaseRef, EvmContext, Inspector, }; pub(crate) mod bindings; @@ -244,7 +245,7 @@ impl JsInspector { ExecutionResult::Halt { .. } => {} }; - let ctx = EvmContext { + let ctx = JsEvmContext { r#type: match env.tx.transact_to { TransactTo::Call(target) => { to = Some(target); @@ -362,7 +363,7 @@ impl JsInspector { if !self.precompiles_registered { return; } - let precompiles = PrecompileList(precompiles.addresses().into_iter().copied().collect()); + let precompiles = PrecompileList(precompiles.addresses().copied().collect()); let _ = precompiles.register_callable(&mut self.ctx); @@ -375,15 +376,15 @@ where DB: Database + DatabaseRef, ::Error: std::fmt::Display, { - fn step(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { if self.step_fn.is_none() { return; } - let (db, _db_guard) = EvmDbRef::new(&data.journaled_state.state, &*data.db); + let (db, _db_guard) = EvmDbRef::new(&context.journaled_state.state, &context.db); let (stack, _stack_guard) = StackRef::new(&interp.stack); - let (memory, _memory_guard) = MemoryRef::new(interp.shared_memory); + let (memory, _memory_guard) = MemoryRef::new(&interp.shared_memory); let step = StepLog { stack, op: interp.current_opcode().into(), @@ -391,7 +392,7 @@ where pc: interp.program_counter() as u64, gas_remaining: interp.gas.remaining(), cost: interp.gas.spend(), - depth: data.journaled_state.depth(), + depth: context.journaled_state.depth(), refund: interp.gas.refunded() as u64, error: None, contract: self.active_call().contract.clone(), @@ -402,25 +403,16 @@ where } } - fn log( - &mut self, - _evm_data: &mut EVMData<'_, DB>, - _address: &Address, - _topics: &[B256], - _data: &Bytes, - ) { - } - - fn step_end(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { if self.step_fn.is_none() { return; } if matches!(interp.instruction_result, return_revert!()) { - let (db, _db_guard) = EvmDbRef::new(&data.journaled_state.state, &*data.db); + let (db, _db_guard) = EvmDbRef::new(&context.journaled_state.state, &context.db); let (stack, _stack_guard) = StackRef::new(&interp.stack); - let (memory, _memory_guard) = MemoryRef::new(interp.shared_memory); + let (memory, _memory_guard) = MemoryRef::new(&interp.shared_memory); let step = StepLog { stack, op: interp.current_opcode().into(), @@ -428,7 +420,7 @@ where pc: interp.program_counter() as u64, gas_remaining: interp.gas.remaining(), cost: interp.gas.spend(), - depth: data.journaled_state.depth(), + depth: context.journaled_state.depth(), refund: interp.gas.refunded() as u64, error: Some(format!("{:?}", interp.instruction_result)), contract: self.active_call().contract.clone(), @@ -438,12 +430,14 @@ where } } + fn log(&mut self, _context: &mut EvmContext, _log: &Log) {} + fn call( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes) { - self.register_precompiles(&data.precompiles); + ) -> Option { + self.register_precompiles(&context.precompiles); // determine correct `from` and `to` based on the call scheme let (from, to) = match inputs.context.scheme { @@ -470,44 +464,45 @@ where kind: call.kind, gas: inputs.gas_limit, }; - if let Err(err) = self.try_enter(frame) { - return (InstructionResult::Revert, Gas::new(0), err.to_string().into()); + if let Err(_err) = self.try_enter(frame) { + todo!("return revert") + // return (InstructionResult::Revert, Gas::new(0), err.to_string().into()); } } - (InstructionResult::Continue, Gas::new(0), Bytes::new()) + None } fn call_end( &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &CallInputs, - remaining_gas: Gas, - ret: InstructionResult, - out: Bytes, - ) -> (InstructionResult, Gas, Bytes) { + _context: &mut EvmContext, + mut result: InterpreterResult, + ) -> InterpreterResult { if self.can_call_exit() { - let frame_result = - FrameResult { gas_used: remaining_gas.spend(), output: out.clone(), error: None }; + let frame_result = FrameResult { + gas_used: result.gas.spend(), + output: result.output.clone(), + error: None, + }; if let Err(err) = self.try_exit(frame_result) { - return (InstructionResult::Revert, Gas::new(0), err.to_string().into()); + result = js_error_to_revert(err); } } self.pop_call(); - (ret, remaining_gas, out) + result } fn create( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CreateInputs, - ) -> (InstructionResult, Option
, Gas, Bytes) { - self.register_precompiles(&data.precompiles); + ) -> Option { + self.register_precompiles(&context.precompiles); - let _ = data.journaled_state.load_account(inputs.caller, data.db); - let nonce = data.journaled_state.account(inputs.caller).info.nonce; + let _ = context.load_account(inputs.caller); + let nonce = context.journaled_state.account(inputs.caller).info.nonce; let address = inputs.created_address(nonce); self.push_call( address, @@ -523,33 +518,33 @@ where let frame = CallFrame { contract: call.contract.clone(), kind: call.kind, gas: call.gas_limit }; if let Err(err) = self.try_enter(frame) { - return (InstructionResult::Revert, None, Gas::new(0), err.to_string().into()); + return Some(CreateOutcome::new(js_error_to_revert(err), None)); } } - (InstructionResult::Continue, None, Gas::new(inputs.gas_limit), Bytes::default()) + None } fn create_end( &mut self, - _data: &mut EVMData<'_, DB>, - _inputs: &CreateInputs, - ret: InstructionResult, + _context: &mut EvmContext, + mut result: InterpreterResult, address: Option
, - remaining_gas: Gas, - out: Bytes, - ) -> (InstructionResult, Option
, Gas, Bytes) { + ) -> CreateOutcome { if self.can_call_exit() { - let frame_result = - FrameResult { gas_used: remaining_gas.spend(), output: out.clone(), error: None }; + let frame_result = FrameResult { + gas_used: result.gas.spend(), + output: result.output.clone(), + error: None, + }; if let Err(err) = self.try_exit(frame_result) { - return (InstructionResult::Revert, None, Gas::new(0), err.to_string().into()); + result = js_error_to_revert(err); } } self.pop_call(); - (ret, address, remaining_gas, out) + CreateOutcome::new(result, address) } fn selfdestruct(&mut self, _contract: Address, _target: Address, _value: U256) { @@ -652,6 +647,16 @@ pub enum JsInspectorError { InvalidJsonConfig(JsError), } +/// Converts a JavaScript error into a [InstructionResult::Revert] [InterpreterResult]. +#[inline] +fn js_error_to_revert(err: JsError) -> InterpreterResult { + InterpreterResult { + result: InstructionResult::Revert, + output: err.to_string().into(), + gas: Gas::new(0), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 8ada81ca..4be24be3 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -6,15 +6,15 @@ use crate::tracing::{ }, utils::gas_used, }; -use alloy_primitives::{Address, Bytes, LogData, B256, U256}; +use alloy_primitives::{Address, Bytes, Log, U256}; use revm::{ inspectors::GasInspector, interpreter::{ - opcode, return_ok, CallInputs, CallScheme, CreateInputs, Gas, InstructionResult, - Interpreter, OpCode, + opcode, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, + InstructionResult, Interpreter, InterpreterResult, OpCode, }, primitives::SpecId, - Database, EVMData, Inspector, JournalEntry, + Database, EvmContext, Inspector, JournalEntry, }; use types::{CallTrace, CallTraceStep}; @@ -142,11 +142,11 @@ impl TracingInspector { #[inline] fn is_precompile_call( &self, - data: &EVMData<'_, DB>, + context: &EvmContext, to: &Address, value: U256, ) -> bool { - if data.precompiles.contains(to) { + if context.precompiles.contains(to) { // only if this is _not_ the root call return self.is_deep() && value.is_zero(); } @@ -192,7 +192,7 @@ impl TracingInspector { #[allow(clippy::too_many_arguments)] fn start_trace_on_call( &mut self, - data: &EVMData<'_, DB>, + context: &EvmContext, address: Address, input_data: Bytes, value: U256, @@ -215,18 +215,18 @@ impl TracingInspector { // because initialization costs are already subtracted from gas_limit // For the root call this value should use the transaction's gas limit // See and - gas_limit = data.env.tx.gas_limit; + gas_limit = context.env.tx.gas_limit; // we set the spec id here because we only need to do this once and this condition is // hit exactly once - self.spec_id = Some(data.env.cfg.spec_id); + self.spec_id = Some(context.spec_id()); } self.trace_stack.push(self.traces.push_trace( 0, push_kind, CallTrace { - depth: data.journaled_state.depth() as usize, + depth: context.journaled_state.depth() as usize, address, kind, data: input_data, @@ -249,25 +249,26 @@ impl TracingInspector { /// This expects an existing trace [Self::start_trace_on_call] fn fill_trace_on_call_end( &mut self, - data: &EVMData<'_, DB>, - status: InstructionResult, - gas: &Gas, - output: Bytes, + context: &mut EvmContext, + result: InterpreterResult, created_address: Option
, ) { + let InterpreterResult { result, output, gas } = result; + let trace_idx = self.pop_trace_idx(); let trace = &mut self.traces.arena[trace_idx].trace; if trace_idx == 0 { // this is the root call which should get the gas used of the transaction // refunds are applied after execution, which is when the root call ends - trace.gas_used = gas_used(data.env.cfg.spec_id, gas.spend(), gas.refunded() as u64); + trace.gas_used = + gas_used(context.spec_id(), gas.spend(), gas.refunded() as u64); } else { trace.gas_used = gas.spend(); } - trace.status = status; - trace.success = matches!(status, return_ok!()); + trace.status = result; + trace.success = trace.status.is_ok(); trace.output = output.clone(); self.last_call_return_data = Some(output); @@ -286,7 +287,7 @@ impl TracingInspector { /// /// This expects an existing [CallTrace], in other words, this panics if not within the context /// of a call. - fn start_step(&mut self, interp: &Interpreter<'_>, data: &EVMData<'_, DB>) { + fn start_step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { let trace_idx = self.last_trace_idx(); let trace = &mut self.traces.arena[trace_idx]; @@ -314,7 +315,7 @@ impl TracingInspector { .expect("is valid opcode;"); trace.trace.steps.push(CallTraceStep { - depth: data.journaled_state.depth(), + depth: context.journaled_state.depth(), pc: interp.program_counter(), op, contract: interp.contract.address, @@ -337,8 +338,8 @@ impl TracingInspector { /// Invoked on [Inspector::step_end]. fn fill_step_on_step_end( &mut self, - interp: &Interpreter<'_>, - data: &EVMData<'_, DB>, + interp: &Interpreter, + context: &EvmContext, ) { let StackStep { trace_idx, step_idx } = self.step_stack.pop().expect("can't fill step without starting a step first"); @@ -359,7 +360,7 @@ impl TracingInspector { if self.config.record_state_diff { let op = step.op.get(); - let journal_entry = data + let journal_entry = context .journaled_state .journal .last() @@ -374,7 +375,7 @@ impl TracingInspector { Some(JournalEntry::StorageChange { address, key, had_value }), ) => { // SAFETY: (Address,key) exists if part if StorageChange - let value = data.journaled_state.state[address].storage[key].present_value(); + let value = context.journaled_state.state[address].storage[key].present_value(); let reason = match op { opcode::SLOAD => StorageChangeReason::SLOAD, opcode::SSTORE => StorageChangeReason::SSTORE, @@ -400,48 +401,43 @@ impl Inspector for TracingInspector where DB: Database, { - fn initialize_interp(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { - self.gas_inspector.initialize_interp(interp, data) + #[inline] + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + self.gas_inspector.initialize_interp(interp, context) } - fn step(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { + fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { if self.config.record_steps { - self.gas_inspector.step(interp, data); - self.start_step(interp, data); + self.gas_inspector.step(interp, context); + self.start_step(interp, context); } } - fn log( - &mut self, - evm_data: &mut EVMData<'_, DB>, - address: &Address, - topics: &[B256], - data: &Bytes, - ) { - self.gas_inspector.log(evm_data, address, topics, data); + fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + if self.config.record_steps { + self.gas_inspector.step_end(interp, context); + self.fill_step_on_step_end(interp, context); + } + } + + fn log(&mut self, context: &mut EvmContext, log: &Log) { + self.gas_inspector.log(context, log); let trace_idx = self.last_trace_idx(); let trace = &mut self.traces.arena[trace_idx]; if self.config.record_logs { trace.ordering.push(LogCallOrder::Log(trace.logs.len())); - trace.logs.push(LogData::new_unchecked(topics.to_vec(), data.clone())); - } - } - - fn step_end(&mut self, interp: &mut Interpreter<'_>, data: &mut EVMData<'_, DB>) { - if self.config.record_steps { - self.gas_inspector.step_end(interp, data); - self.fill_step_on_step_end(interp, data); + trace.logs.push(log.data.clone()); } } fn call( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CallInputs, - ) -> (InstructionResult, Gas, Bytes) { - self.gas_inspector.call(data, inputs); + ) -> Option { + self.gas_inspector.call(context, inputs); // determine correct `from` and `to` based on the call scheme let (from, to) = match inputs.context.scheme { @@ -463,11 +459,13 @@ where }; // if calls to precompiles should be excluded, check whether this is a call to a precompile - let maybe_precompile = - self.config.exclude_precompile_calls.then(|| self.is_precompile_call(data, &to, value)); + let maybe_precompile = self + .config + .exclude_precompile_calls + .then(|| self.is_precompile_call(context, &to, value)); self.start_trace_on_call( - data, + context, to, inputs.input.clone(), value, @@ -477,35 +475,32 @@ where maybe_precompile, ); - (InstructionResult::Continue, Gas::new(0), Bytes::new()) + None } fn call_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CallInputs, - gas: Gas, - ret: InstructionResult, - out: Bytes, - ) -> (InstructionResult, Gas, Bytes) { - self.gas_inspector.call_end(data, inputs, gas, ret, out.clone()); + context: &mut EvmContext, + result: InterpreterResult, + ) -> InterpreterResult { + self.gas_inspector.call_end(context, result.clone()); - self.fill_trace_on_call_end(data, ret, &gas, out.clone(), None); + self.fill_trace_on_call_end(context, result.clone(), None); - (ret, gas, out) + result } fn create( &mut self, - data: &mut EVMData<'_, DB>, + context: &mut EvmContext, inputs: &mut CreateInputs, - ) -> (InstructionResult, Option
, Gas, Bytes) { - self.gas_inspector.create(data, inputs); + ) -> Option { + self.gas_inspector.create(context, inputs); - let _ = data.journaled_state.load_account(inputs.caller, data.db); - let nonce = data.journaled_state.account(inputs.caller).info.nonce; + let _ = context.load_account(inputs.caller); + let nonce = context.journaled_state.account(inputs.caller).info.nonce; self.start_trace_on_call( - data, + context, inputs.created_address(nonce), inputs.init_code.clone(), inputs.value, @@ -515,7 +510,7 @@ where Some(false), ); - (InstructionResult::Continue, None, Gas::new(inputs.gas_limit), Bytes::default()) + None } /// Called when a contract has been created. @@ -524,19 +519,17 @@ where /// remaining_gas, address, out)`) will alter the result of the create. fn create_end( &mut self, - data: &mut EVMData<'_, DB>, - inputs: &CreateInputs, - status: InstructionResult, + context: &mut EvmContext, + result: InterpreterResult, address: Option
, - gas: Gas, - retdata: Bytes, - ) -> (InstructionResult, Option
, Gas, Bytes) { - self.gas_inspector.create_end(data, inputs, status, address, gas, retdata.clone()); + ) -> CreateOutcome { + self.gas_inspector.create_end(context, result.clone(), address); // get the code of the created contract - let code = address + let _code = address .and_then(|address| { - data.journaled_state + context + .journaled_state .account(address) .info .code @@ -545,9 +538,9 @@ where }) .unwrap_or_default(); - self.fill_trace_on_call_end(data, status, &gas, code.into(), address); + self.fill_trace_on_call_end(context, result.clone(), address); - (status, address, gas, retdata) + CreateOutcome::new(result, address) } fn selfdestruct(&mut self, _contract: Address, target: Address, _value: U256) { diff --git a/src/tracing/opcount.rs b/src/tracing/opcount.rs index 9f3bcd7f..c379836f 100644 --- a/src/tracing/opcount.rs +++ b/src/tracing/opcount.rs @@ -2,7 +2,7 @@ //! //! See also -use revm::{interpreter::Interpreter, Database, EVMData, Inspector}; +use revm::{interpreter::Interpreter, Database, EvmContext, Inspector}; /// An inspector that counts all opcodes. #[derive(Debug, Clone, Copy, Default)] @@ -23,7 +23,7 @@ impl Inspector for OpcodeCountInspector where DB: Database, { - fn step(&mut self, _interp: &mut Interpreter<'_>, _data: &mut EVMData<'_, DB>) { + fn step(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext) { self.count += 1; } } diff --git a/src/tracing/types.rs b/src/tracing/types.rs index 247679ea..8487ede5 100644 --- a/src/tracing/types.rs +++ b/src/tracing/types.rs @@ -3,7 +3,6 @@ use crate::tracing::{config::TraceStyle, utils, utils::convert_memory}; pub use alloy_primitives::Log; use alloy_primitives::{Address, Bytes, LogData, U256, U64}; - use alloy_rpc_trace_types::{ geth::{CallFrame, CallLogFrame, GethDefaultTracingOptions, StructLog}, parity::{ @@ -60,7 +59,7 @@ pub struct CallTrace { impl CallTrace { /// Returns true if the status code is an error or revert, See [InstructionResult::Revert] #[inline] - pub fn is_error(&self) -> bool { + pub const fn is_error(&self) -> bool { !self.status.is_ok() } From 751a75e6e9dfe1c649e4f9514c1a8c9644b54ca2 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 22 Jan 2024 13:20:12 +0100 Subject: [PATCH 2/9] rustfmt --- src/tracing/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 4be24be3..c860aab7 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -261,8 +261,7 @@ impl TracingInspector { if trace_idx == 0 { // this is the root call which should get the gas used of the transaction // refunds are applied after execution, which is when the root call ends - trace.gas_used = - gas_used(context.spec_id(), gas.spend(), gas.refunded() as u64); + trace.gas_used = gas_used(context.spec_id(), gas.spend(), gas.refunded() as u64); } else { trace.gas_used = gas.spend(); } From 984c48ad922f8ec3ae9fe235684eb3f5d7af6d01 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 22 Jan 2024 13:22:05 +0100 Subject: [PATCH 3/9] docs: fix docs --- src/stack/mod.rs | 5 +++-- src/tracing/mod.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/stack/mod.rs b/src/stack/mod.rs index 4024ba85..0f18f2f7 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -32,8 +32,9 @@ pub enum Hook { /// An inspector that calls multiple inspectors in sequence. /// -/// If a call to an inspector returns a value other than [InstructionResult::Continue] (or -/// equivalent) the remaining inspectors are not called. +/// If a call to an inspector returns a value other than +/// [revm::interpreter::InstructionResult::Continue] (or equivalent) the remaining inspectors are +/// not called. #[derive(Default, Clone)] pub struct InspectorStack { /// An inspector that prints the opcode traces to the console. diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index c860aab7..f98b6260 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -40,7 +40,7 @@ pub mod js; /// An inspector that collects call traces. /// -/// This [Inspector] can be hooked into the [EVM](revm::EVM) which then calls the inspector +/// This [Inspector] can be hooked into revm's EVM which then calls the inspector /// functions, such as [Inspector::call] or [Inspector::call_end]. /// /// The [TracingInspector] keeps track of everything by: From 223a896067e4dd151431fbdf93db57034c192c98 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 22 Jan 2024 14:26:40 +0100 Subject: [PATCH 4/9] chore: order fns --- src/stack/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stack/mod.rs b/src/stack/mod.rs index 0f18f2f7..ca86933f 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -115,15 +115,15 @@ where }); } - fn log(&mut self, context: &mut EvmContext, log: &Log) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.log(context, log); + inspector.step_end(interp, context); }); } - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn log(&mut self, context: &mut EvmContext, log: &Log) { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - inspector.step_end(interp, context); + inspector.log(context, log); }); } From a8a33c2df9d0c78a4eab5f8091de372d16a031d2 Mon Sep 17 00:00:00 2001 From: rakita Date: Tue, 30 Jan 2024 15:37:39 +0100 Subject: [PATCH 5/9] Migrate to new revm --- Cargo.toml | 8 +++++--- src/stack/maybe_owned.rs | 29 +++++++++++++++++------------ src/stack/mod.rs | 34 +++++++++++++++------------------- src/tracing/fourbyte.rs | 3 ++- src/tracing/js/mod.rs | 28 ++++++++++++++++------------ src/tracing/mod.rs | 29 +++++++++++++++++------------ 6 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c0fe8c21..fe154001 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Revm inspector implementations" version = "0.1.0" edition = "2021" rust-version = "1.74.0" -license = "MIT OR Apache-2.0" +license = "MIT or Apache-2.0" homepage = "https://github.com/paradigmxyz/evm-inspectors" repository = "https://github.com/paradigmxyz/evm-inspectors" categories = ["cryptography"] @@ -25,8 +25,10 @@ alloy-primitives = "0.6" alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy" } alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy" } -# revm = "3.4" -revm = { git = "https://github.com/bluealloy/revm", default-features = false, features = ["std"] } +# revm = "4.0" +revm = { git = "https://github.com/bluealloy/revm", branch = "tweeks", default-features = false, features = [ + "std", +] } # js-tracing-inspector boa_engine = { version = "0.17", optional = true } diff --git a/src/stack/maybe_owned.rs b/src/stack/maybe_owned.rs index 9f50a16b..4f2535b6 100644 --- a/src/stack/maybe_owned.rs +++ b/src/stack/maybe_owned.rs @@ -1,13 +1,12 @@ use alloy_primitives::{Log, U256}; use revm::{ - interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, - }, + interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter}, primitives::{db::Database, Address}, EvmContext, Inspector, }; use std::{ cell::{Ref, RefCell}, + ops::Range, rc::Rc, }; @@ -105,9 +104,12 @@ where &mut self, context: &mut EvmContext, inputs: &mut CallInputs, + return_memory_offset: Range, ) -> Option { match self { - MaybeOwnedInspector::Owned(insp) => return insp.borrow_mut().call(context, inputs), + MaybeOwnedInspector::Owned(insp) => { + return insp.borrow_mut().call(context, inputs, return_memory_offset) + } MaybeOwnedInspector::Stacked(_) => None, } } @@ -115,11 +117,14 @@ where fn call_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - ) -> InterpreterResult { + inputs: &CallInputs, + outcome: CallOutcome, + ) -> CallOutcome { match self { - MaybeOwnedInspector::Owned(insp) => insp.borrow_mut().call_end(context, result), - MaybeOwnedInspector::Stacked(_) => result, + MaybeOwnedInspector::Owned(insp) => { + insp.borrow_mut().call_end(context, inputs, outcome) + } + MaybeOwnedInspector::Stacked(_) => outcome, } } @@ -137,14 +142,14 @@ where fn create_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - address: Option
, + inputs: &CreateInputs, + outcome: CreateOutcome, ) -> CreateOutcome { match self { MaybeOwnedInspector::Owned(insp) => { - return insp.borrow_mut().create_end(context, result, address) + return insp.borrow_mut().create_end(context, inputs, outcome) } - MaybeOwnedInspector::Stacked(_) => CreateOutcome::new(result, address), + MaybeOwnedInspector::Stacked(_) => outcome, } } diff --git a/src/stack/mod.rs b/src/stack/mod.rs index ca86933f..aa241f17 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -1,13 +1,11 @@ use alloy_primitives::{Address, Log, B256, U256}; use revm::{ inspectors::CustomPrintTracer, - interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult, - }, + interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter}, primitives::Env, Database, EvmContext, Inspector, }; -use std::fmt::Debug; +use std::{fmt::Debug, ops::Range}; /// A wrapped [Inspector] that can be reused in the stack mod maybe_owned; @@ -131,9 +129,10 @@ where &mut self, context: &mut EvmContext, inputs: &mut CallInputs, + return_memory_offset: Range, ) -> Option { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - if let Some(outcome) = inspector.call(context, inputs) { + if let Some(outcome) = inspector.call(context, inputs, return_memory_offset) { return Some(outcome); } }); @@ -144,21 +143,20 @@ where fn call_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - ) -> InterpreterResult { + inputs: &CallInputs, + outcome: CallOutcome, + ) -> CallOutcome { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let new_ret = inspector.call_end(context, result.clone()); + let new_ret = inspector.call_end(context, inputs, outcome.clone()); // If the inspector returns a different ret or a revert with a non-empty message, // we assume it wants to tell us something - if new_ret.result != result.result - || (new_ret.result.is_revert() && new_ret.output != result.output) - { + if new_ret != outcome { return new_ret; } }); - result + outcome } fn create( @@ -178,22 +176,20 @@ where fn create_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - address: Option
, + inputs: &CreateInputs, + outcome: CreateOutcome, ) -> CreateOutcome { call_inspectors!(inspector, [&mut self.custom_print_tracer], { - let new_ret = inspector.create_end(context, result.clone(), address); + let new_ret = inspector.create_end(context, inputs, outcome.clone()); // If the inspector returns a different ret or a revert with a non-empty message, // we assume it wants to tell us something - if new_ret.result.result != result.result - || (new_ret.result.result.is_revert() && new_ret.result.output != result.output) - { + if new_ret != outcome { return new_ret; } }); - CreateOutcome::new(result, address) + outcome } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index a54134e6..7893bc1d 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -27,7 +27,7 @@ use revm::{ interpreter::{CallInputs, CallOutcome}, Database, EvmContext, Inspector, }; -use std::collections::HashMap; +use std::{collections::HashMap, ops::Range}; /// Fourbyte tracing inspector that records all function selectors and their calldata sizes. #[derive(Debug, Clone, Default)] @@ -51,6 +51,7 @@ where &mut self, _context: &mut EvmContext, inputs: &mut CallInputs, + _return_memory_offset: Range, ) -> Option { if inputs.input.len() >= 4 { let selector = diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 682c250a..3047d628 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -1,5 +1,7 @@ //! Javascript inspector +use std::ops::Range; + use crate::tracing::{ js::{ bindings::{ @@ -436,6 +438,7 @@ where &mut self, context: &mut EvmContext, inputs: &mut CallInputs, + _return_memory_offset: Range, ) -> Option { self.register_precompiles(&context.precompiles); @@ -476,22 +479,23 @@ where fn call_end( &mut self, _context: &mut EvmContext, - mut result: InterpreterResult, - ) -> InterpreterResult { + _inputs: &CallInputs, + mut outcome: CallOutcome, + ) -> CallOutcome { if self.can_call_exit() { let frame_result = FrameResult { - gas_used: result.gas.spend(), - output: result.output.clone(), + gas_used: outcome.result.gas.spend(), + output: outcome.result.output.clone(), error: None, }; if let Err(err) = self.try_exit(frame_result) { - result = js_error_to_revert(err); + outcome.result = js_error_to_revert(err); } } self.pop_call(); - result + outcome } fn create( @@ -528,23 +532,23 @@ where fn create_end( &mut self, _context: &mut EvmContext, - mut result: InterpreterResult, - address: Option
, + _inputs: &CreateInputs, + mut outcome: CreateOutcome, ) -> CreateOutcome { if self.can_call_exit() { let frame_result = FrameResult { - gas_used: result.gas.spend(), - output: result.output.clone(), + gas_used: outcome.result.gas.spend(), + output: outcome.result.output.clone(), error: None, }; if let Err(err) = self.try_exit(frame_result) { - result = js_error_to_revert(err); + outcome.result = js_error_to_revert(err); } } self.pop_call(); - CreateOutcome::new(result, address) + outcome } fn selfdestruct(&mut self, _contract: Address, _target: Address, _value: U256) { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index f98b6260..52788944 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + use self::parity::stack_push_count; use crate::tracing::{ arena::PushTraceKind, @@ -435,8 +437,9 @@ where &mut self, context: &mut EvmContext, inputs: &mut CallInputs, + return_memory_offset: Range, ) -> Option { - self.gas_inspector.call(context, inputs); + self.gas_inspector.call(context, inputs, return_memory_offset); // determine correct `from` and `to` based on the call scheme let (from, to) = match inputs.context.scheme { @@ -480,13 +483,14 @@ where fn call_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - ) -> InterpreterResult { - self.gas_inspector.call_end(context, result.clone()); + inputs: &CallInputs, + outcome: CallOutcome, + ) -> CallOutcome { + let outcome = self.gas_inspector.call_end(context, inputs, outcome); - self.fill_trace_on_call_end(context, result.clone(), None); + self.fill_trace_on_call_end(context, outcome.result.clone(), None); - result + outcome } fn create( @@ -519,13 +523,14 @@ where fn create_end( &mut self, context: &mut EvmContext, - result: InterpreterResult, - address: Option
, + inputs: &CreateInputs, + outcome: CreateOutcome, ) -> CreateOutcome { - self.gas_inspector.create_end(context, result.clone(), address); + let outcome = self.gas_inspector.create_end(context, inputs, outcome); // get the code of the created contract - let _code = address + let _code = outcome + .address .and_then(|address| { context .journaled_state @@ -537,9 +542,9 @@ where }) .unwrap_or_default(); - self.fill_trace_on_call_end(context, result.clone(), address); + self.fill_trace_on_call_end(context, outcome.result.clone(), outcome.address); - CreateOutcome::new(result, address) + outcome } fn selfdestruct(&mut self, _contract: Address, target: Address, _value: U256) { From f0728291da4126652196527ed77c57bae5f840f2 Mon Sep 17 00:00:00 2001 From: rakita Date: Wed, 31 Jan 2024 14:59:53 +0100 Subject: [PATCH 6/9] Impl GetInstector for stack --- src/stack/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/stack/mod.rs b/src/stack/mod.rs index aa241f17..4e7061a3 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -3,7 +3,7 @@ use revm::{ inspectors::CustomPrintTracer, interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter}, primitives::Env, - Database, EvmContext, Inspector, + Database, EvmContext, GetInspector, Inspector, }; use std::{fmt::Debug, ops::Range}; @@ -41,6 +41,12 @@ pub struct InspectorStack { pub hook: Hook, } +impl GetInspector<'_, DB> for InspectorStack { + fn get_inspector(&mut self) -> &mut dyn Inspector { + self + } +} + impl Debug for InspectorStack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("InspectorStack") From 7d7d261302e35d5d50947b22696797b7394b84fc Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 1 Feb 2024 17:30:40 +0100 Subject: [PATCH 7/9] Remove GetInspector --- src/stack/mod.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/stack/mod.rs b/src/stack/mod.rs index 4e7061a3..aa241f17 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -3,7 +3,7 @@ use revm::{ inspectors::CustomPrintTracer, interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter}, primitives::Env, - Database, EvmContext, GetInspector, Inspector, + Database, EvmContext, Inspector, }; use std::{fmt::Debug, ops::Range}; @@ -41,12 +41,6 @@ pub struct InspectorStack { pub hook: Hook, } -impl GetInspector<'_, DB> for InspectorStack { - fn get_inspector(&mut self) -> &mut dyn Inspector { - self - } -} - impl Debug for InspectorStack { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("InspectorStack") From 3a1a17a00293d1b6ac12cc5377e8b66146dbd061 Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 5 Feb 2024 19:50:22 +0100 Subject: [PATCH 8/9] bump revm to main branch --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fe154001..2fc368a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy" } alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy" } # revm = "4.0" -revm = { git = "https://github.com/bluealloy/revm", branch = "tweeks", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm", branch = "main", default-features = false, features = [ "std", ] } From 621ccff547583ea713bd928224289d6263d1d88a Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 5 Feb 2024 19:51:01 +0100 Subject: [PATCH 9/9] licence OR --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2fc368a4..f6d01b0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = "Revm inspector implementations" version = "0.1.0" edition = "2021" rust-version = "1.74.0" -license = "MIT or Apache-2.0" +license = "MIT OR Apache-2.0" homepage = "https://github.com/paradigmxyz/evm-inspectors" repository = "https://github.com/paradigmxyz/evm-inspectors" categories = ["cryptography"]