From dba807913c4b9b1b5677c25cb6bded54515cc654 Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 20 Dec 2024 15:31:42 +0200 Subject: [PATCH 01/15] chore: bump revm dec 2024 --- Cargo.toml | 10 ++- src/access_list.rs | 24 +++--- src/opcode.rs | 99 +++++++++++++++---------- src/tracing/builder/geth.rs | 7 +- src/tracing/builder/parity.rs | 11 ++- src/tracing/config.rs | 2 +- src/tracing/fourbyte.rs | 9 ++- src/tracing/js/mod.rs | 16 ++-- src/tracing/mod.rs | 133 +++++++++++++++++++--------------- src/tracing/mux.rs | 89 ++++++++++++----------- src/tracing/opcount.rs | 10 ++- src/tracing/types.rs | 5 +- src/tracing/utils.rs | 9 +-- src/transfer.rs | 27 +++---- tests/it/geth.rs | 9 +-- tests/it/parity.rs | 10 +-- tests/it/transfer.rs | 10 +-- tests/it/utils.rs | 7 +- 18 files changed, 270 insertions(+), 217 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1bba873..4e32f49c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,12 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { version = "18.0.0", default-features = false, features = ["std"] } +revm = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ + "std", +] } +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ + "std", +] } anstyle = "1.0" colorchoice = "1.0" @@ -50,6 +55,9 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ + "std", +] } [features] serde = ["dep:serde", "revm/serde"] diff --git a/src/access_list.rs b/src/access_list.rs index de86ad68..e44d8bb6 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -1,9 +1,15 @@ use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::{AccessList, AccessListItem}; use revm::{ - interpreter::{opcode, Interpreter}, - Database, EvmContext, Inspector, + bytecode::opcode, + interpreter::{ + interpreter::EthInterpreter, + interpreter_types::{InputsTrait, Jumps}, + Interpreter, + }, + Database, }; +use revm_inspector::{Inspector, PrevContext}; use std::collections::{BTreeSet, HashMap, HashSet}; /// An [Inspector] that collects touched accounts and storage slots. @@ -58,15 +64,15 @@ impl AccessListInspector { } } -impl Inspector for AccessListInspector +impl Inspector, EthInterpreter> for AccessListInspector where DB: Database, { - fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { - match interp.current_opcode() { + fn step(&mut self, interp: &mut Interpreter, _context: &mut PrevContext) { + match interp.bytecode.opcode() { opcode::SLOAD | opcode::SSTORE => { - if let Ok(slot) = interp.stack().peek(0) { - let cur_contract = interp.contract.target_address; + if let Ok(slot) = interp.stack.peek(0) { + let cur_contract = interp.input.target_address(); self.access_list .entry(cur_contract) .or_default() @@ -78,7 +84,7 @@ where | opcode::EXTCODESIZE | opcode::BALANCE | opcode::SELFDESTRUCT => { - if let Ok(slot) = interp.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 +92,7 @@ where } } opcode::DELEGATECALL | opcode::CALL | opcode::STATICCALL | opcode::CALLCODE => { - if let Ok(slot) = interp.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/opcode.rs b/src/opcode.rs index 59de9984..9e53a6c6 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -1,11 +1,14 @@ use alloy_rpc_types_trace::opcode::OpcodeGas; use revm::{ + bytecode::opcode::{self, OpCode}, interpreter::{ - opcode::{self, OpCode}, + interpreter::EthInterpreter, + interpreter_types::{Immediates, Jumps, LoopControl}, Interpreter, }, - Database, EvmContext, Inspector, + Database, }; +use revm_inspector::{Inspector, PrevContext}; use std::collections::HashMap; /// An Inspector that counts opcodes and measures gas usage per opcode. @@ -57,80 +60,88 @@ impl OpcodeGasInspector { } } -impl Inspector for OpcodeGasInspector +impl Inspector, EthInterpreter> for OpcodeGasInspector where DB: Database, { - fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { - let opcode_value = interp.current_opcode(); + fn step(&mut self, interp: &mut Interpreter, _context: &mut PrevContext) { + let opcode_value = interp.bytecode.opcode(); if let Some(opcode) = OpCode::new(opcode_value) { // keep track of opcode counts *self.opcode_counts.entry(opcode).or_default() += 1; // keep track of the last opcode executed - self.last_opcode_gas_remaining = Some((opcode, interp.gas().remaining())); + self.last_opcode_gas_remaining = Some((opcode, interp.control.gas().remaining())); } } - fn step_end(&mut self, interp: &mut Interpreter, _context: &mut EvmContext) { + fn step_end( + &mut self, + interp: &mut Interpreter, + _context: &mut PrevContext, + ) { // update gas usage for the last opcode if let Some((opcode, gas_remaining)) = self.last_opcode_gas_remaining.take() { - let gas_cost = gas_remaining.saturating_sub(interp.gas().remaining()); + let gas_cost = gas_remaining.saturating_sub(interp.control.gas().remaining()); *self.opcode_gas.entry(opcode).or_default() += gas_cost; } } } -/// Accepts [OpCode] and a slice of bytecode immediately after it and returns the size of immediate +/// Accepts Bytecode that implements [Immediates] and returns the size of immediate /// value. /// /// Primarily needed to handle a special case of RJUMPV opcode. -pub fn immediate_size(op: OpCode, bytes_after: &[u8]) -> u8 { - match op.get() { - opcode::RJUMPV => { - if bytes_after.is_empty() { - return 0; - } - 1 + (bytes_after[0] + 1) * 2 - } - _ => op.info().immediate_size(), +pub fn immediate_size(bytecode: &impl Immediates) -> u8 { + let opcode = bytecode.read_u8(); + if opcode == opcode::RJUMPV { + let vtable_size = bytecode.read_slice(2)[2]; + return 1 + (vtable_size + 1) * 2; } + let Some(opcode) = OpCode::new(opcode) else { return 0 }; + opcode.info().immediate_size() } #[cfg(test)] mod tests { use super::*; use revm::{ - db::{CacheDB, EmptyDB}, - interpreter::{opcode, Contract}, + bytecode::Bytecode, + database_interface::EmptyDB, + interpreter::{InputsImpl, SharedMemory}, + primitives::Bytes, + specification::hardfork::SpecId, }; + use revm_database::CacheDB; + use std::{cell::RefCell, rc::Rc}; #[test] fn test_opcode_counter_inspector() { let mut opcode_counter = OpcodeGasInspector::new(); - let contract = Contract::default(); - let mut interpreter = Interpreter::new(contract, 10000, false); - let db = CacheDB::new(EmptyDB::default()); - let opcodes = [ - OpCode::new(opcode::ADD).unwrap(), - OpCode::new(opcode::ADD).unwrap(), - OpCode::new(opcode::ADD).unwrap(), - OpCode::new(opcode::BYTE).unwrap(), - ]; + let opcodes = [opcode::ADD, opcode::ADD, opcode::ADD, opcode::BYTE]; + + let bytecode = Bytecode::new_raw(Bytes::from(opcodes)); + let mut interpreter = Interpreter::::new( + Rc::new(RefCell::new(SharedMemory::new())), + bytecode, + InputsImpl::default(), + false, + false, + SpecId::LATEST, + u64::MAX, + ); + let db = CacheDB::new(EmptyDB::default()); - for &opcode in &opcodes { - interpreter.instruction_pointer = &opcode.get(); - opcode_counter.step(&mut interpreter, &mut EvmContext::new(db.clone())); + for _ in &opcodes { + opcode_counter + .step(&mut interpreter, &mut PrevContext::new(db.clone(), SpecId::BERLIN)); } } #[test] fn test_with_variety_of_opcodes() { let mut opcode_counter = OpcodeGasInspector::new(); - let contract = Contract::default(); - let mut interpreter = Interpreter::new(contract, 2024, false); - let db = CacheDB::new(EmptyDB::default()); let opcodes = [ opcode::PUSH1, @@ -141,9 +152,21 @@ mod tests { opcode::STOP, ]; - for opcode in opcodes.iter() { - interpreter.instruction_pointer = opcode; - opcode_counter.step(&mut interpreter, &mut EvmContext::new(db.clone())); + let bytecode = Bytecode::new_raw(Bytes::from(opcodes)); + let mut interpreter = Interpreter::::new( + Rc::new(RefCell::new(SharedMemory::new())), + bytecode, + InputsImpl::default(), + false, + false, + SpecId::LATEST, + u64::MAX, + ); + let db = CacheDB::new(EmptyDB::default()); + + for _ in opcodes.iter() { + opcode_counter + .step(&mut interpreter, &mut PrevContext::new(db.clone(), SpecId::LATEST)); } } } diff --git a/src/tracing/builder/geth.rs b/src/tracing/builder/geth.rs index 9e7f1e21..027a5084 100644 --- a/src/tracing/builder/geth.rs +++ b/src/tracing/builder/geth.rs @@ -10,8 +10,9 @@ use alloy_rpc_types_trace::geth::{ GethDefaultTracingOptions, PreStateConfig, PreStateFrame, PreStateMode, StructLog, }; use revm::{ - db::DatabaseRef, - primitives::{EvmState, ResultAndState}, + context_interface::result::{HaltReasonTrait, ResultAndState}, + state::EvmState, + DatabaseRef, }; use std::{ borrow::Cow, @@ -216,7 +217,7 @@ impl<'a> GethTraceBuilder<'a> { /// * `db` - The database to fetch state pre-transaction execution. pub fn geth_prestate_traces( &self, - ResultAndState { state, .. }: &ResultAndState, + ResultAndState { state, .. }: &ResultAndState, prestate_config: &PreStateConfig, db: DB, ) -> Result { diff --git a/src/tracing/builder/parity.rs b/src/tracing/builder/parity.rs index 16e1c46b..db28a3a1 100644 --- a/src/tracing/builder/parity.rs +++ b/src/tracing/builder/parity.rs @@ -8,8 +8,11 @@ use alloy_primitives::{map::HashSet, Address, U256, U64}; use alloy_rpc_types_eth::TransactionInfo; use alloy_rpc_types_trace::parity::*; use revm::{ - db::DatabaseRef, - primitives::{Account, ExecutionResult, ResultAndState, SpecId, KECCAK_EMPTY}, + context_interface::result::{ExecutionResult, HaltReasonTrait, ResultAndState}, + primitives::KECCAK_EMPTY, + specification::hardfork::SpecId, + state::Account, + DatabaseRef, }; use std::{collections::VecDeque, iter::Peekable}; @@ -148,7 +151,7 @@ impl ParityTraceBuilder { /// using the [DatabaseRef]. pub fn into_trace_results( self, - res: &ExecutionResult, + res: &ExecutionResult, trace_types: &HashSet, ) -> TraceResults { let output = res.output().cloned().unwrap_or_default(); @@ -169,7 +172,7 @@ impl ParityTraceBuilder { /// with the [TracingInspector](crate::tracing::TracingInspector). pub fn into_trace_results_with_state( self, - res: &ResultAndState, + res: &ResultAndState, trace_types: &HashSet, db: DB, ) -> Result { diff --git a/src/tracing/config.rs b/src/tracing/config.rs index edf5445c..2de47b2b 100644 --- a/src/tracing/config.rs +++ b/src/tracing/config.rs @@ -3,7 +3,7 @@ use alloy_rpc_types_trace::{ geth::{CallConfig, FlatCallConfig, GethDefaultTracingOptions, PreStateConfig}, parity::TraceType, }; -use revm::interpreter::OpCode; +use revm::bytecode::opcode::OpCode; /// 256 bits each marking whether an opcode should be included into steps trace or not. #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index ba5b22e6..82043f66 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -24,9 +24,10 @@ use alloy_primitives::{hex, Selector}; use alloy_rpc_types_trace::geth::FourByteFrame; use revm::{ - interpreter::{CallInputs, CallOutcome}, - Database, EvmContext, Inspector, + interpreter::{interpreter::EthInterpreter, CallInputs, CallOutcome}, + Database, }; +use revm_inspector::{Inspector, PrevContext}; use std::collections::HashMap; /// Fourbyte tracing inspector that records all function selectors and their calldata sizes. @@ -43,13 +44,13 @@ impl FourByteInspector { } } -impl Inspector for FourByteInspector +impl Inspector, EthInterpreter> for FourByteInspector where DB: Database, { fn call( &mut self, - _context: &mut EvmContext, + _context: &mut PrevContext, inputs: &mut CallInputs, ) -> Option { if inputs.input.len() >= 4 { diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index b9c01516..4d39702f 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -385,12 +385,12 @@ impl JsInspector { } } -impl Inspector for JsInspector +impl Inspector, EthInterpreter> for JsInspector where DB: Database + DatabaseRef, ::Error: std::fmt::Display, { - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { if self.step_fn.is_none() { return; } @@ -417,7 +417,7 @@ where } } - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { if self.step_fn.is_none() { return; } @@ -444,11 +444,11 @@ where } } - fn log(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext, _log: &Log) {} + fn log(&mut self, _interp: &mut Interpreter, _context: &mut PrevContext, _log: &Log) {} fn call( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CallInputs, ) -> Option { self.register_precompiles(&context.precompiles); @@ -489,7 +489,7 @@ where fn call_end( &mut self, - _context: &mut EvmContext, + _context: &mut PrevContext, _inputs: &CallInputs, mut outcome: CallOutcome, ) -> CallOutcome { @@ -511,7 +511,7 @@ where fn create( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CreateInputs, ) -> Option { self.register_precompiles(&context.precompiles); @@ -542,7 +542,7 @@ where fn create_end( &mut self, - _context: &mut EvmContext, + _context: &mut PrevContext, _inputs: &CreateInputs, mut outcome: CreateOutcome, ) -> CreateOutcome { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index b75fb9bf..2d79dae9 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -11,13 +11,18 @@ use crate::{ }; use alloy_primitives::{Address, Bytes, Log, B256, U256}; use revm::{ + bytecode::opcode::{self, OpCode}, + context_interface::{Journal, JournalStateGetter}, interpreter::{ - opcode::{self}, + interpreter::EthInterpreter, + interpreter_types::{ + Immediates, InputsTrait, Jumps, LoopControl, ReturnData, RuntimeFlag, SubRoutineStack, + }, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, EOFCreateInputs, - InstructionResult, Interpreter, InterpreterResult, OpCode, + InstructionResult, Interpreter, InterpreterResult, }, - primitives::SpecId, - Database, EvmContext, Inspector, JournalEntry, + specification::hardfork::SpecId, + Database, JournalEntry, }; mod arena; @@ -39,6 +44,7 @@ mod opcount; pub use opcount::OpcodeCountInspector; pub mod types; +use revm_inspector::{Inspector, PrevContext}; use types::{CallLog, CallTrace, CallTraceStep}; mod utils; @@ -235,14 +241,15 @@ impl TracingInspector { #[inline] fn is_precompile_call( &self, - context: &EvmContext, + context: &PrevContext, to: &Address, value: &U256, ) -> bool { - if context.precompiles.contains(to) { - // only if this is _not_ the root call - return self.is_deep() && value.is_zero(); - } + // TODO rakita how to support this? + //if context.precompiles.contains(to) { + // // only if this is _not_ the root call + // return self.is_deep() && value.is_zero(); + //} false } @@ -292,7 +299,7 @@ impl TracingInspector { #[allow(clippy::too_many_arguments)] fn start_trace_on_call( &mut self, - context: &EvmContext, + context: &PrevContext, address: Address, input_data: Bytes, value: U256, @@ -337,7 +344,7 @@ impl TracingInspector { /// This expects an existing trace [Self::start_trace_on_call] fn fill_trace_on_call_end( &mut self, - _context: &mut EvmContext, + _context: &mut PrevContext, result: &InterpreterResult, created_address: Option
, ) { @@ -369,14 +376,18 @@ impl TracingInspector { /// This expects an existing [CallTrace], in other words, this panics if not within the context /// of a call. #[cold] - fn start_step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn start_step( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + ) { let trace_idx = self.last_trace_idx(); let trace = &mut self.traces.arena[trace_idx]; let step_idx = trace.trace.steps.len(); // We always want an OpCode, even it is unknown because it could be an additional opcode // that not a known constant. - let op = unsafe { OpCode::new_unchecked(interp.current_opcode()) }; + let op = unsafe { OpCode::new_unchecked(interp.bytecode.opcode()) }; let record = self.config.should_record_opcode(op); @@ -399,7 +410,7 @@ impl TracingInspector { } } } - RecordedMemory::new(interp.shared_memory.context_memory()) + RecordedMemory::new(interp.memory.borrow().context_memory()) }); let stack = if self.config.record_stack_snapshots.is_all() @@ -412,34 +423,36 @@ impl TracingInspector { let returndata = self .config .record_returndata_snapshots - .then(|| interp.return_data_buffer.clone()) + .then(|| interp.return_data.buffer().to_vec().into()) .unwrap_or_default(); - let gas_used = - gas_used(context.spec_id(), interp.gas.spent(), interp.gas.refunded() as u64); + let gas_used = gas_used( + interp.runtime_flag.spec_id(), + interp.control.gas.spent(), + interp.control.gas.refunded() as u64, + ); - let immediate_bytes = if self.config.record_immediate_bytes { - let pc = interp.program_counter(); - let size = immediate_size(op, &interp.bytecode[pc + 1..]); - let start = pc + 1; - let end = pc + 1 + size as usize; - (size > 0 && end <= interp.bytecode.len()).then(|| interp.bytecode.slice(start..end)) - } else { - None - }; + let mut immediate_bytes = None; + if self.config.record_immediate_bytes { + let size = immediate_size(&interp.bytecode); + if size != 0 { + immediate_bytes = + Some(interp.bytecode.read_slice(size as usize + 1)[1..].to_vec().into()); + } + } trace.trace.steps.push(CallTraceStep { - depth: context.journaled_state.depth(), - pc: interp.program_counter(), - code_section_idx: interp.function_stack.current_code_idx, + depth: context.journaled_state.depth() as u64, + pc: interp.bytecode.pc(), + code_section_idx: interp.sub_routine.routine_idx(), op, - contract: interp.contract.target_address, + contract: interp.input.target_address(), stack, push_stack: None, memory, returndata, - gas_remaining: interp.gas.remaining(), - gas_refund_counter: interp.gas.refunded() as u64, + gas_remaining: interp.control.gas().remaining(), + gas_refund_counter: interp.control.gas().refunded() as u64, gas_used, decoded: None, immediate_bytes, @@ -459,8 +472,8 @@ impl TracingInspector { #[cold] fn fill_step_on_step_end( &mut self, - interp: &mut Interpreter, - context: &mut EvmContext, + interp: &mut Interpreter, + context: &mut PrevContext, ) { let StackStep { trace_idx, step_idx, record } = self.step_stack.pop().expect("can't fill step without starting a step first"); @@ -513,32 +526,41 @@ impl TracingInspector { // The gas cost is the difference between the recorded gas remaining at the start of the // step the remaining gas here, at the end of the step. // TODO: Figure out why this can overflow. https://github.com/paradigmxyz/revm-inspectors/pull/38 - step.gas_cost = step.gas_remaining.saturating_sub(interp.gas.remaining()); + step.gas_cost = step.gas_remaining.saturating_sub(interp.control.gas().remaining()); // set the status - step.status = interp.instruction_result; + step.status = interp.control.instruction_result(); } } -impl Inspector for TracingInspector +impl Inspector, EthInterpreter> for TracingInspector where DB: Database, { #[inline] - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { if self.config.record_steps { self.start_step(interp, context); } } #[inline] - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step_end( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + ) { if self.config.record_steps { self.fill_step_on_step_end(interp, context); } } - fn log(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext, log: &Log) { + fn log( + &mut self, + _interp: &mut Interpreter, + _context: &mut PrevContext, + log: &Log, + ) { if self.config.record_logs { let trace = self.last_trace(); trace.ordering.push(TraceMemberOrder::Log(trace.logs.len())); @@ -548,7 +570,7 @@ where fn call( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CallInputs, ) -> Option { // determine correct `from` and `to` based on the call scheme @@ -593,20 +615,19 @@ where fn call_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, _inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { + outcome: &mut CallOutcome, + ) { self.fill_trace_on_call_end(context, &outcome.result, None); - outcome } fn create( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CreateInputs, ) -> Option { - let _ = context.load_account(inputs.caller); + let _ = context.journal().load_account(inputs.caller); let nonce = context.journaled_state.account(inputs.caller).info.nonce; self.start_trace_on_call( context, @@ -624,23 +645,22 @@ where fn create_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, _inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { self.fill_trace_on_call_end(context, &outcome.result, outcome.address); - outcome } fn eofcreate( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut EOFCreateInputs, ) -> Option { let address = if let Some(address) = inputs.kind.created_address() { *address } else { - let _ = context.load_account(inputs.caller); + let _ = context.journal().load_account(inputs.caller); let nonce = context.journaled_state.account(inputs.caller).info.nonce; inputs.caller.create(nonce) }; @@ -660,12 +680,11 @@ where fn eofcreate_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, _inputs: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { self.fill_trace_on_call_end(context, &outcome.result, outcome.address); - outcome } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { diff --git a/src/tracing/mux.rs b/src/tracing/mux.rs index 481b0ddf..5f4f67a9 100644 --- a/src/tracing/mux.rs +++ b/src/tracing/mux.rs @@ -7,12 +7,14 @@ use alloy_rpc_types_trace::geth::{ PreStateConfig, }; use revm::{ + context_interface::result::{HaltReasonTrait, ResultAndState}, interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, Interpreter, + interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, + EOFCreateInputs, Interpreter, }, - primitives::ResultAndState, - Database, DatabaseRef, EvmContext, Inspector, + Database, DatabaseRef, }; +use revm_inspector::{Inspector, PrevContext}; use thiserror::Error; /// Mux tracing inspector that runs and collects results of multiple inspectors at once. @@ -98,7 +100,7 @@ impl MuxInspector { /// Try converting this [MuxInspector] into a [MuxFrame]. pub fn try_into_mux_frame( &self, - result: &ResultAndState, + result: &ResultAndState, db: &DB, tx_info: TransactionInfo, ) -> Result { @@ -155,12 +157,16 @@ impl MuxInspector { } } -impl Inspector for MuxInspector +impl Inspector, EthInterpreter> for MuxInspector where DB: Database, { #[inline] - fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn initialize_interp( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + ) { if let Some(ref mut inspector) = self.four_byte { inspector.initialize_interp(interp, context); } @@ -170,7 +176,7 @@ where } #[inline] - fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { if let Some(ref mut inspector) = self.four_byte { inspector.step(interp, context); } @@ -180,7 +186,11 @@ where } #[inline] - fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext) { + fn step_end( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + ) { if let Some(ref mut inspector) = self.four_byte { inspector.step_end(interp, context); } @@ -190,7 +200,12 @@ where } #[inline] - fn log(&mut self, interp: &mut Interpreter, context: &mut EvmContext, log: &Log) { + fn log( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + log: &Log, + ) { if let Some(ref mut inspector) = self.four_byte { inspector.log(interp, context, log); } @@ -202,7 +217,7 @@ where #[inline] fn call( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CallInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -217,26 +232,22 @@ where #[inline] fn call_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &CallInputs, - outcome: CallOutcome, - ) -> CallOutcome { - let mut outcome = outcome; - + outcome: &mut CallOutcome, + ) { if let Some(ref mut inspector) = self.four_byte { - outcome = inspector.call_end(context, inputs, outcome); + inspector.call_end(context, inputs, outcome); } if let Some(ref mut inspector) = self.tracing { - outcome = inspector.call_end(context, inputs, outcome); + inspector.call_end(context, inputs, outcome); } - - outcome } #[inline] fn create( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CreateInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -251,26 +262,22 @@ where #[inline] fn create_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &CreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - let mut outcome = outcome; - + outcome: &mut CreateOutcome, + ) { if let Some(ref mut inspector) = self.four_byte { - outcome = inspector.create_end(context, inputs, outcome); + inspector.create_end(context, inputs, outcome); } if let Some(ref mut inspector) = self.tracing { - outcome = inspector.create_end(context, inputs, outcome); + inspector.create_end(context, inputs, outcome); } - - outcome } #[inline] fn eofcreate( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut EOFCreateInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -285,29 +292,29 @@ where #[inline] fn eofcreate_end( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &EOFCreateInputs, - outcome: CreateOutcome, - ) -> CreateOutcome { - let mut outcome = outcome; - + outcome: &mut CreateOutcome, + ) { if let Some(ref mut inspector) = self.four_byte { - outcome = inspector.eofcreate_end(context, inputs, outcome); + inspector.eofcreate_end(context, inputs, outcome); } if let Some(ref mut inspector) = self.tracing { - outcome = inspector.eofcreate_end(context, inputs, outcome); + inspector.eofcreate_end(context, inputs, outcome); } - - outcome } #[inline] fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { if let Some(ref mut inspector) = self.four_byte { - >::selfdestruct(inspector, contract, target, value); + , EthInterpreter>>::selfdestruct( + inspector, contract, target, value, + ); } if let Some(ref mut inspector) = self.tracing { - >::selfdestruct(inspector, contract, target, value); + , EthInterpreter>>::selfdestruct( + inspector, contract, target, value, + ); } } } diff --git a/src/tracing/opcount.rs b/src/tracing/opcount.rs index 99c50b53..c7a11a93 100644 --- a/src/tracing/opcount.rs +++ b/src/tracing/opcount.rs @@ -2,7 +2,11 @@ //! //! See also -use revm::{interpreter::Interpreter, Database, EvmContext, Inspector}; +use revm::{ + interpreter::{interpreter::EthInterpreter, Interpreter}, + Database, +}; +use revm_inspector::{Inspector, PrevContext}; /// An inspector that counts all opcodes. #[derive(Clone, Copy, Debug, Default)] @@ -19,11 +23,11 @@ impl OpcodeCountInspector { } } -impl Inspector for OpcodeCountInspector +impl Inspector, EthInterpreter> for OpcodeCountInspector where DB: Database, { - fn step(&mut self, _interp: &mut Interpreter, _context: &mut EvmContext) { + fn step(&mut self, _interp: &mut Interpreter, _context: &mut PrevContext) { self.count += 1; } } diff --git a/src/tracing/types.rs b/src/tracing/types.rs index e9353b48..b52250bf 100644 --- a/src/tracing/types.rs +++ b/src/tracing/types.rs @@ -10,7 +10,10 @@ use alloy_rpc_types_trace::{ CreationMethod, SelfdestructAction, TraceOutput, TransactionTrace, }, }; -use revm::interpreter::{opcode, CallScheme, CreateScheme, InstructionResult, OpCode}; +use revm::{ + bytecode::opcode::{self, OpCode}, + interpreter::{CallScheme, CreateScheme, InstructionResult}, +}; use std::collections::VecDeque; /// Decoded call data. diff --git a/src/tracing/utils.rs b/src/tracing/utils.rs index 2b52c451..7fb5f754 100644 --- a/src/tracing/utils.rs +++ b/src/tracing/utils.rs @@ -2,10 +2,7 @@ use alloy_primitives::{hex, Bytes}; use alloy_sol_types::{ContractError, GenericRevertReason}; -use revm::{ - primitives::{SpecId, KECCAK_EMPTY}, - DatabaseRef, -}; +use revm::{primitives::KECCAK_EMPTY, specification::hardfork::SpecId, DatabaseRef}; /// Formats memory data into a list of 32-byte hex-encoded chunks. /// @@ -28,7 +25,7 @@ pub(crate) fn convert_memory(data: &[u8]) -> Vec { /// Get the gas used, accounting for refunds #[inline] pub(crate) fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 { - let refund_quotient = if SpecId::enabled(spec, SpecId::LONDON) { 5 } else { 2 }; + let refund_quotient = if SpecId::is_enabled_in(spec, SpecId::LONDON) { 5 } else { 2 }; spent - (refunded).min(spent / refund_quotient) } @@ -38,7 +35,7 @@ pub(crate) fn gas_used(spec: SpecId, spent: u64, refunded: u64) -> u64 { #[inline] pub(crate) fn load_account_code( db: DB, - db_acc: &revm::primitives::AccountInfo, + db_acc: &revm::state::AccountInfo, ) -> Option { db_acc .code diff --git a/src/transfer.rs b/src/transfer.rs index 834052ad..6686ac6a 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -1,11 +1,14 @@ use alloy_primitives::{address, b256, Address, Log, LogData, B256, U256}; use alloy_sol_types::SolValue; use revm::{ + context_interface::Journal, interpreter::{ - CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, EOFCreateKind, + interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, + CreateScheme, EOFCreateKind, }, - Database, EvmContext, Inspector, JournaledState, + Database, JournaledState, }; +use revm_inspector::{Inspector, PrevContext}; /// Sender of ETH transfer log per `eth_simulateV1` spec. /// @@ -65,13 +68,13 @@ impl TransferInspector { self.transfers.iter() } - fn on_transfer( + fn on_transfer( &mut self, from: Address, to: Address, value: U256, kind: TransferKind, - journaled_state: &mut JournaledState, + journaled_state: &mut JournaledState, ) { // skip top level transfers if self.internal_only && journaled_state.depth() == 0 { @@ -96,13 +99,13 @@ impl TransferInspector { } } -impl Inspector for TransferInspector +impl Inspector, EthInterpreter> for TransferInspector where DB: Database, { fn call( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CallInputs, ) -> Option { if let Some(value) = inputs.transfer_value() { @@ -120,7 +123,7 @@ where fn create( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut CreateInputs, ) -> Option { let nonce = context.journaled_state.account(inputs.caller).info.nonce; @@ -138,17 +141,11 @@ where fn eofcreate( &mut self, - context: &mut EvmContext, + context: &mut PrevContext, inputs: &mut revm::interpreter::EOFCreateInputs, ) -> Option { let address = match inputs.kind { - EOFCreateKind::Tx { .. } => { - let nonce = - context.env.tx.nonce.unwrap_or_else(|| { - context.journaled_state.account(inputs.caller).info.nonce - }); - inputs.caller.create(nonce) - } + EOFCreateKind::Tx { .. } => inputs.caller.create(context.tx.nonce), EOFCreateKind::Opcode { created_address, .. } => created_address, }; diff --git a/tests/it/geth.rs b/tests/it/geth.rs index be318cb7..41f113fa 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -7,13 +7,8 @@ use alloy_rpc_types_trace::geth::{ mux::MuxConfig, CallConfig, FlatCallConfig, GethDebugBuiltInTracerType, GethDebugTracerConfig, GethTrace, PreStateConfig, PreStateFrame, }; -use revm::{ - db::{CacheDB, EmptyDB}, - primitives::{ - BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, HandlerCfg, SpecId, TransactTo, - TxEnv, - }, -}; +use revm::{context::{CfgEnv, TxEnv}, context_interface::TransactTo, database_interface::EmptyDB, specification::hardfork::SpecId}; +use revm_database::CacheDB; use revm_inspectors::tracing::{MuxInspector, TracingInspector, TracingInspectorConfig}; #[test] diff --git a/tests/it/parity.rs b/tests/it/parity.rs index 5ea5c508..b4296431 100644 --- a/tests/it/parity.rs +++ b/tests/it/parity.rs @@ -6,14 +6,8 @@ use alloy_rpc_types_eth::TransactionInfo; use alloy_rpc_types_trace::parity::{ Action, CallAction, CallType, CreationMethod, SelfdestructAction, TraceType, }; -use revm::{ - db::{CacheDB, EmptyDB}, - primitives::{ - AccountInfo, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, - EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Output, SpecId, TransactTo, TxEnv, - }, - DatabaseCommit, -}; +use revm::{database_interface::EmptyDB, specification::hardfork::SpecId, DatabaseCommit}; +use revm_database::CacheDB; use revm_inspectors::tracing::{ parity::populate_state_diff, TracingInspector, TracingInspectorConfig, }; diff --git a/tests/it/transfer.rs b/tests/it/transfer.rs index 6eed8ffa..0d97706f 100644 --- a/tests/it/transfer.rs +++ b/tests/it/transfer.rs @@ -1,14 +1,8 @@ //! Transfer tests use alloy_primitives::{hex, Address, U256}; -use revm::{ - db::{CacheDB, EmptyDB}, - primitives::{ - BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, - Output, SpecId, TransactTo, TxEnv, - }, - DatabaseCommit, -}; +use revm::{database_interface::EmptyDB, DatabaseCommit}; +use revm_database::CacheDB; use crate::utils::inspect; use revm_inspectors::{ diff --git a/tests/it/utils.rs b/tests/it/utils.rs index 7d670865..1cb31d46 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -1,14 +1,15 @@ use alloy_primitives::{Address, Bytes, U256}; use colorchoice::ColorChoice; use revm::{ - db::{CacheDB, EmptyDB}, - inspector_handle_register, + database_interface::EmptyDB, primitives::{ BlockEnv, EVMError, Env, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, ResultAndState, SpecId, TransactTo, TxEnv, }, - Database, DatabaseCommit, GetInspector, + Database, DatabaseCommit, }; +use revm_database::CacheDB; +use revm_inspector::{inspector_handler, Inspector}; use revm_inspectors::tracing::{ TraceWriter, TraceWriterConfig, TracingInspector, TracingInspectorConfig, }; From 832037e49e01bf4f5d1871c50a9be89306ff3d54 Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 20 Dec 2024 15:36:22 +0200 Subject: [PATCH 02/15] fmt --- src/tracing/js/mod.rs | 14 ++++++++++++-- tests/it/geth.rs | 7 ++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 4d39702f..91aca3c3 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -417,7 +417,11 @@ where } } - fn step_end(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { + fn step_end( + &mut self, + interp: &mut Interpreter, + context: &mut PrevContext, + ) { if self.step_fn.is_none() { return; } @@ -444,7 +448,13 @@ where } } - fn log(&mut self, _interp: &mut Interpreter, _context: &mut PrevContext, _log: &Log) {} + fn log( + &mut self, + _interp: &mut Interpreter, + _context: &mut PrevContext, + _log: &Log, + ) { + } fn call( &mut self, diff --git a/tests/it/geth.rs b/tests/it/geth.rs index 41f113fa..5bcd748f 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -7,7 +7,12 @@ use alloy_rpc_types_trace::geth::{ mux::MuxConfig, CallConfig, FlatCallConfig, GethDebugBuiltInTracerType, GethDebugTracerConfig, GethTrace, PreStateConfig, PreStateFrame, }; -use revm::{context::{CfgEnv, TxEnv}, context_interface::TransactTo, database_interface::EmptyDB, specification::hardfork::SpecId}; +use revm::{ + context::{CfgEnv, TxEnv}, + context_interface::TransactTo, + database_interface::EmptyDB, + specification::hardfork::SpecId, +}; use revm_database::CacheDB; use revm_inspectors::tracing::{MuxInspector, TracingInspector, TracingInspectorConfig}; From 26eed85b7198a044940047f14613ad988c09952d Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 20 Dec 2024 17:05:28 +0200 Subject: [PATCH 03/15] save compile err msg --- Cargo.toml | 6 +++--- src/access_list.rs | 2 +- src/opcode.rs | 2 +- src/tracing/fourbyte.rs | 8 ++++++-- src/tracing/js/mod.rs | 3 ++- src/tracing/mod.rs | 2 +- src/tracing/mux.rs | 2 +- src/tracing/opcount.rs | 2 +- src/transfer.rs | 2 +- tests/it/utils.rs | 9 +-------- 10 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4e32f49c..4ffd29a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "f84bfb58", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ "std", ] } diff --git a/src/access_list.rs b/src/access_list.rs index e44d8bb6..50ed2f6d 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -64,7 +64,7 @@ impl AccessListInspector { } } -impl Inspector, EthInterpreter> for AccessListInspector +impl Inspector, EthInterpreter> for AccessListInspector where DB: Database, { diff --git a/src/opcode.rs b/src/opcode.rs index 9e53a6c6..ba1b3837 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -60,7 +60,7 @@ impl OpcodeGasInspector { } } -impl Inspector, EthInterpreter> for OpcodeGasInspector +impl Inspector, EthInterpreter> for OpcodeGasInspector where DB: Database, { diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index 82043f66..d1553167 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -24,8 +24,9 @@ use alloy_primitives::{hex, Selector}; use alloy_rpc_types_trace::geth::FourByteFrame; use revm::{ + context::{BlockEnv, CfgEnv, ContextWire, ContextWiring, TxEnv}, interpreter::{interpreter::EthInterpreter, CallInputs, CallOutcome}, - Database, + Context, Database, }; use revm_inspector::{Inspector, PrevContext}; use std::collections::HashMap; @@ -44,9 +45,12 @@ impl FourByteInspector { } } -impl Inspector, EthInterpreter> for FourByteInspector +/// TODO : rakita the type parameter `CTXW` is not constrained by the impl trait, self type, or predicates +/// unconstrained type parameter +impl Inspector, EthInterpreter> for FourByteInspector where DB: Database, + CTXW: ContextWiring, { fn call( &mut self, diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 91aca3c3..50312618 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -385,9 +385,10 @@ impl JsInspector { } } -impl Inspector, EthInterpreter> for JsInspector +impl Inspector, EthInterpreter> for JsInspector where DB: Database + DatabaseRef, + W: ContextWiring, ::Error: std::fmt::Display, { fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 2d79dae9..d5a88527 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -533,7 +533,7 @@ impl TracingInspector { } } -impl Inspector, EthInterpreter> for TracingInspector +impl Inspector, EthInterpreter> for TracingInspector where DB: Database, { diff --git a/src/tracing/mux.rs b/src/tracing/mux.rs index 5f4f67a9..38999087 100644 --- a/src/tracing/mux.rs +++ b/src/tracing/mux.rs @@ -157,7 +157,7 @@ impl MuxInspector { } } -impl Inspector, EthInterpreter> for MuxInspector +impl Inspector, EthInterpreter> for MuxInspector where DB: Database, { diff --git a/src/tracing/opcount.rs b/src/tracing/opcount.rs index c7a11a93..3493b9ed 100644 --- a/src/tracing/opcount.rs +++ b/src/tracing/opcount.rs @@ -23,7 +23,7 @@ impl OpcodeCountInspector { } } -impl Inspector, EthInterpreter> for OpcodeCountInspector +impl Inspector, EthInterpreter> for OpcodeCountInspector where DB: Database, { diff --git a/src/transfer.rs b/src/transfer.rs index 6686ac6a..008e76be 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -99,7 +99,7 @@ impl TransferInspector { } } -impl Inspector, EthInterpreter> for TransferInspector +impl Inspector, EthInterpreter> for TransferInspector where DB: Database, { diff --git a/tests/it/utils.rs b/tests/it/utils.rs index 1cb31d46..ce9f6848 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -1,13 +1,6 @@ use alloy_primitives::{Address, Bytes, U256}; use colorchoice::ColorChoice; -use revm::{ - database_interface::EmptyDB, - primitives::{ - BlockEnv, EVMError, Env, EnvWithHandlerCfg, ExecutionResult, HandlerCfg, ResultAndState, - SpecId, TransactTo, TxEnv, - }, - Database, DatabaseCommit, -}; +use revm::{database_interface::EmptyDB, Database, DatabaseCommit}; use revm_database::CacheDB; use revm_inspector::{inspector_handler, Inspector}; use revm_inspectors::tracing::{ From 8fb15a607a004d7fdd7fade35fd0b77f9fbf438c Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 20 Dec 2024 18:30:22 +0200 Subject: [PATCH 04/15] progress --- Cargo.toml | 6 +-- src/access_list.rs | 15 +++++-- src/opcode.rs | 35 ++++++++++------ src/tracing/fourbyte.rs | 16 ++++---- src/tracing/js/mod.rs | 18 ++++---- src/tracing/mod.rs | 91 ++++++++++++++++++++--------------------- src/tracing/mux.rs | 51 ++++++++++++++--------- src/tracing/opcount.rs | 15 +++++-- src/transfer.rs | 25 ++++++----- 9 files changed, 157 insertions(+), 115 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4ffd29a9..bdbfa5a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "ab62fe1a", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ "std", ] } diff --git a/src/access_list.rs b/src/access_list.rs index 50ed2f6d..e99ec291 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -2,14 +2,15 @@ use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::{AccessList, AccessListItem}; use revm::{ bytecode::opcode, + context_interface::Journal, interpreter::{ interpreter::EthInterpreter, interpreter_types::{InputsTrait, Jumps}, Interpreter, }, - Database, + Context, Database, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; use std::collections::{BTreeSet, HashMap, HashSet}; /// An [Inspector] that collects touched accounts and storage slots. @@ -64,11 +65,17 @@ impl AccessListInspector { } } -impl Inspector, EthInterpreter> for AccessListInspector +impl + Inspector, EthInterpreter> for AccessListInspector where DB: Database, + JOURNAL: Journal, { - fn step(&mut self, interp: &mut Interpreter, _context: &mut PrevContext) { + fn step( + &mut self, + interp: &mut Interpreter, + _context: &mut Context, + ) { match interp.bytecode.opcode() { opcode::SLOAD | opcode::SSTORE => { if let Ok(slot) = interp.stack.peek(0) { diff --git a/src/opcode.rs b/src/opcode.rs index ba1b3837..cce45453 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -1,14 +1,15 @@ use alloy_rpc_types_trace::opcode::OpcodeGas; use revm::{ bytecode::opcode::{self, OpCode}, + context_interface::Journal, interpreter::{ interpreter::EthInterpreter, interpreter_types::{Immediates, Jumps, LoopControl}, Interpreter, }, - Database, + Context, Database, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; use std::collections::HashMap; /// An Inspector that counts opcodes and measures gas usage per opcode. @@ -60,11 +61,17 @@ impl OpcodeGasInspector { } } -impl Inspector, EthInterpreter> for OpcodeGasInspector +impl + Inspector, EthInterpreter> for OpcodeGasInspector where DB: Database, + JOURNAL: Journal, { - fn step(&mut self, interp: &mut Interpreter, _context: &mut PrevContext) { + fn step( + &mut self, + interp: &mut Interpreter, + _context: &mut Context, + ) { let opcode_value = interp.bytecode.opcode(); if let Some(opcode) = OpCode::new(opcode_value) { // keep track of opcode counts @@ -78,7 +85,7 @@ where fn step_end( &mut self, interp: &mut Interpreter, - _context: &mut PrevContext, + _context: &mut Context, ) { // update gas usage for the last opcode if let Some((opcode, gas_remaining)) = self.last_opcode_gas_remaining.take() { @@ -133,10 +140,11 @@ mod tests { ); let db = CacheDB::new(EmptyDB::default()); - for _ in &opcodes { - opcode_counter - .step(&mut interpreter, &mut PrevContext::new(db.clone(), SpecId::BERLIN)); - } + // TODO(rakita) fix this + // let mut context = PrevContext::new(db.clone(), SpecId::BERLIN); + // for _ in &opcodes { + // opcode_counter.step(&mut interpreter, &mut context); + // } } #[test] @@ -164,9 +172,10 @@ mod tests { ); let db = CacheDB::new(EmptyDB::default()); - for _ in opcodes.iter() { - opcode_counter - .step(&mut interpreter, &mut PrevContext::new(db.clone(), SpecId::LATEST)); - } + // TODO(rakita): fix this + // let mut context: Context<> = Context::new(db.clone(), SpecId::LATEST); + // for _ in opcodes.iter() { + // opcode_counter.step(&mut interpreter, &mut context); + // } } } diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index d1553167..81ecfb40 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -24,11 +24,12 @@ use alloy_primitives::{hex, Selector}; use alloy_rpc_types_trace::geth::FourByteFrame; use revm::{ - context::{BlockEnv, CfgEnv, ContextWire, ContextWiring, TxEnv}, + context::{BlockEnv, CfgEnv, TxEnv}, + context_interface::Journal, interpreter::{interpreter::EthInterpreter, CallInputs, CallOutcome}, Context, Database, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; use std::collections::HashMap; /// Fourbyte tracing inspector that records all function selectors and their calldata sizes. @@ -45,16 +46,17 @@ impl FourByteInspector { } } -/// TODO : rakita the type parameter `CTXW` is not constrained by the impl trait, self type, or predicates -/// unconstrained type parameter -impl Inspector, EthInterpreter> for FourByteInspector +/// TODO rakita the type parameter `CTXW` is not constrained by the impl trait, self type, or +/// predicates unconstrained type parameter +impl + Inspector, EthInterpreter> for FourByteInspector where DB: Database, - CTXW: ContextWiring, + JOURNAL: Journal, { fn call( &mut self, - _context: &mut PrevContext, + _context: &mut Context, inputs: &mut CallInputs, ) -> Option { if inputs.input.len() >= 4 { diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 50312618..cfc57b07 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -391,7 +391,11 @@ where W: ContextWiring, ::Error: std::fmt::Display, { - fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { + fn step( + &mut self, + interp: &mut Interpreter, + context: &mut Context, + ) { if self.step_fn.is_none() { return; } @@ -421,7 +425,7 @@ where fn step_end( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut Context, ) { if self.step_fn.is_none() { return; @@ -452,14 +456,14 @@ where fn log( &mut self, _interp: &mut Interpreter, - _context: &mut PrevContext, + _context: &mut Context, _log: &Log, ) { } fn call( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CallInputs, ) -> Option { self.register_precompiles(&context.precompiles); @@ -500,7 +504,7 @@ where fn call_end( &mut self, - _context: &mut PrevContext, + _context: &mut Context, _inputs: &CallInputs, mut outcome: CallOutcome, ) -> CallOutcome { @@ -522,7 +526,7 @@ where fn create( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CreateInputs, ) -> Option { self.register_precompiles(&context.precompiles); @@ -553,7 +557,7 @@ where fn create_end( &mut self, - _context: &mut PrevContext, + _context: &mut Context, _inputs: &CreateInputs, mut outcome: CreateOutcome, ) -> CreateOutcome { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index d5a88527..9adc6107 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -12,7 +12,7 @@ use crate::{ use alloy_primitives::{Address, Bytes, Log, B256, U256}; use revm::{ bytecode::opcode::{self, OpCode}, - context_interface::{Journal, JournalStateGetter}, + context_interface::{Journal, JournalGetter}, interpreter::{ interpreter::EthInterpreter, interpreter_types::{ @@ -22,7 +22,7 @@ use revm::{ InstructionResult, Interpreter, InterpreterResult, }, specification::hardfork::SpecId, - Database, JournalEntry, + Context, Database, JournalEntry, }; mod arena; @@ -44,7 +44,7 @@ mod opcount; pub use opcount::OpcodeCountInspector; pub mod types; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::{Inspector, JournalExt, JournalExtGetter}; use types::{CallLog, CallTrace, CallTraceStep}; mod utils; @@ -239,9 +239,10 @@ impl TracingInspector { /// /// Returns true if the `to` address is a precompile contract and the value is zero. #[inline] - fn is_precompile_call( + fn is_precompile_call( &self, - context: &PrevContext, + // TODO(rakita) + //context: &Context, to: &Address, value: &U256, ) -> bool { @@ -297,9 +298,9 @@ impl TracingInspector { /// /// Invoked on [Inspector::call]. #[allow(clippy::too_many_arguments)] - fn start_trace_on_call( + fn start_trace_on_call( &mut self, - context: &PrevContext, + context: &mut CTX, address: Address, input_data: Bytes, value: U256, @@ -321,7 +322,7 @@ impl TracingInspector { 0, push_kind, CallTrace { - depth: context.journaled_state.depth() as usize, + depth: context.journal().depth() as usize, address, kind, data: input_data, @@ -342,9 +343,8 @@ impl TracingInspector { /// # Panics /// /// This expects an existing trace [Self::start_trace_on_call] - fn fill_trace_on_call_end( + fn fill_trace_on_call_end( &mut self, - _context: &mut PrevContext, result: &InterpreterResult, created_address: Option
, ) { @@ -376,10 +376,10 @@ impl TracingInspector { /// This expects an existing [CallTrace], in other words, this panics if not within the context /// of a call. #[cold] - fn start_step( + fn start_step( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut CTX, ) { let trace_idx = self.last_trace_idx(); let trace = &mut self.traces.arena[trace_idx]; @@ -442,7 +442,7 @@ impl TracingInspector { } trace.trace.steps.push(CallTraceStep { - depth: context.journaled_state.depth() as u64, + depth: context.journal().depth() as u64, pc: interp.bytecode.pc(), code_section_idx: interp.sub_routine.routine_idx(), op, @@ -470,10 +470,10 @@ impl TracingInspector { /// /// Invoked on [Inspector::step_end]. #[cold] - fn fill_step_on_step_end( + fn fill_step_on_step_end( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut CTX, ) { let StackStep { trace_idx, step_idx, record } = self.step_stack.pop().expect("can't fill step without starting a step first"); @@ -494,14 +494,7 @@ impl TracingInspector { if self.config.record_state_diff { let op = step.op.get(); - let journal_entry = context - .journaled_state - .journal - .last() - // This should always work because revm initializes it as `vec![vec![]]` - // See [JournaledState::new](revm::JournaledState) - .expect("exists; initialized with vec") - .last(); + let journal_entry = context.journal_ext().last_journal().last().cloned(); step.storage_change = match (op, journal_entry) { ( @@ -509,14 +502,15 @@ impl TracingInspector { Some(JournalEntry::StorageChanged { address, key, had_value }), ) => { // SAFETY: (Address,key) exists if part if StorageChange - let value = context.journaled_state.state[address].storage[key].present_value(); + //TODO let value = + // context.journal_ext().state[address].storage[key].present_value(); + let value = U256::ZERO; let reason = match op { opcode::SLOAD => StorageChangeReason::SLOAD, opcode::SSTORE => StorageChangeReason::SSTORE, _ => unreachable!(), }; - let change = - StorageChange { key: *key, value, had_value: Some(*had_value), reason }; + let change = StorageChange { key, value, had_value: Some(had_value), reason }; Some(change) } _ => None, @@ -533,12 +527,18 @@ impl TracingInspector { } } -impl Inspector, EthInterpreter> for TracingInspector +impl + Inspector, EthInterpreter> for TracingInspector where DB: Database, + JOURNAL: Journal, { #[inline] - fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { + fn step( + &mut self, + interp: &mut Interpreter, + context: &mut Context, + ) { if self.config.record_steps { self.start_step(interp, context); } @@ -548,17 +548,18 @@ where fn step_end( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut Context, ) { if self.config.record_steps { - self.fill_step_on_step_end(interp, context); + // TODO(rakita) fix this + //self.fill_step_on_step_end(interp, context); } } fn log( &mut self, _interp: &mut Interpreter, - _context: &mut PrevContext, + _context: &mut Context, log: &Log, ) { if self.config.record_logs { @@ -570,7 +571,7 @@ where fn call( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CallInputs, ) -> Option { // determine correct `from` and `to` based on the call scheme @@ -594,10 +595,8 @@ 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(context, &to, &value)); + let maybe_precompile = + self.config.exclude_precompile_calls.then(|| self.is_precompile_call(&to, &value)); self.start_trace_on_call( context, @@ -615,20 +614,20 @@ where fn call_end( &mut self, - context: &mut PrevContext, + context: &mut Context, _inputs: &CallInputs, outcome: &mut CallOutcome, ) { - self.fill_trace_on_call_end(context, &outcome.result, None); + self.fill_trace_on_call_end(&outcome.result, None); } fn create( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CreateInputs, ) -> Option { let _ = context.journal().load_account(inputs.caller); - let nonce = context.journaled_state.account(inputs.caller).info.nonce; + let nonce = context.journaled_state.load_account(inputs.caller).ok()?.info.nonce; self.start_trace_on_call( context, inputs.created_address(nonce), @@ -645,23 +644,23 @@ where fn create_end( &mut self, - context: &mut PrevContext, + context: &mut Context, _inputs: &CreateInputs, outcome: &mut CreateOutcome, ) { - self.fill_trace_on_call_end(context, &outcome.result, outcome.address); + self.fill_trace_on_call_end(&outcome.result, outcome.address); } fn eofcreate( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut EOFCreateInputs, ) -> Option { let address = if let Some(address) = inputs.kind.created_address() { *address } else { let _ = context.journal().load_account(inputs.caller); - let nonce = context.journaled_state.account(inputs.caller).info.nonce; + let nonce = context.journaled_state.load_account(inputs.caller).ok()?.info.nonce; inputs.caller.create(nonce) }; self.start_trace_on_call( @@ -680,11 +679,11 @@ where fn eofcreate_end( &mut self, - context: &mut PrevContext, + context: &mut Context, _inputs: &EOFCreateInputs, outcome: &mut CreateOutcome, ) { - self.fill_trace_on_call_end(context, &outcome.result, outcome.address); + self.fill_trace_on_call_end(&outcome.result, outcome.address); } fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { diff --git a/src/tracing/mux.rs b/src/tracing/mux.rs index 38999087..55dcbe37 100644 --- a/src/tracing/mux.rs +++ b/src/tracing/mux.rs @@ -7,14 +7,17 @@ use alloy_rpc_types_trace::geth::{ PreStateConfig, }; use revm::{ - context_interface::result::{HaltReasonTrait, ResultAndState}, + context_interface::{ + result::{HaltReasonTrait, ResultAndState}, + Journal, + }, interpreter::{ interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, Interpreter, }, - Database, DatabaseRef, + Context, Database, DatabaseRef, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; use thiserror::Error; /// Mux tracing inspector that runs and collects results of multiple inspectors at once. @@ -157,15 +160,17 @@ impl MuxInspector { } } -impl Inspector, EthInterpreter> for MuxInspector +impl + Inspector, EthInterpreter> for MuxInspector where DB: Database, + JOURNAL: Journal, { #[inline] fn initialize_interp( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut Context, ) { if let Some(ref mut inspector) = self.four_byte { inspector.initialize_interp(interp, context); @@ -176,7 +181,11 @@ where } #[inline] - fn step(&mut self, interp: &mut Interpreter, context: &mut PrevContext) { + fn step( + &mut self, + interp: &mut Interpreter, + context: &mut Context, + ) { if let Some(ref mut inspector) = self.four_byte { inspector.step(interp, context); } @@ -189,7 +198,7 @@ where fn step_end( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut Context, ) { if let Some(ref mut inspector) = self.four_byte { inspector.step_end(interp, context); @@ -203,7 +212,7 @@ where fn log( &mut self, interp: &mut Interpreter, - context: &mut PrevContext, + context: &mut Context, log: &Log, ) { if let Some(ref mut inspector) = self.four_byte { @@ -217,7 +226,7 @@ where #[inline] fn call( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CallInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -232,7 +241,7 @@ where #[inline] fn call_end( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &CallInputs, outcome: &mut CallOutcome, ) { @@ -247,7 +256,7 @@ where #[inline] fn create( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CreateInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -262,7 +271,7 @@ where #[inline] fn create_end( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &CreateInputs, outcome: &mut CreateOutcome, ) { @@ -277,7 +286,7 @@ where #[inline] fn eofcreate( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut EOFCreateInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -292,7 +301,7 @@ where #[inline] fn eofcreate_end( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &EOFCreateInputs, outcome: &mut CreateOutcome, ) { @@ -307,14 +316,16 @@ where #[inline] fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { if let Some(ref mut inspector) = self.four_byte { - , EthInterpreter>>::selfdestruct( - inspector, contract, target, value, - ); + , + EthInterpreter, + >>::selfdestruct(inspector, contract, target, value); } if let Some(ref mut inspector) = self.tracing { - , EthInterpreter>>::selfdestruct( - inspector, contract, target, value, - ); + , + EthInterpreter, + >>::selfdestruct(inspector, contract, target, value); } } } diff --git a/src/tracing/opcount.rs b/src/tracing/opcount.rs index 3493b9ed..27452d26 100644 --- a/src/tracing/opcount.rs +++ b/src/tracing/opcount.rs @@ -3,10 +3,11 @@ //! See also use revm::{ + context_interface::Journal, interpreter::{interpreter::EthInterpreter, Interpreter}, - Database, + Context, Database, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; /// An inspector that counts all opcodes. #[derive(Clone, Copy, Debug, Default)] @@ -23,11 +24,17 @@ impl OpcodeCountInspector { } } -impl Inspector, EthInterpreter> for OpcodeCountInspector +impl + Inspector, EthInterpreter> for OpcodeCountInspector where DB: Database, + JOURNAL: Journal, { - fn step(&mut self, _interp: &mut Interpreter, _context: &mut PrevContext) { + fn step( + &mut self, + _interp: &mut Interpreter, + _context: &mut Context, + ) { self.count += 1; } } diff --git a/src/transfer.rs b/src/transfer.rs index 008e76be..804b12c9 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -1,14 +1,14 @@ use alloy_primitives::{address, b256, Address, Log, LogData, B256, U256}; use alloy_sol_types::SolValue; use revm::{ - context_interface::Journal, + context_interface::{Journal, Transaction, TransactionGetter}, interpreter::{ interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, EOFCreateKind, }, - Database, JournaledState, + Context, Database, JournaledState, }; -use revm_inspector::{Inspector, PrevContext}; +use revm_inspector::Inspector; /// Sender of ETH transfer log per `eth_simulateV1` spec. /// @@ -68,13 +68,13 @@ impl TransferInspector { self.transfers.iter() } - fn on_transfer( + fn on_transfer>( &mut self, from: Address, to: Address, value: U256, kind: TransferKind, - journaled_state: &mut JournaledState, + journaled_state: &mut JOURNAL, ) { // skip top level transfers if self.internal_only && journaled_state.depth() == 0 { @@ -99,13 +99,16 @@ impl TransferInspector { } } -impl Inspector, EthInterpreter> for TransferInspector +impl + Inspector, EthInterpreter> for TransferInspector where DB: Database, + JOURNAL: Journal, + TX: Transaction, { fn call( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CallInputs, ) -> Option { if let Some(value) = inputs.transfer_value() { @@ -123,10 +126,10 @@ where fn create( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut CreateInputs, ) -> Option { - let nonce = context.journaled_state.account(inputs.caller).info.nonce; + let nonce = context.journaled_state.load_account(inputs.caller).ok()?.data.info.nonce; let address = inputs.created_address(nonce); let kind = match inputs.scheme { @@ -141,11 +144,11 @@ where fn eofcreate( &mut self, - context: &mut PrevContext, + context: &mut Context, inputs: &mut revm::interpreter::EOFCreateInputs, ) -> Option { let address = match inputs.kind { - EOFCreateKind::Tx { .. } => inputs.caller.create(context.tx.nonce), + EOFCreateKind::Tx { .. } => inputs.caller.create(context.tx().common_fields().nonce()), EOFCreateKind::Opcode { created_address, .. } => created_address, }; From c755f5b6fa3a9e840eb4fa8af7625d6979818aeb Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 23 Dec 2024 13:54:21 +0100 Subject: [PATCH 05/15] simplify impl for Inspector, and add util for evm exec --- Cargo.toml | 6 ++-- src/tracing/fourbyte.rs | 20 ++--------- src/tracing/mod.rs | 56 ++++++++---------------------- src/tracing/mux.rs | 76 ++++++++++++----------------------------- src/tracing/opcount.rs | 19 ++--------- tests/it/geth.rs | 30 +++++++--------- tests/it/utils.rs | 36 +++++++++++-------- 7 files changed, 78 insertions(+), 165 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bdbfa5a5..f06f0f67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "235ad5c8", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ "std", ] } diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index 81ecfb40..c88a04c8 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -23,12 +23,7 @@ use alloy_primitives::{hex, Selector}; use alloy_rpc_types_trace::geth::FourByteFrame; -use revm::{ - context::{BlockEnv, CfgEnv, TxEnv}, - context_interface::Journal, - interpreter::{interpreter::EthInterpreter, CallInputs, CallOutcome}, - Context, Database, -}; +use revm::interpreter::{interpreter::EthInterpreter, CallInputs, CallOutcome}; use revm_inspector::Inspector; use std::collections::HashMap; @@ -48,17 +43,8 @@ impl FourByteInspector { /// TODO rakita the type parameter `CTXW` is not constrained by the impl trait, self type, or /// predicates unconstrained type parameter -impl - Inspector, EthInterpreter> for FourByteInspector -where - DB: Database, - JOURNAL: Journal, -{ - fn call( - &mut self, - _context: &mut Context, - inputs: &mut CallInputs, - ) -> Option { +impl Inspector for FourByteInspector { + fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option { if inputs.input.len() >= 4 { let selector = Selector::try_from(&inputs.input[..4]).expect("input is at least 4 bytes"); diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 9adc6107..5c55f452 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -527,41 +527,26 @@ impl TracingInspector { } } -impl - Inspector, EthInterpreter> for TracingInspector +impl Inspector for TracingInspector where - DB: Database, - JOURNAL: Journal, + CTX: JournalExtGetter + JournalGetter, { #[inline] - fn step( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.config.record_steps { self.start_step(interp, context); } } #[inline] - fn step_end( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.config.record_steps { // TODO(rakita) fix this - //self.fill_step_on_step_end(interp, context); + self.fill_step_on_step_end(interp, context); } } - fn log( - &mut self, - _interp: &mut Interpreter, - _context: &mut Context, - log: &Log, - ) { + fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, log: &Log) { if self.config.record_logs { let trace = self.last_trace(); trace.ordering.push(TraceMemberOrder::Log(trace.logs.len())); @@ -569,11 +554,7 @@ where } } - fn call( - &mut self, - context: &mut Context, - inputs: &mut CallInputs, - ) -> Option { + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { // determine correct `from` and `to` based on the call scheme let (from, to) = match inputs.scheme { CallScheme::DelegateCall | CallScheme::CallCode | CallScheme::ExtDelegateCall => { @@ -612,22 +593,13 @@ where None } - fn call_end( - &mut self, - context: &mut Context, - _inputs: &CallInputs, - outcome: &mut CallOutcome, - ) { + fn call_end(&mut self, _: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) { self.fill_trace_on_call_end(&outcome.result, None); } - fn create( - &mut self, - context: &mut Context, - inputs: &mut CreateInputs, - ) -> Option { + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { let _ = context.journal().load_account(inputs.caller); - let nonce = context.journaled_state.load_account(inputs.caller).ok()?.info.nonce; + let nonce = context.journal().load_account(inputs.caller).ok()?.info.nonce; self.start_trace_on_call( context, inputs.created_address(nonce), @@ -644,7 +616,7 @@ where fn create_end( &mut self, - context: &mut Context, + context: &mut CTX, _inputs: &CreateInputs, outcome: &mut CreateOutcome, ) { @@ -653,14 +625,14 @@ where fn eofcreate( &mut self, - context: &mut Context, + context: &mut CTX, inputs: &mut EOFCreateInputs, ) -> Option { let address = if let Some(address) = inputs.kind.created_address() { *address } else { let _ = context.journal().load_account(inputs.caller); - let nonce = context.journaled_state.load_account(inputs.caller).ok()?.info.nonce; + let nonce = context.journal().load_account(inputs.caller).ok()?.info.nonce; inputs.caller.create(nonce) }; self.start_trace_on_call( @@ -679,7 +651,7 @@ where fn eofcreate_end( &mut self, - context: &mut Context, + context: &mut CTX, _inputs: &EOFCreateInputs, outcome: &mut CreateOutcome, ) { diff --git a/src/tracing/mux.rs b/src/tracing/mux.rs index 55dcbe37..7dc7c91a 100644 --- a/src/tracing/mux.rs +++ b/src/tracing/mux.rs @@ -9,15 +9,15 @@ use alloy_rpc_types_trace::geth::{ use revm::{ context_interface::{ result::{HaltReasonTrait, ResultAndState}, - Journal, + JournalGetter, }, interpreter::{ interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, Interpreter, }, - Context, Database, DatabaseRef, + DatabaseRef, }; -use revm_inspector::Inspector; +use revm_inspector::{Inspector, JournalExtGetter}; use thiserror::Error; /// Mux tracing inspector that runs and collects results of multiple inspectors at once. @@ -160,18 +160,12 @@ impl MuxInspector { } } -impl - Inspector, EthInterpreter> for MuxInspector +impl Inspector for MuxInspector where - DB: Database, - JOURNAL: Journal, + CTX: JournalExtGetter + JournalGetter, { #[inline] - fn initialize_interp( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut CTX) { if let Some(ref mut inspector) = self.four_byte { inspector.initialize_interp(interp, context); } @@ -181,11 +175,7 @@ where } #[inline] - fn step( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { if let Some(ref mut inspector) = self.four_byte { inspector.step(interp, context); } @@ -195,11 +185,7 @@ where } #[inline] - fn step_end( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { if let Some(ref mut inspector) = self.four_byte { inspector.step_end(interp, context); } @@ -209,12 +195,7 @@ where } #[inline] - fn log( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - log: &Log, - ) { + fn log(&mut self, interp: &mut Interpreter, context: &mut CTX, log: &Log) { if let Some(ref mut inspector) = self.four_byte { inspector.log(interp, context, log); } @@ -224,11 +205,7 @@ where } #[inline] - fn call( - &mut self, - context: &mut Context, - inputs: &mut CallInputs, - ) -> Option { + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { if let Some(ref mut inspector) = self.four_byte { let _ = inspector.call(context, inputs); } @@ -239,12 +216,7 @@ where } #[inline] - fn call_end( - &mut self, - context: &mut Context, - inputs: &CallInputs, - outcome: &mut CallOutcome, - ) { + fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) { if let Some(ref mut inspector) = self.four_byte { inspector.call_end(context, inputs, outcome); } @@ -254,11 +226,7 @@ where } #[inline] - fn create( - &mut self, - context: &mut Context, - inputs: &mut CreateInputs, - ) -> Option { + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { if let Some(ref mut inspector) = self.four_byte { let _ = inspector.create(context, inputs); } @@ -271,7 +239,7 @@ where #[inline] fn create_end( &mut self, - context: &mut Context, + context: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome, ) { @@ -286,7 +254,7 @@ where #[inline] fn eofcreate( &mut self, - context: &mut Context, + context: &mut CTX, inputs: &mut EOFCreateInputs, ) -> Option { if let Some(ref mut inspector) = self.four_byte { @@ -301,7 +269,7 @@ where #[inline] fn eofcreate_end( &mut self, - context: &mut Context, + context: &mut CTX, inputs: &EOFCreateInputs, outcome: &mut CreateOutcome, ) { @@ -316,16 +284,14 @@ where #[inline] fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { if let Some(ref mut inspector) = self.four_byte { - , - EthInterpreter, - >>::selfdestruct(inspector, contract, target, value); + >::selfdestruct( + inspector, contract, target, value, + ); } if let Some(ref mut inspector) = self.tracing { - , - EthInterpreter, - >>::selfdestruct(inspector, contract, target, value); + >::selfdestruct( + inspector, contract, target, value, + ); } } } diff --git a/src/tracing/opcount.rs b/src/tracing/opcount.rs index 27452d26..54630e05 100644 --- a/src/tracing/opcount.rs +++ b/src/tracing/opcount.rs @@ -2,11 +2,7 @@ //! //! See also -use revm::{ - context_interface::Journal, - interpreter::{interpreter::EthInterpreter, Interpreter}, - Context, Database, -}; +use revm::interpreter::{interpreter::EthInterpreter, Interpreter}; use revm_inspector::Inspector; /// An inspector that counts all opcodes. @@ -24,17 +20,8 @@ impl OpcodeCountInspector { } } -impl - Inspector, EthInterpreter> for OpcodeCountInspector -where - DB: Database, - JOURNAL: Journal, -{ - fn step( - &mut self, - _interp: &mut Interpreter, - _context: &mut Context, - ) { +impl Inspector for OpcodeCountInspector { + fn step(&mut self, _interp: &mut Interpreter, _context: &mut CTX) { self.count += 1; } } diff --git a/tests/it/geth.rs b/tests/it/geth.rs index 5bcd748f..22b82dd8 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -8,10 +8,8 @@ use alloy_rpc_types_trace::geth::{ GethTrace, PreStateConfig, PreStateFrame, }; use revm::{ - context::{CfgEnv, TxEnv}, - context_interface::TransactTo, - database_interface::EmptyDB, - specification::hardfork::SpecId, + context::TxEnv, context_interface::TransactTo, database_interface::EmptyDB, + specification::hardfork::SpecId, Context, }; use revm_database::CacheDB; use revm_inspectors::tracing::{MuxInspector, TracingInspector, TracingInspectorConfig}; @@ -232,23 +230,21 @@ fn test_geth_inspector_reset() { let mut insp = TracingInspector::new(TracingInspectorConfig::default_geth()); let mut db = CacheDB::new(EmptyDB::default()); - let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::LONDON)); - let env = EnvWithHandlerCfg::new_with_cfg_env( - cfg.clone(), - BlockEnv::default(), - TxEnv { - caller: Address::ZERO, - gas_limit: 1000000, - gas_price: Default::default(), - transact_to: TransactTo::Call(Address::ZERO), - ..Default::default() - }, - ); + //let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::LONDON)); + let context = Context::default() + .with_db(&mut db) + .modify_cfg_chained(|cfg| cfg.spec = SpecId::LONDON) + .modify_tx_chained(|tx| { + tx.caller = Address::ZERO; + tx.gas_limit = 1000000; + tx.gas_price = Default::default(); + tx.transact_to = TransactTo::Call(Address::ZERO); + }); assert_eq!(insp.traces().nodes().first().unwrap().trace.gas_limit, 0); // first run inspector - let (res, env) = inspect(&mut db, env.clone(), &mut insp).unwrap(); + let (res, env) = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); assert_eq!( insp.clone() diff --git a/tests/it/utils.rs b/tests/it/utils.rs index ce9f6848..697ddf56 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -1,8 +1,18 @@ use alloy_primitives::{Address, Bytes, U256}; use colorchoice::ColorChoice; -use revm::{database_interface::EmptyDB, Database, DatabaseCommit}; +use revm::{ + context::{BlockEnv, CfgEnv, TxEnv}, + context_interface::result::{EVMError, HaltReason, InvalidTransaction, ResultAndState}, + database_interface::EmptyDB, + interpreter::interpreter::EthInterpreter, + specification::hardfork::SpecId, + Context, Database, DatabaseCommit, EvmExec, JournaledState, +}; use revm_database::CacheDB; -use revm_inspector::{inspector_handler, Inspector}; +use revm_inspector::{ + inspector_handler, GetInspector, Inspector, InspectorContext, InspectorHandler, + InspectorMainEvm, +}; use revm_inspectors::tracing::{ TraceWriter, TraceWriterConfig, TracingInspector, TracingInspectorConfig, }; @@ -104,25 +114,21 @@ impl TestEvm { } } +pub type ContextDb = Context, ()>; + /// Executes the [EnvWithHandlerCfg] against the given [Database] without committing state changes. pub fn inspect( - db: DB, - env: EnvWithHandlerCfg, + context: &mut ContextDb, inspector: I, -) -> Result<(ResultAndState, EnvWithHandlerCfg), EVMError> +) -> Result, EVMError> where DB: Database, - I: GetInspector, + I: for<'a> GetInspector<&'a mut ContextDb, EthInterpreter>, { - let mut evm = revm::Evm::builder() - .with_db(db) - .with_external_context(inspector) - .with_env_with_handler_cfg(env) - .append_handler_register(inspector_handle_register) - .build(); - let res = evm.transact()?; - let (_, env) = evm.into_db_and_env_with_handler_cfg(); - Ok((res, env)) + let ctx = InspectorContext::new(context, inspector); + let mut evm = InspectorMainEvm::new(ctx, inspector_handler()); + + evm.exec() } pub fn write_traces(tracer: &TracingInspector) -> String { From 394c4024821989ef6536187dc9d48efec29a04f2 Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 23 Dec 2024 14:11:31 +0100 Subject: [PATCH 06/15] temp comment out tests --- src/tracing/fourbyte.rs | 2 -- src/tracing/mod.rs | 2 +- tests/it/main.rs | 16 ++++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/tracing/fourbyte.rs b/src/tracing/fourbyte.rs index c88a04c8..fcc6d326 100644 --- a/src/tracing/fourbyte.rs +++ b/src/tracing/fourbyte.rs @@ -41,8 +41,6 @@ impl FourByteInspector { } } -/// TODO rakita the type parameter `CTXW` is not constrained by the impl trait, self type, or -/// predicates unconstrained type parameter impl Inspector for FourByteInspector { fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option { if inputs.input.len() >= 4 { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 5c55f452..c148a92c 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -22,7 +22,7 @@ use revm::{ InstructionResult, Interpreter, InterpreterResult, }, specification::hardfork::SpecId, - Context, Database, JournalEntry, + JournalEntry, }; mod arena; diff --git a/tests/it/main.rs b/tests/it/main.rs index 98e8c554..10c4caf5 100644 --- a/tests/it/main.rs +++ b/tests/it/main.rs @@ -1,9 +1,9 @@ -#![allow(missing_docs)] -pub mod utils; +// #![allow(missing_docs)] +// pub mod utils; -mod geth; -#[cfg(feature = "js-tracer")] -mod geth_js; -mod parity; -mod transfer; -mod writer; +// mod geth; +// #[cfg(feature = "js-tracer")] +// mod geth_js; +// mod parity; +// mod transfer; +// mod writer; From a2b2a93f3b5ba269ee050642e758341ddd76edab Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 23 Dec 2024 15:05:28 +0100 Subject: [PATCH 07/15] use generic ctx --- src/opcode.rs | 38 +++++++++++++------------------------- src/tracing/js/mod.rs | 36 +++++++----------------------------- src/tracing/mod.rs | 8 ++++---- src/transfer.rs | 33 +++++++++++---------------------- tests/it/main.rs | 4 ++-- 5 files changed, 37 insertions(+), 82 deletions(-) diff --git a/src/opcode.rs b/src/opcode.rs index cce45453..f4d8447d 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -1,7 +1,7 @@ use alloy_rpc_types_trace::opcode::OpcodeGas; use revm::{ bytecode::opcode::{self, OpCode}, - context_interface::Journal, + context_interface::{Journal, JournalGetter}, interpreter::{ interpreter::EthInterpreter, interpreter_types::{Immediates, Jumps, LoopControl}, @@ -61,17 +61,11 @@ impl OpcodeGasInspector { } } -impl - Inspector, EthInterpreter> for OpcodeGasInspector +impl Inspector for OpcodeGasInspector where - DB: Database, - JOURNAL: Journal, + CTX: JournalGetter, { - fn step( - &mut self, - interp: &mut Interpreter, - _context: &mut Context, - ) { + fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { let opcode_value = interp.bytecode.opcode(); if let Some(opcode) = OpCode::new(opcode_value) { // keep track of opcode counts @@ -82,11 +76,7 @@ where } } - fn step_end( - &mut self, - interp: &mut Interpreter, - _context: &mut Context, - ) { + fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) { // update gas usage for the last opcode if let Some((opcode, gas_remaining)) = self.last_opcode_gas_remaining.take() { let gas_cost = gas_remaining.saturating_sub(interp.control.gas().remaining()); @@ -140,11 +130,10 @@ mod tests { ); let db = CacheDB::new(EmptyDB::default()); - // TODO(rakita) fix this - // let mut context = PrevContext::new(db.clone(), SpecId::BERLIN); - // for _ in &opcodes { - // opcode_counter.step(&mut interpreter, &mut context); - // } + let mut context = Context::default().with_db(db); + for _ in &opcodes { + opcode_counter.step(&mut interpreter, &mut context); + } } #[test] @@ -172,10 +161,9 @@ mod tests { ); let db = CacheDB::new(EmptyDB::default()); - // TODO(rakita): fix this - // let mut context: Context<> = Context::new(db.clone(), SpecId::LATEST); - // for _ in opcodes.iter() { - // opcode_counter.step(&mut interpreter, &mut context); - // } + let mut context = Context::default().with_db(db); + for _ in opcodes.iter() { + opcode_counter.step(&mut interpreter, &mut context); + } } } diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index cfc57b07..ec768d4e 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -391,11 +391,7 @@ where W: ContextWiring, ::Error: std::fmt::Display, { - fn step( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.step_fn.is_none() { return; } @@ -422,11 +418,7 @@ where } } - fn step_end( - &mut self, - interp: &mut Interpreter, - context: &mut Context, - ) { + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.step_fn.is_none() { return; } @@ -453,19 +445,9 @@ where } } - fn log( - &mut self, - _interp: &mut Interpreter, - _context: &mut Context, - _log: &Log, - ) { - } + fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, _log: &Log) {} - fn call( - &mut self, - context: &mut Context, - inputs: &mut CallInputs, - ) -> Option { + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { self.register_precompiles(&context.precompiles); // determine contract address based on the call scheme @@ -504,7 +486,7 @@ where fn call_end( &mut self, - _context: &mut Context, + _context: &mut CTX, _inputs: &CallInputs, mut outcome: CallOutcome, ) -> CallOutcome { @@ -524,11 +506,7 @@ where outcome } - fn create( - &mut self, - context: &mut Context, - inputs: &mut CreateInputs, - ) -> Option { + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { self.register_precompiles(&context.precompiles); let _ = context.load_account(inputs.caller); @@ -557,7 +535,7 @@ where fn create_end( &mut self, - _context: &mut Context, + _context: &mut CTX, _inputs: &CreateInputs, mut outcome: CreateOutcome, ) -> CreateOutcome { diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index c148a92c..b995a4b1 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -242,16 +242,16 @@ impl TracingInspector { fn is_precompile_call( &self, // TODO(rakita) - //context: &Context, - to: &Address, - value: &U256, + //context: &CTX, + _to: &Address, + _value: &U256, ) -> bool { // TODO rakita how to support this? //if context.precompiles.contains(to) { // // only if this is _not_ the root call // return self.is_deep() && value.is_zero(); //} - false + self.is_deep() } /// Returns the currently active call trace. diff --git a/src/transfer.rs b/src/transfer.rs index 804b12c9..8217067a 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -1,12 +1,12 @@ use alloy_primitives::{address, b256, Address, Log, LogData, B256, U256}; use alloy_sol_types::SolValue; use revm::{ - context_interface::{Journal, Transaction, TransactionGetter}, + context_interface::{Journal, JournalGetter, Transaction, TransactionGetter}, interpreter::{ interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, EOFCreateKind, }, - Context, Database, JournaledState, + Context, Database, }; use revm_inspector::Inspector; @@ -99,37 +99,26 @@ impl TransferInspector { } } -impl - Inspector, EthInterpreter> for TransferInspector +impl Inspector for TransferInspector where - DB: Database, - JOURNAL: Journal, - TX: Transaction, + CTX: TransactionGetter + JournalGetter, { - fn call( - &mut self, - context: &mut Context, - inputs: &mut CallInputs, - ) -> Option { + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { if let Some(value) = inputs.transfer_value() { self.on_transfer( inputs.transfer_from(), inputs.transfer_to(), value, TransferKind::Call, - &mut context.journaled_state, + context.journal(), ); } None } - fn create( - &mut self, - context: &mut Context, - inputs: &mut CreateInputs, - ) -> Option { - let nonce = context.journaled_state.load_account(inputs.caller).ok()?.data.info.nonce; + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { + let nonce = context.journal().load_account(inputs.caller).ok()?.data.info.nonce; let address = inputs.created_address(nonce); let kind = match inputs.scheme { @@ -137,14 +126,14 @@ where CreateScheme::Create2 { .. } => TransferKind::Create2, }; - self.on_transfer(inputs.caller, address, inputs.value, kind, &mut context.journaled_state); + self.on_transfer(inputs.caller, address, inputs.value, kind, context.journal()); None } fn eofcreate( &mut self, - context: &mut Context, + context: &mut CTX, inputs: &mut revm::interpreter::EOFCreateInputs, ) -> Option { let address = match inputs.kind { @@ -157,7 +146,7 @@ where address, inputs.value, TransferKind::EofCreate, - &mut context.journaled_state, + context.journal(), ); None diff --git a/tests/it/main.rs b/tests/it/main.rs index 10c4caf5..30ee4405 100644 --- a/tests/it/main.rs +++ b/tests/it/main.rs @@ -1,5 +1,5 @@ -// #![allow(missing_docs)] -// pub mod utils; +#![allow(missing_docs)] +pub mod utils; // mod geth; // #[cfg(feature = "js-tracer")] From fb1872fe16cf5cd66930c0e39eb3eb058b8ece98 Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 23 Dec 2024 15:07:23 +0100 Subject: [PATCH 08/15] and with access list --- src/access_list.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/access_list.rs b/src/access_list.rs index e99ec291..73a33672 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -2,7 +2,7 @@ use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::{AccessList, AccessListItem}; use revm::{ bytecode::opcode, - context_interface::Journal, + context_interface::{Journal, JournalGetter}, interpreter::{ interpreter::EthInterpreter, interpreter_types::{InputsTrait, Jumps}, @@ -65,17 +65,11 @@ impl AccessListInspector { } } -impl - Inspector, EthInterpreter> for AccessListInspector +impl Inspector for AccessListInspector where - DB: Database, - JOURNAL: Journal, + CTX: JournalGetter, { - fn step( - &mut self, - interp: &mut Interpreter, - _context: &mut Context, - ) { + fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { match interp.bytecode.opcode() { opcode::SLOAD | opcode::SSTORE => { if let Ok(slot) = interp.stack.peek(0) { From 8c93e30ff80323be7419031e429652b1fa791b0d Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 23 Dec 2024 15:08:58 +0100 Subject: [PATCH 09/15] cleanup requirement --- src/access_list.rs | 7 +------ src/opcode.rs | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/access_list.rs b/src/access_list.rs index 73a33672..0bc919b7 100644 --- a/src/access_list.rs +++ b/src/access_list.rs @@ -2,13 +2,11 @@ use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::{AccessList, AccessListItem}; use revm::{ bytecode::opcode, - context_interface::{Journal, JournalGetter}, interpreter::{ interpreter::EthInterpreter, interpreter_types::{InputsTrait, Jumps}, Interpreter, }, - Context, Database, }; use revm_inspector::Inspector; use std::collections::{BTreeSet, HashMap, HashSet}; @@ -65,10 +63,7 @@ impl AccessListInspector { } } -impl Inspector for AccessListInspector -where - CTX: JournalGetter, -{ +impl Inspector for AccessListInspector { fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { match interp.bytecode.opcode() { opcode::SLOAD | opcode::SSTORE => { diff --git a/src/opcode.rs b/src/opcode.rs index f4d8447d..a02187c0 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -1,13 +1,11 @@ use alloy_rpc_types_trace::opcode::OpcodeGas; use revm::{ bytecode::opcode::{self, OpCode}, - context_interface::{Journal, JournalGetter}, interpreter::{ interpreter::EthInterpreter, interpreter_types::{Immediates, Jumps, LoopControl}, Interpreter, }, - Context, Database, }; use revm_inspector::Inspector; use std::collections::HashMap; @@ -61,10 +59,7 @@ impl OpcodeGasInspector { } } -impl Inspector for OpcodeGasInspector -where - CTX: JournalGetter, -{ +impl Inspector for OpcodeGasInspector { fn step(&mut self, interp: &mut Interpreter, _context: &mut CTX) { let opcode_value = interp.bytecode.opcode(); if let Some(opcode) = OpCode::new(opcode_value) { @@ -108,6 +103,7 @@ mod tests { interpreter::{InputsImpl, SharedMemory}, primitives::Bytes, specification::hardfork::SpecId, + Context, }; use revm_database::CacheDB; use std::{cell::RefCell, rc::Rc}; From 125daa2e7a659aecf996ec326d597971cdcde43e Mon Sep 17 00:00:00 2001 From: rakita Date: Wed, 25 Dec 2024 00:19:38 +0100 Subject: [PATCH 10/15] run tests --- Cargo.toml | 7 +- src/tracing/js/bindings.rs | 28 ++-- src/tracing/js/mod.rs | 117 +++++++++-------- src/transfer.rs | 2 +- tests/it/geth.rs | 45 ++++--- tests/it/geth_js.rs | 44 +++++-- tests/it/main.rs | 12 +- tests/it/parity.rs | 145 +++++++++++++-------- tests/it/transfer.rs | 46 ++++--- tests/it/utils.rs | 255 ++++++++++++++++++++++--------------- tests/it/writer.rs | 42 +++++- 11 files changed, 448 insertions(+), 295 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f06f0f67..27d79c4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ "std", ] } @@ -55,10 +55,11 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "0d987e4c", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ "std", ] } [features] +#default = ["js-tracer"] serde = ["dep:serde", "revm/serde"] js-tracer = ["dep:boa_engine", "dep:boa_gc"] diff --git a/src/tracing/js/bindings.rs b/src/tracing/js/bindings.rs index 61162ccc..1d62141e 100644 --- a/src/tracing/js/bindings.rs +++ b/src/tracing/js/bindings.rs @@ -17,11 +17,10 @@ use boa_engine::{ }; use boa_gc::{empty_trace, Finalize, Trace}; use revm::{ - interpreter::{ - opcode::{PUSH0, PUSH32}, - OpCode, SharedMemory, Stack, - }, - primitives::{AccountInfo, Bytecode, EvmState, KECCAK_EMPTY}, + bytecode::opcode::{OpCode, PUSH0, PUSH32}, + interpreter::{SharedMemory, Stack}, + primitives::KECCAK_EMPTY, + state::{AccountInfo, Bytecode, EvmState}, DatabaseRef, }; use std::{cell::RefCell, rc::Rc}; @@ -277,7 +276,7 @@ impl MemoryRef { let size = end - start; let slice = memory .0 - .with_inner(|mem| mem.slice(start, size).to_vec()) + .with_inner(|mem| mem.slice_len(start, size).to_vec()) .unwrap_or_default(); to_uint8_array_value(slice, ctx) @@ -301,7 +300,7 @@ impl MemoryRef { } let slice = memory .0 - .with_inner(|mem| mem.slice(offset, 32).to_vec()) + .with_inner(|mem| mem.slice_len(offset, 32).to_vec()) .unwrap_or_default(); to_uint8_array_value(slice, ctx) }, @@ -976,7 +975,8 @@ mod tests { json_stringify, register_builtins, to_serde_value, BIG_INT_JS, }; use boa_engine::{property::Attribute, Source}; - use revm::db::{CacheDB, EmptyDB}; + use revm::database_interface::EmptyDB; + use revm_database::CacheDB; #[test] fn test_contract() { @@ -1161,9 +1161,9 @@ mod tests { obj.get(js_string!("step"), &mut context).unwrap().as_object().cloned().unwrap(); let mut stack = Stack::new(); - stack.push(U256::from(35000)).unwrap(); - stack.push(U256::from(35000)).unwrap(); - stack.push(U256::from(35000)).unwrap(); + stack.push(U256::from(35000)); + stack.push(U256::from(35000)); + stack.push(U256::from(35000)); let (stack_ref, _stack_guard) = StackRef::new(&stack); let mem = SharedMemory::new(); let (mem_ref, _mem_guard) = MemoryRef::new(&mem); @@ -1253,9 +1253,9 @@ mod tests { obj.get(js_string!("step"), &mut context).unwrap().as_object().cloned().unwrap(); let mut stack = Stack::new(); - stack.push(U256::from(35000)).unwrap(); - stack.push(U256::from(35000)).unwrap(); - stack.push(U256::from(35000)).unwrap(); + stack.push(U256::from(35000)); + stack.push(U256::from(35000)); + stack.push(U256::from(35000)); let (stack_ref, _stack_guard) = StackRef::new(&stack); let mem = SharedMemory::new(); let (mem_ref, _mem_guard) = MemoryRef::new(&mem); diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index ec768d4e..2e20fb78 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -14,13 +14,19 @@ use alloy_primitives::{Address, Bytes, Log, U256}; pub use boa_engine::vm::RuntimeLimits; use boa_engine::{js_string, Context, JsError, JsObject, JsResult, JsValue, Source}; use revm::{ + context_interface::{ + result::{ExecutionResult, HaltReasonTrait, Output, ResultAndState}, + Block, DatabaseGetter, Journal, JournalGetter, TransactTo, Transaction, + }, interpreter::{ + interpreter::EthInterpreter, + interpreter_types::{Jumps, LoopControl}, return_revert, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, - InstructionResult, Interpreter, InterpreterResult, + InstructionResult, Interpreter, InterpreterResult, InterpreterTypes, }, - primitives::{Env, ExecutionResult, Output, ResultAndState, TransactTo}, - ContextPrecompiles, Database, DatabaseRef, EvmContext, Inspector, + Database, DatabaseRef, }; +use revm_inspector::{Inspector, JournalExt, JournalExtGetter}; pub(crate) mod bindings; pub(crate) mod builtins; @@ -207,26 +213,29 @@ impl JsInspector { /// Note: This is supposed to be called after the inspection has finished. pub fn json_result( &mut self, - res: ResultAndState, - env: &Env, + res: ResultAndState, + tx: &impl Transaction, + block: &impl Block, db: &DB, ) -> Result where DB: DatabaseRef, ::Error: std::fmt::Display, { - let result = self.result(res, env, db)?; + let result = self.result(res, tx, block, db)?; Ok(to_serde_value(result, &mut self.ctx)?) } /// Calls the result function and returns the result. - pub fn result( + pub fn result( &mut self, - res: ResultAndState, - env: &Env, + res: ResultAndState, + tx: &TX, + block: &impl Block, db: &DB, ) -> Result where + TX: Transaction, DB: DatabaseRef, ::Error: std::fmt::Display, { @@ -256,27 +265,27 @@ impl JsInspector { } }; - if let TransactTo::Call(target) = env.tx.transact_to { + if let TransactTo::Call(target) = tx.kind() { to = Some(target); } let ctx = JsEvmContext { - r#type: match env.tx.transact_to { + r#type: match tx.kind() { TransactTo::Call(_) => "CALL", TransactTo::Create => "CREATE", } .to_string(), - from: env.tx.caller, + from: tx.common_fields().caller(), to, - input: env.tx.data.clone(), - gas: env.tx.gas_limit, + input: tx.common_fields().input().clone(), + gas: tx.common_fields().gas_limit(), gas_used, - gas_price: env.tx.gas_price.try_into().unwrap_or(u64::MAX), - value: env.tx.value, - block: env.block.number.try_into().unwrap_or(u64::MAX), - coinbase: env.block.coinbase, + gas_price: tx.effective_gas_price(*block.basefee()).try_into().unwrap_or(u64::MAX), + value: tx.common_fields().value(), + block: block.number().try_into().unwrap_or(u64::MAX), + coinbase: *block.beneficiary(), output: output_bytes.unwrap_or_default(), - time: env.block.timestamp.to_string(), + time: block.timestamp().to_string(), intrinsic_gas: 0, transaction_ctx: self.transaction_context, error, @@ -385,36 +394,34 @@ impl JsInspector { } } -impl Inspector, EthInterpreter> for JsInspector +impl Inspector for JsInspector where - DB: Database + DatabaseRef, - W: ContextWiring, - ::Error: std::fmt::Display, + CTX: JournalGetter + JournalExtGetter + DatabaseGetter, { fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.step_fn.is_none() { return; } - let (db, _db_guard) = EvmDbRef::new(&context.journaled_state.state, &context.db); + let (db, _db_guard) = EvmDbRef::new(&context.journal_ext().evm_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.memory.borrow()); let step = StepLog { stack, - op: interp.current_opcode().into(), + op: interp.bytecode.opcode().into(), memory, - pc: interp.program_counter() as u64, - gas_remaining: interp.gas.remaining(), - cost: interp.gas.spent(), - depth: context.journaled_state.depth(), - refund: interp.gas.refunded() as u64, + pc: interp.bytecode.pc() as u64, + gas_remaining: interp.control.gas().remaining(), + cost: interp.control.gas().spent(), + depth: context.journal().depth() as u64, + refund: interp.control.gas().refunded() as u64, error: None, contract: self.active_call().contract.clone(), }; if self.try_step(step, db).is_err() { - interp.instruction_result = InstructionResult::Revert; + interp.control.set_instruction_result(InstructionResult::Revert); } } @@ -423,21 +430,21 @@ where return; } - if matches!(interp.instruction_result, return_revert!()) { - let (db, _db_guard) = EvmDbRef::new(&context.journaled_state.state, &context.db); + if interp.control.instruction_result().is_revert() { + let (db, _db_guard) = EvmDbRef::new(&context.journal_ext().evm_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.memory.borrow()); let step = StepLog { stack, - op: interp.current_opcode().into(), + op: interp.bytecode.opcode().into(), memory, - pc: interp.program_counter() as u64, - gas_remaining: interp.gas.remaining(), - cost: interp.gas.spent(), - depth: context.journaled_state.depth(), - refund: interp.gas.refunded() as u64, - error: Some(format!("{:?}", interp.instruction_result)), + pc: interp.bytecode.pc() as u64, + gas_remaining: interp.control.gas().remaining(), + cost: interp.control.gas().spent(), + depth: context.journal().depth() as u64, + refund: interp.control.gas().refunded() as u64, + error: Some(format!("{:?}", interp.control.instruction_result())), contract: self.active_call().contract.clone(), }; @@ -488,8 +495,8 @@ where &mut self, _context: &mut CTX, _inputs: &CallInputs, - mut outcome: CallOutcome, - ) -> CallOutcome { + mut outcome: &mut CallOutcome, + ) { if self.can_call_exit() { let frame_result = FrameResult { gas_used: outcome.result.gas.spent(), @@ -502,15 +509,12 @@ where } self.pop_call(); - - outcome } fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { self.register_precompiles(&context.precompiles); - let _ = context.load_account(inputs.caller); - let nonce = context.journaled_state.account(inputs.caller).info.nonce; + let nonce = context.journal().load_account(inputs.caller).unwrap().info.nonce; let contract = inputs.created_address(nonce); self.push_call( contract, @@ -537,8 +541,8 @@ where &mut self, _context: &mut CTX, _inputs: &CreateInputs, - mut outcome: CreateOutcome, - ) -> CreateOutcome { + outcome: &mut CreateOutcome, + ) { if self.can_call_exit() { let frame_result = FrameResult { gas_used: outcome.result.gas.spent(), @@ -551,8 +555,6 @@ where } self.pop_call(); - - outcome } fn selfdestruct(&mut self, _contract: Address, _target: Address, _value: U256) { @@ -633,13 +635,10 @@ mod tests { use alloy_primitives::{hex, Address}; use revm::{ - db::{CacheDB, EmptyDB}, - inspector_handle_register, - primitives::{ - AccountInfo, BlockEnv, Bytecode, CfgEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, - HandlerCfg, SpecId, TransactTo, TxEnv, - }, + database_interface::EmptyDB, + state::{AccountInfo, Bytecode}, }; + use revm_database::CacheDB; use serde_json::json; #[test] @@ -683,7 +682,7 @@ mod tests { db.insert_account_info( addr, AccountInfo { - code: Some(Bytecode::LegacyRaw( + code: Some(Bytecode::new_legacy( /* PUSH1 1, PUSH1 1, STOP */ contract.unwrap_or_else(|| hex!("6001600100").into()), )), diff --git a/src/transfer.rs b/src/transfer.rs index 8217067a..41695f69 100644 --- a/src/transfer.rs +++ b/src/transfer.rs @@ -6,7 +6,7 @@ use revm::{ interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, EOFCreateKind, }, - Context, Database, + Database, }; use revm_inspector::Inspector; diff --git a/tests/it/geth.rs b/tests/it/geth.rs index 22b82dd8..806f9101 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -8,8 +8,11 @@ use alloy_rpc_types_trace::geth::{ GethTrace, PreStateConfig, PreStateFrame, }; use revm::{ - context::TxEnv, context_interface::TransactTo, database_interface::EmptyDB, - specification::hardfork::SpecId, Context, + context::TxEnv, + context_interface::{transaction::TransactionSetter, DatabaseGetter, TransactTo}, + database_interface::EmptyDB, + specification::hardfork::SpecId, + Context, }; use revm_database::CacheDB; use revm_inspectors::tracing::{MuxInspector, TracingInspector, TracingInspectorConfig}; @@ -48,23 +51,26 @@ fn test_geth_calltracer_logs() { } } */ - + let mut context = Context::default().with_db(CacheDB::new(EmptyDB::default())); let code = hex!("608060405234801561001057600080fd5b506103ac806100206000396000f3fe60806040526004361061003f5760003560e01c80630332ed131461014d5780636ae1ad40146101625780638384a00214610177578063de7eb4f31461018c575b60405134815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316636ae1ad406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561009d57600080fd5b505af19250505080156100ae575060015b50306001600160a01b0316630332ed136040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156100ea57600080fd5b505af19250505080156100fb575060015b50306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b005b34801561015957600080fd5b5061014b6101a1565b34801561016e57600080fd5b5061014b610253565b34801561018357600080fd5b5061014b6102b7565b34801561019857600080fd5b5061014b6102dd565b306001600160a01b031663de7eb4f36040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156101dc57600080fd5b505af11580156101f0573d6000803e3d6000fd5b505060405162461bcd60e51b8152602060048201526024808201527f6e6573746564456d6974576974684661696c75726541667465724e6573746564604482015263115b5a5d60e21b6064820152608401915061024a9050565b60405180910390fd5b6040516000815233906000805160206103578339815191529060200160405180910390a260405162461bcd60e51b81526020600482015260156024820152746e6573746564456d6974576974684661696c75726560581b604482015260640161024a565b6040516000815233906000805160206103578339815191529060200160405180910390a2565b6040516000815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561033c57600080fd5b505af1158015610350573d6000803e3d6000fd5b5050505056fef950957d2407bed19dc99b718b46b4ce6090c05589006dfb86fd22c34865b23ea2646970667358221220090a696b9fbd22c7d1cc2a0b6d4a48c32d3ba892480713689a3145b73cfeb02164736f6c63430008130033"); let deployer = Address::ZERO; - let (addr, mut evm) = deploy_contract(code.into(), deployer, SpecId::LONDON); + let addr = deploy_contract(&mut context, code.into(), deployer, SpecId::LONDON) + .created_address() + .unwrap(); let mut insp = TracingInspector::new(TracingInspectorConfig::default_geth().set_record_logs(true)); - let env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(addr), data: Bytes::default(), // call fallback + nonce: 1, ..Default::default() }); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); let call_frame = insp @@ -131,9 +137,13 @@ fn test_geth_mux_tracer() { } */ + let mut context = Context::default().with_db(CacheDB::new(EmptyDB::default())); + let code = hex!("608060405234801561001057600080fd5b506103ac806100206000396000f3fe60806040526004361061003f5760003560e01c80630332ed131461014d5780636ae1ad40146101625780638384a00214610177578063de7eb4f31461018c575b60405134815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316636ae1ad406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561009d57600080fd5b505af19250505080156100ae575060015b50306001600160a01b0316630332ed136040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156100ea57600080fd5b505af19250505080156100fb575060015b50306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b005b34801561015957600080fd5b5061014b6101a1565b34801561016e57600080fd5b5061014b610253565b34801561018357600080fd5b5061014b6102b7565b34801561019857600080fd5b5061014b6102dd565b306001600160a01b031663de7eb4f36040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156101dc57600080fd5b505af11580156101f0573d6000803e3d6000fd5b505060405162461bcd60e51b8152602060048201526024808201527f6e6573746564456d6974576974684661696c75726541667465724e6573746564604482015263115b5a5d60e21b6064820152608401915061024a9050565b60405180910390fd5b6040516000815233906000805160206103578339815191529060200160405180910390a260405162461bcd60e51b81526020600482015260156024820152746e6573746564456d6974576974684661696c75726560581b604482015260640161024a565b6040516000815233906000805160206103578339815191529060200160405180910390a2565b6040516000815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561033c57600080fd5b505af1158015610350573d6000803e3d6000fd5b5050505056fef950957d2407bed19dc99b718b46b4ce6090c05589006dfb86fd22c34865b23ea2646970667358221220090a696b9fbd22c7d1cc2a0b6d4a48c32d3ba892480713689a3145b73cfeb02164736f6c63430008130033"); let deployer = Address::ZERO; - let (addr, mut evm) = deploy_contract(code.into(), deployer, SpecId::LONDON); + let addr = deploy_contract(&mut context, code.into(), deployer, SpecId::LONDON) + .created_address() + .unwrap(); let call_config = CallConfig { only_top_call: Some(false), with_log: Some(true) }; let flatcall_config = @@ -158,18 +168,19 @@ fn test_geth_mux_tracer() { let mut insp = MuxInspector::try_from_config(config.clone()).unwrap(); - let env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(addr), data: Bytes::default(), // call fallback + nonce: 1, ..Default::default() }); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); - let frame = insp.try_into_mux_frame(&res, &evm.db, TransactionInfo::default()).unwrap(); + let frame = insp.try_into_mux_frame(&res, &context.db(), TransactionInfo::default()).unwrap(); assert_eq!(frame.0.len(), 4); assert!(frame.0.contains_key(&GethDebugBuiltInTracerType::FourByteTracer)); @@ -229,10 +240,8 @@ fn test_geth_mux_tracer() { fn test_geth_inspector_reset() { let mut insp = TracingInspector::new(TracingInspectorConfig::default_geth()); - let mut db = CacheDB::new(EmptyDB::default()); - //let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::LONDON)); - let context = Context::default() - .with_db(&mut db) + let mut context = Context::default() + .with_db(CacheDB::new(EmptyDB::default())) .modify_cfg_chained(|cfg| cfg.spec = SpecId::LONDON) .modify_tx_chained(|tx| { tx.caller = Address::ZERO; @@ -244,11 +253,11 @@ fn test_geth_inspector_reset() { assert_eq!(insp.traces().nodes().first().unwrap().trace.gas_limit, 0); // first run inspector - let (res, env) = inspect(&mut context, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); assert_eq!( insp.clone() - .with_transaction_gas_limit(env.tx.gas_limit) + .with_transaction_gas_limit(context.tx.gas_limit) .traces() .nodes() .first() @@ -263,10 +272,10 @@ fn test_geth_inspector_reset() { assert_eq!(insp.traces().nodes().first().unwrap().trace.gas_limit, 0); // second run inspector after reset - let (res, env) = inspect(&mut db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); assert_eq!( - insp.with_transaction_gas_limit(env.tx.gas_limit) + insp.with_transaction_gas_limit(context.tx.gas_limit) .traces() .nodes() .first() diff --git a/tests/it/geth_js.rs b/tests/it/geth_js.rs index 36532396..662197da 100644 --- a/tests/it/geth_js.rs +++ b/tests/it/geth_js.rs @@ -1,8 +1,15 @@ //! Geth Js tracer tests -use crate::utils::{deploy_contract, inspect, TestEvm}; +use crate::utils::{deploy_contract, inspect}; use alloy_primitives::{address, hex, Address}; -use revm::primitives::{SpecId, TransactTo, TxEnv}; +use revm::{ + context::TxEnv, + context_interface::{transaction::TransactionSetter, DatabaseGetter, TransactTo}, + database_interface::EmptyDB, + specification::hardfork::SpecId, + Context, +}; +use revm_database::CacheDB; use revm_inspectors::tracing::js::JsInspector; use serde_json::json; @@ -28,7 +35,13 @@ fn test_geth_jstracer_revert() { let code = hex!("608060405261023e806100115f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063c298557814610038578063febb0f7e14610042575b5f80fd5b61004061004c565b005b61004a61009c565b005b3373ffffffffffffffffffffffffffffffffffffffff167ff950957d2407bed19dc99b718b46b4ce6090c05589006dfb86fd22c34865b23e5f6040516100929190610177565b60405180910390a2565b3373ffffffffffffffffffffffffffffffffffffffff167ff950957d2407bed19dc99b718b46b4ce6090c05589006dfb86fd22c34865b23e5f6040516100e29190610177565b60405180910390a25f61012a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610121906101ea565b60405180910390fd5b565b5f819050919050565b5f819050919050565b5f819050919050565b5f61016161015c6101578461012c565b61013e565b610135565b9050919050565b61017181610147565b82525050565b5f60208201905061018a5f830184610168565b92915050565b5f82825260208201905092915050565b7f62617262617262617200000000000000000000000000000000000000000000005f82015250565b5f6101d4600983610190565b91506101df826101a0565b602082019050919050565b5f6020820190508181035f830152610201816101c8565b905091905056fea2646970667358221220e058dc2c4bd629d62405850cc8e08e6bfad0eea187260784445dfe8f3ee0bea564736f6c634300081a0033"); let deployer = Address::ZERO; - let (addr, mut evm) = deploy_contract(code.into(), deployer, SpecId::CANCUN); + let mut context = Context::default() + .with_db(CacheDB::new(EmptyDB::default())) + .modify_cfg_chained(|cfg| cfg.spec = SpecId::CANCUN); + + let addr = deploy_contract(&mut context, code.into(), deployer, SpecId::CANCUN) + .created_address() + .unwrap(); let code = r#" { @@ -37,7 +50,7 @@ fn test_geth_jstracer_revert() { }"#; // test with normal operation - let mut env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(addr), @@ -46,10 +59,10 @@ fn test_geth_jstracer_revert() { }); let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); - let (res, _) = inspect(&mut evm.db, env.clone(), &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); - let result = insp.json_result(res, &env, &evm.db).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); // sucessful operation assert!(!result["error"].as_bool().unwrap()); @@ -63,10 +76,10 @@ fn test_geth_jstracer_revert() { ..Default::default() }; let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); - let (res, _) = inspect(&mut evm.db, env.clone(), &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(!res.result.is_success()); - let result = insp.json_result(res, &env, &evm.db).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); // reverted operation assert!(result["error"].as_bool().unwrap()); @@ -100,10 +113,15 @@ fn test_geth_jstracer_proxy_contract() { let deployer = address!("f077b491b355e64048ce21e3a6fc4751eeea77fa"); - let mut evm = TestEvm::new(); + let mut context = Context::default() + .with_db(CacheDB::new(EmptyDB::default())) + .modify_cfg_chained(|cfg| cfg.spec = SpecId::CANCUN); // Deploy Implementation(Token) contract - let token_addr = evm.simple_deploy(token_code.into()); + let token_addr = + deploy_contract(&mut context, token_code.into(), Address::default(), SpecId::CANCUN) + .created_address() + .unwrap(); // Deploy Proxy contract let proxy_addr = evm.simple_deploy(proxy_code.into()); @@ -131,7 +149,7 @@ fn test_geth_jstracer_proxy_contract() { result: function() { return this.data; } }"#; let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); - let env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(proxy_addr), @@ -139,9 +157,9 @@ fn test_geth_jstracer_proxy_contract() { ..Default::default() }); - let (res, _) = inspect(&mut evm.db, env.clone(), &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); - let result = insp.json_result(res, &env, &evm.db).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); assert_eq!(result, json!([{"event": "Transfer", "token": proxy_addr, "caller": deployer}])); } diff --git a/tests/it/main.rs b/tests/it/main.rs index 30ee4405..98e8c554 100644 --- a/tests/it/main.rs +++ b/tests/it/main.rs @@ -1,9 +1,9 @@ #![allow(missing_docs)] pub mod utils; -// mod geth; -// #[cfg(feature = "js-tracer")] -// mod geth_js; -// mod parity; -// mod transfer; -// mod writer; +mod geth; +#[cfg(feature = "js-tracer")] +mod geth_js; +mod parity; +mod transfer; +mod writer; diff --git a/tests/it/parity.rs b/tests/it/parity.rs index b4296431..4351648e 100644 --- a/tests/it/parity.rs +++ b/tests/it/parity.rs @@ -1,12 +1,24 @@ //! Parity tests -use crate::utils::{inspect, print_traces, TestEvm}; +use crate::utils::{deploy_contract, inspect, inspect_deploy_contract, print_traces}; use alloy_primitives::{address, hex, map::HashSet, Address, U256}; use alloy_rpc_types_eth::TransactionInfo; use alloy_rpc_types_trace::parity::{ Action, CallAction, CallType, CreationMethod, SelfdestructAction, TraceType, }; -use revm::{database_interface::EmptyDB, specification::hardfork::SpecId, DatabaseCommit}; +use revm::{ + context::TxEnv, + context_interface::{ + block::BlobExcessGasAndPrice, + result::{ExecutionResult, Output}, + transaction::TransactionSetter, + DatabaseGetter, TransactTo, + }, + database_interface::EmptyDB, + specification::hardfork::SpecId, + state::AccountInfo, + Context, DatabaseCommit, +}; use revm_database::CacheDB; use revm_inspectors::tracing::{ parity::populate_state_diff, TracingInspector, TracingInspectorConfig, @@ -38,24 +50,28 @@ fn test_parity_selfdestruct(spec_id: SpecId) { let deployer = address!("341348115259a8bf69f1f50101c227fced83bac6"); let value = U256::from(69); - let mut evm = TestEvm::new_with_spec_id(spec_id); - evm.db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); - evm.env.tx.caller = deployer; - evm.env.tx.value = value; + let mut context = + Context::default().with_db(CacheDB::::default()).modify_db_chained(|db| { + db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); + }); - let addr = evm.simple_deploy(code.into()); + let output = deploy_contract(&mut context, code.into(), deployer, spec_id); + let addr = output.created_address().unwrap(); let mut insp = TracingInspector::new(TracingInspectorConfig::default_parity()); - let env = evm.env_with_tx(TxEnv { - caller: deployer, - gas_limit: 1000000, - transact_to: TransactTo::Call(addr), - data: hex!("43d726d6").into(), - ..Default::default() + context.modify_tx(|tx| { + *tx = TxEnv { + caller: deployer, + gas_limit: 1000000, + transact_to: TransactTo::Call(addr), + data: hex!("43d726d6").into(), + nonce: 1, + ..Default::default() + } }); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success(), "{res:#?}"); assert_eq!(insp.traces().nodes().len(), 1); @@ -102,24 +118,30 @@ fn test_parity_constructor_selfdestruct() { let deployer = Address::ZERO; - let mut evm = TestEvm::new_with_spec_id(SpecId::LONDON); - evm.env.tx.caller = deployer; + let mut context = Context::default() + .with_db(CacheDB::::default()) + .modify_tx_chained(|tx| tx.caller = deployer); let mut insp = TracingInspector::new(TracingInspectorConfig::default_parity()); - let addr = evm.deploy(code.into(), &mut insp).expect("failed to deploy contract"); + let addr = + inspect_deploy_contract(&mut context, code.into(), deployer, SpecId::LONDON, &mut insp) + .created_address() + .expect("contect created"); + print_traces(&insp); let mut insp = TracingInspector::new(TracingInspectorConfig::default_parity()); - let env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(addr), data: hex!("43d726d6").into(), + nonce: 1, ..Default::default() }); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); print_traces(&insp); @@ -148,28 +170,38 @@ fn test_parity_call_selfdestruct() { let deployer = address!("341348115259a8bf69f1f50101c227fced83bac6"); let value = U256::from(69); - let mut evm = TestEvm::new_with_spec_id(SpecId::LONDON); - evm.db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); - evm.env.tx.caller = deployer; - evm.env.tx.value = value; + // let mut evm = TestEvm::new_with_spec_id(SpecId::LONDON); + // evm.db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); + // evm.env.tx.caller = deployer; + // evm.env.tx.value = value; - let to = evm.simple_deploy(code.into()); + let mut context = + Context::default().with_db(CacheDB::::default()).modify_db_chained(|db| { + db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); + }); - evm.db.accounts.get_mut(&to).unwrap().info.balance = balance; + let to = deploy_contract(&mut context, code.into(), deployer, SpecId::LONDON) + .created_address() + .unwrap(); - let env = evm.env_with_tx(TxEnv { - caller, - gas_limit: 100000000, - transact_to: TransactTo::Call(to), - data: input.to_vec().into(), - ..Default::default() + context.db().accounts.get_mut(&to).unwrap().info.balance = balance; + + context.modify_tx(|tx| { + *tx = TxEnv { + caller, + gas_limit: 100000000, + transact_to: TransactTo::Call(to), + data: input.to_vec().into(), + nonce: 1, + ..Default::default() + }; }); let mut insp = TracingInspector::new(TracingInspectorConfig::default_parity()); // evm.env.tx.caller = caller; // let res = evm.call(to, input.to_vec().into(), &mut insp).unwrap(); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); match &res.result { ExecutionResult::Success { output, .. } => match output { Output::Call(_) => {} @@ -177,7 +209,7 @@ fn test_parity_call_selfdestruct() { }, err => panic!("Execution failed: {err:?}"), } - evm.db.commit(res.state); + context.db().commit(res.state); let traces = insp .into_parity_builder() @@ -206,26 +238,23 @@ fn test_parity_call_selfdestruct() { #[test] fn test_parity_statediff_blob_commit() { let caller = address!("283b5b7d75e3e6b84b8e2161e8a468d733bbbe8d"); + let to = address!("15dd773dad3f630773a0e771e9b221f4c8b9b939"); let mut db = CacheDB::new(EmptyDB::default()); - - let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::CANCUN)); - db.insert_account_info( caller, AccountInfo { balance: U256::from(u64::MAX), ..Default::default() }, ); - - let to = address!("15dd773dad3f630773a0e771e9b221f4c8b9b939"); - - let env = EnvWithHandlerCfg::new_with_cfg_env( - cfg.clone(), - BlockEnv { - basefee: U256::from(100), - blob_excess_gas_and_price: Some(BlobExcessGasAndPrice::new(100)), - ..Default::default() - }, - TxEnv { + let mut context = Context::default() + .with_db(db.clone()) + .modify_cfg_chained(|cfg| { + cfg.spec = SpecId::CANCUN; + }) + .modify_block_chained(|b| { + b.basefee = U256::from(100); + b.blob_excess_gas_and_price = Some(BlobExcessGasAndPrice::new(100)); + }) + .with_tx(TxEnv { caller, gas_limit: 1000000, transact_to: TransactTo::Call(to), @@ -235,12 +264,11 @@ fn test_parity_statediff_blob_commit() { .unwrap()], max_fee_per_blob_gas: Some(U256::from(1000000000)), ..Default::default() - }, - ); + }); let trace_types = HashSet::from_iter([TraceType::StateDiff]); let mut insp = TracingInspector::new(TracingInspectorConfig::from_parity_config(&trace_types)); - let (res, _) = inspect(&mut db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); let mut full_trace = insp.into_parity_builder().into_trace_results(&res.result, &trace_types); let state_diff = full_trace.state_diff.as_mut().unwrap(); @@ -275,13 +303,19 @@ fn test_parity_delegatecall_selfdestruct() { let deployer = address!("341348115259a8bf69f1f50101c227fced83bac6"); - let mut evm = TestEvm::new(); + let mut context = Context::default().with_db(CacheDB::::default()); // Deploy DelegateCall contract - let delegate_addr = evm.simple_deploy(delegate_code.into()); + let delegate_addr = + deploy_contract(&mut context, delegate_code.into(), Address::ZERO, SpecId::PRAGUE) + .created_address() + .unwrap(); // Deploy SelfDestructTarget contract - let target_addr = evm.simple_deploy(target_code.into()); + let target_addr = + deploy_contract(&mut context, target_code.into(), Address::ZERO, SpecId::PRAGUE) + .created_address() + .unwrap(); // Prepare the input data for the close(address) function call let mut input_data = hex!("c74073a1").to_vec(); // keccak256("close(address)")[:4] @@ -290,15 +324,16 @@ fn test_parity_delegatecall_selfdestruct() { // Call DelegateCall contract with SelfDestructTarget address let mut insp = TracingInspector::new(TracingInspectorConfig::default_parity()); - let env = evm.env_with_tx(TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(delegate_addr), data: input_data.into(), + nonce: 2, ..Default::default() }); - let (res, _) = inspect(&mut evm.db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); let traces = diff --git a/tests/it/transfer.rs b/tests/it/transfer.rs index 0d97706f..6aec3341 100644 --- a/tests/it/transfer.rs +++ b/tests/it/transfer.rs @@ -1,7 +1,16 @@ //! Transfer tests use alloy_primitives::{hex, Address, U256}; -use revm::{database_interface::EmptyDB, DatabaseCommit}; +use revm::{ + context::TxEnv, + context_interface::{ + result::{ExecutionResult, Output}, + DatabaseGetter, TransactTo, + }, + database_interface::EmptyDB, + specification::hardfork::SpecId, + Context, DatabaseCommit, +}; use revm_database::CacheDB; use crate::utils::inspect; @@ -26,24 +35,21 @@ fn test_internal_transfers() { let mut db = CacheDB::new(EmptyDB::default()); - let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::LONDON)); - - let env = EnvWithHandlerCfg::new_with_cfg_env( - cfg.clone(), - BlockEnv::default(), - TxEnv { + let mut context = Context::default() + .with_db(db) + .modify_cfg_chained(|c| c.spec = SpecId::LONDON) + .with_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Create, data: code.into(), ..Default::default() - }, - ); + }); let mut insp = TracingInspector::new(TracingInspectorConfig::default_geth()); // Create contract - let (res, _) = inspect(&mut db, env, &mut insp).unwrap(); + let res = inspect(&mut context, &mut insp).unwrap(); let addr = match res.result { ExecutionResult::Success { output, .. } => match output { Output::Create(_, addr) => addr.unwrap(), @@ -51,9 +57,9 @@ fn test_internal_transfers() { }, _ => panic!("Execution failed"), }; - db.commit(res.state); + context.db().commit(res.state); - let acc = db.load_account(deployer).unwrap(); + let acc = context.db().load_account(deployer).unwrap(); acc.info.balance = U256::from(u64::MAX); let tx_env = TxEnv { @@ -63,13 +69,17 @@ fn test_internal_transfers() { data: hex!("830c29ae0000000000000000000000000000000000000000000000000000000000000000") .into(), value: U256::from(10), + nonce: 0, ..Default::default() }; let mut insp = TransferInspector::new(false); - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg.clone(), BlockEnv::default(), tx_env.clone()); - let (res, _) = inspect(&mut db, env, &mut insp).unwrap(); + context.modify_tx(|tx| { + *tx = tx_env.clone(); + tx.nonce = 1; + }); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); assert_eq!(insp.transfers().len(), 2); @@ -94,9 +104,11 @@ fn test_internal_transfers() { let mut insp = TransferInspector::internal_only(); - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, BlockEnv::default(), tx_env); - - let (res, _) = inspect(&mut db, env, &mut insp).unwrap(); + context.modify_tx(|tx| { + *tx = tx_env.clone(); + tx.nonce = 1; + }); + let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); assert_eq!(insp.transfers().len(), 1); diff --git a/tests/it/utils.rs b/tests/it/utils.rs index 697ddf56..178a53c1 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -2,11 +2,15 @@ use alloy_primitives::{Address, Bytes, U256}; use colorchoice::ColorChoice; use revm::{ context::{BlockEnv, CfgEnv, TxEnv}, - context_interface::result::{EVMError, HaltReason, InvalidTransaction, ResultAndState}, + context_interface::{ + result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, ResultAndState}, + DatabaseGetter, TransactTo, + }, database_interface::EmptyDB, + handler::EthHandler, interpreter::interpreter::EthInterpreter, specification::hardfork::SpecId, - Context, Database, DatabaseCommit, EvmExec, JournaledState, + Context, Database, DatabaseCommit, Evm, EvmCommit, EvmExec, JournaledState, MainEvm, }; use revm_database::CacheDB; use revm_inspector::{ @@ -18,101 +22,104 @@ use revm_inspectors::tracing::{ }; use std::convert::Infallible; -type TestDb = CacheDB; - -#[derive(Clone, Debug)] -pub struct TestEvm { - pub db: TestDb, - pub env: EnvWithHandlerCfg, -} - -impl Default for TestEvm { - fn default() -> Self { - Self::new() - } -} - -impl TestEvm { - pub fn new() -> Self { - let db = CacheDB::new(EmptyDB::default()); - let env = EnvWithHandlerCfg::new( - Box::new(Env { - block: BlockEnv { gas_limit: U256::MAX, ..Default::default() }, - tx: TxEnv { gas_limit: u64::MAX, gas_price: U256::ZERO, ..Default::default() }, - ..Default::default() - }), - HandlerCfg::new(SpecId::CANCUN), - ); - Self { db, env } - } - - pub fn new_with_spec_id(spec_id: SpecId) -> Self { - let mut evm = Self::new(); - evm.env.handler_cfg.spec_id = spec_id; - evm - } - - pub fn env_with_tx(&self, tx_env: TxEnv) -> EnvWithHandlerCfg { - let mut env = self.env.clone(); - env.tx = tx_env; - env - } - - pub fn simple_deploy(&mut self, data: Bytes) -> Address { - self.deploy(data, TracingInspector::new(TracingInspectorConfig::default_geth())) - .expect("failed to deploy contract") - } - - pub fn deploy GetInspector<&'a mut TestDb>>( - &mut self, - data: Bytes, - inspector: I, - ) -> Result> { - let (_, address) = self.try_deploy(data, inspector)?; - Ok(address.expect("failed to deploy contract")) - } - - pub fn try_deploy GetInspector<&'a mut TestDb>>( - &mut self, - data: Bytes, - inspector: I, - ) -> Result<(ExecutionResult, Option
), EVMError> { - self.env.tx.data = data; - self.env.tx.transact_to = TransactTo::Create; - - let (ResultAndState { result, state }, env) = self.inspect(inspector)?; - self.db.commit(state); - self.env = env; - match &result { - ExecutionResult::Success { output, .. } => { - let address = output.address().copied(); - Ok((result, address)) - } - _ => Ok((result, None)), - } - } - - pub fn call GetInspector<&'a mut TestDb>>( - &mut self, - address: Address, - data: Bytes, - inspector: I, - ) -> Result> { - self.env.tx.data = data; - self.env.tx.transact_to = TransactTo::Call(address); - let (ResultAndState { result, state }, env) = self.inspect(inspector)?; - self.db.commit(state); - self.env = env; - Ok(result) - } - - pub fn inspect GetInspector<&'a mut TestDb>>( - &mut self, - inspector: I, - ) -> Result<(ResultAndState, EnvWithHandlerCfg), EVMError> { - inspect(&mut self.db, self.env.clone(), inspector) - } -} +// type TestDb = CacheDB; + +// #[derive(Clone, Debug)] +// pub struct TestEvm { +// pub context: Context>, +// } + +// impl Default for TestEvm { +// fn default() -> Self { +// Self::new() +// } +// } + +// impl TestEvm { +// pub fn new() -> Self { +// let context = Context::default() +// .modify_block_chained(|b| { +// b.gas_limit = U256::MAX; +// }) +// .modify_tx_chained(|tx| { +// tx.gas_limit = u64::MAX; +// tx.gas_price = U256::ZERO; +// }) +// .with_db(CacheDB::new(EmptyDB::default())) +// .modify_cfg_chained(|cfg| { +// cfg.spec = SpecId::CANCUN; +// }); + +// Self { context } +// } + +// pub fn new_with_spec_id(spec_id: SpecId) -> Self { +// let mut evm = Self::new(); +// evm.context.modify_cfg(|cfg| cfg.spec = spec_id); +// evm +// } + +// pub fn env_with_tx(&self, tx_env: TxEnv) -> EnvWithHandlerCfg { +// let mut env = self.env.clone(); +// env.tx = tx_env; +// env +// } + +// pub fn simple_deploy(&mut self, data: Bytes) -> Address { +// self.deploy(data, TracingInspector::new(TracingInspectorConfig::default_geth())) +// .expect("failed to deploy contract") +// } + +// pub fn deploy GetInspector<&'a mut TestDb>>( +// &mut self, +// data: Bytes, +// inspector: I, +// ) -> Result> { +// let (_, address) = self.try_deploy(data, inspector)?; +// Ok(address.expect("failed to deploy contract")) +// } + +// pub fn try_deploy GetInspector<&'a mut TestDb>>( +// &mut self, +// data: Bytes, +// inspector: I, +// ) -> Result<(ExecutionResult, Option
), EVMError> { +// self.env.tx.data = data; +// self.env.tx.transact_to = TransactTo::Create; + +// let (ResultAndState { result, state }, env) = self.inspect(inspector)?; +// self.db.commit(state); +// self.env = env; +// match &result { +// ExecutionResult::Success { output, .. } => { +// let address = output.address().copied(); +// Ok((result, address)) +// } +// _ => Ok((result, None)), +// } +// } + +// pub fn call GetInspector<&'a mut TestDb>>( +// &mut self, +// address: Address, +// data: Bytes, +// inspector: I, +// ) -> Result> { +// self.env.tx.data = data; +// self.env.tx.transact_to = TransactTo::Call(address); +// let (ResultAndState { result, state }, env) = self.inspect(inspector)?; +// self.db.commit(state); +// self.env = env; +// Ok(result) +// } + +// pub fn inspect GetInspector<&'a mut TestDb>>( +// &mut self, +// inspector: I, +// ) -> Result<(ResultAndState, EnvWithHandlerCfg), EVMError> { +// inspect(&mut self.db, self.env.clone(), inspector) +// } +// } pub type ContextDb = Context, ()>; @@ -147,11 +154,53 @@ pub fn print_traces(tracer: &TracingInspector) { } /// Deploys a contract with the given code and deployer address. -pub fn deploy_contract(code: Bytes, deployer: Address, spec_id: SpecId) -> (Address, TestEvm) { - let mut evm = TestEvm::new(); - - evm.env.tx.caller = deployer; - evm.env.handler_cfg = HandlerCfg::new(spec_id); +pub fn deploy_contract( + context: &mut ContextDb, + code: Bytes, + deployer: Address, + spec: SpecId, +) -> ExecutionResult { + context.modify_tx(|tx| { + *tx = TxEnv { + caller: deployer, + gas_limit: 1000000, + transact_to: TransactTo::Create, + data: code, + ..Default::default() + }; + }); + context.modify_cfg(|cfg| cfg.spec = spec); + + let out = Evm::new(&mut *context, EthHandler::default()) + .exec_commit() + .expect("Expect to be executed"); + context.tx.nonce += 1; + out +} - (evm.simple_deploy(code), evm) +/// Deploys a contract with the given code and deployer address. +pub fn inspect_deploy_contract( + context: &mut ContextDb, + code: Bytes, + deployer: Address, + spec: SpecId, + inspector: I, +) -> ExecutionResult +where + I: for<'a> GetInspector<&'a mut ContextDb, EthInterpreter>, +{ + context.modify_tx(|tx| { + *tx = TxEnv { + caller: deployer, + gas_limit: 1000000, + transact_to: TransactTo::Create, + data: code, + ..Default::default() + }; + }); + context.modify_cfg(|cfg| cfg.spec = spec); + let output = inspect(context, inspector).expect("Expect to be executed"); + context.db().commit(output.state); + context.tx.nonce += 1; + output.result } diff --git a/tests/it/writer.rs b/tests/it/writer.rs index d2b96914..3d60d68b 100644 --- a/tests/it/writer.rs +++ b/tests/it/writer.rs @@ -1,7 +1,14 @@ -use crate::utils::{write_traces_with, TestEvm}; +use crate::utils::{inspect, inspect_deploy_contract, write_traces_with}; use alloy_primitives::{address, b256, bytes, hex, Address, B256, U256}; use alloy_sol_types::{sol, SolCall}; use colorchoice::ColorChoice; +use revm::{ + context_interface::{DatabaseGetter, TransactTo, TransactionGetter}, + database_interface::EmptyDB, + specification::hardfork::SpecId, + Context, DatabaseCommit, +}; +use revm_database::CacheDB; use revm_inspectors::tracing::{ types::{DecodedCallData, DecodedInternalCall, DecodedTraceStep}, TraceWriterConfig, TracingInspector, TracingInspectorConfig, @@ -19,10 +26,19 @@ fn test_trace_printing() { let base_path = &Path::new(OUT_DIR).join("test_trace_printing"); - let mut evm = TestEvm::new(); + let mut context = Context::default().with_db(CacheDB::new(EmptyDB::default())); let mut tracer = TracingInspector::new(TracingInspectorConfig::all()); - let address = evm.deploy(CREATION_CODE.parse().unwrap(), &mut tracer).unwrap(); + //let address = evm.deploy(CREATION_CODE.parse().unwrap(), &mut tracer).unwrap(); + let address = inspect_deploy_contract( + &mut context, + CREATION_CODE.parse().unwrap(), + Address::default(), + SpecId::LONDON, + &mut tracer, + ) + .created_address() + .unwrap(); let mut index = 0; @@ -31,7 +47,14 @@ fn test_trace_printing() { let mut call = |data: Vec| { let mut tracer = TracingInspector::new(TracingInspectorConfig::all()); - let r = evm.call(address, data.into(), &mut tracer).unwrap(); + context.modify_tx(|tx| { + tx.data = data.into(); + tx.transact_to = TransactTo::Call(address); + tx.nonce = index as u64; + }); + let r = inspect(&mut context, &mut tracer).unwrap(); + context.db().commit(r.state); + let r = r.result; assert!(r.is_success(), "evm.call reverted: {r:#?}"); assert_traces(base_path, None, Some(index), &mut tracer); @@ -68,9 +91,16 @@ fn test_trace_printing() { fn deploy_fail() { let base_path = &Path::new(OUT_DIR).join("deploy_fail"); - let mut evm = TestEvm::new(); + let mut context = Context::default().with_db(CacheDB::new(EmptyDB::default())); let mut tracer = TracingInspector::new(TracingInspectorConfig::all()); - let _ = evm.try_deploy(bytes!("604260005260206000fd"), &mut tracer).unwrap(); + + inspect_deploy_contract( + &mut context, + bytes!("604260005260206000fd"), + Address::default(), + SpecId::LONDON, + &mut tracer, + ); assert_traces(base_path, Some("raw"), None, &mut tracer); From 8e46f981653c6c30cf90f181ad9a0f1590ae2155 Mon Sep 17 00:00:00 2001 From: rakita Date: Wed, 25 Dec 2024 17:44:13 +0100 Subject: [PATCH 11/15] fix all tests --- Cargo.toml | 6 +-- src/tracing/arena.rs | 2 + src/tracing/mod.rs | 18 +++---- tests/it/parity.rs | 19 +++---- tests/it/transfer.rs | 2 +- tests/it/utils.rs | 126 +++---------------------------------------- tests/it/writer.rs | 4 +- 7 files changed, 35 insertions(+), 142 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27d79c4f..23934a3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "a0e82657", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ "std", ] } diff --git a/src/tracing/arena.rs b/src/tracing/arena.rs index ebe97f01..46ab2fc4 100644 --- a/src/tracing/arena.rs +++ b/src/tracing/arena.rs @@ -53,6 +53,7 @@ impl CallTraceArena { kind: PushTraceKind, new_trace: CallTrace, ) -> usize { + println!("entry: {:?} kind {kind:?}, new_trace: {new_trace:?}", entry); loop { match new_trace.depth { // The entry node, just update it @@ -91,6 +92,7 @@ impl CallTraceArena { } /// How to push a trace into the arena +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) enum PushTraceKind { /// This will _only_ push the trace into the arena. PushOnly, diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index b995a4b1..7a567842 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -251,7 +251,8 @@ impl TracingInspector { // // only if this is _not_ the root call // return self.is_deep() && value.is_zero(); //} - self.is_deep() + let _ = self.is_deep(); + false } /// Returns the currently active call trace. @@ -494,7 +495,7 @@ impl TracingInspector { if self.config.record_state_diff { let op = step.op.get(); - let journal_entry = context.journal_ext().last_journal().last().cloned(); + let journal_entry = context.journal_ext().last_journal().last(); step.storage_change = match (op, journal_entry) { ( @@ -502,15 +503,15 @@ impl TracingInspector { Some(JournalEntry::StorageChanged { address, key, had_value }), ) => { // SAFETY: (Address,key) exists if part if StorageChange - //TODO let value = - // context.journal_ext().state[address].storage[key].present_value(); - let value = U256::ZERO; + let value = + context.journal_ext().evm_state()[address].storage[&key].present_value(); let reason = match op { opcode::SLOAD => StorageChangeReason::SLOAD, opcode::SSTORE => StorageChangeReason::SSTORE, _ => unreachable!(), }; - let change = StorageChange { key, value, had_value: Some(had_value), reason }; + let change = + StorageChange { key: *key, value, had_value: Some(*had_value), reason }; Some(change) } _ => None, @@ -541,7 +542,6 @@ where #[inline] fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.config.record_steps { - // TODO(rakita) fix this self.fill_step_on_step_end(interp, context); } } @@ -616,7 +616,7 @@ where fn create_end( &mut self, - context: &mut CTX, + _context: &mut CTX, _inputs: &CreateInputs, outcome: &mut CreateOutcome, ) { @@ -651,7 +651,7 @@ where fn eofcreate_end( &mut self, - context: &mut CTX, + _context: &mut CTX, _inputs: &EOFCreateInputs, outcome: &mut CreateOutcome, ) { diff --git a/tests/it/parity.rs b/tests/it/parity.rs index 4351648e..63dc0ff0 100644 --- a/tests/it/parity.rs +++ b/tests/it/parity.rs @@ -55,6 +55,7 @@ fn test_parity_selfdestruct(spec_id: SpecId) { db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); }); + context.modify_tx(|tx| tx.value = value); let output = deploy_contract(&mut context, code.into(), deployer, spec_id); let addr = output.created_address().unwrap(); @@ -170,14 +171,14 @@ fn test_parity_call_selfdestruct() { let deployer = address!("341348115259a8bf69f1f50101c227fced83bac6"); let value = U256::from(69); - // let mut evm = TestEvm::new_with_spec_id(SpecId::LONDON); - // evm.db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); - // evm.env.tx.caller = deployer; - // evm.env.tx.value = value; - - let mut context = - Context::default().with_db(CacheDB::::default()).modify_db_chained(|db| { + let mut context = Context::default() + .with_db(CacheDB::::default()) + .modify_db_chained(|db| { db.insert_account_info(deployer, AccountInfo { balance: value, ..Default::default() }); + }) + .modify_tx_chained(|tx| { + tx.caller = deployer; + tx.value = value; }); let to = deploy_contract(&mut context, code.into(), deployer, SpecId::LONDON) @@ -192,7 +193,7 @@ fn test_parity_call_selfdestruct() { gas_limit: 100000000, transact_to: TransactTo::Call(to), data: input.to_vec().into(), - nonce: 1, + nonce: 0, ..Default::default() }; }); @@ -329,7 +330,7 @@ fn test_parity_delegatecall_selfdestruct() { gas_limit: 1000000, transact_to: TransactTo::Call(delegate_addr), data: input_data.into(), - nonce: 2, + nonce: 0, ..Default::default() }); diff --git a/tests/it/transfer.rs b/tests/it/transfer.rs index 6aec3341..fbce9f58 100644 --- a/tests/it/transfer.rs +++ b/tests/it/transfer.rs @@ -33,7 +33,7 @@ fn test_internal_transfers() { let code = hex!("608060405234801561001057600080fd5b5060ef8061001f6000396000f3fe608060405260043610601c5760003560e01c8063830c29ae146021575b600080fd5b6030602c366004608b565b6032565b005b600080826001600160a01b03163460405160006040518083038185875af1925050503d8060008114607e576040519150601f19603f3d011682016040523d82523d6000602084013e6083565b606091505b505050505050565b600060208284031215609c57600080fd5b81356001600160a01b038116811460b257600080fd5b939250505056fea26469706673582212201654bdbf09c088897c9b02f3ba9df280b136ef99c3a05ca5a21d9a10fd912d3364736f6c634300080d0033"); let deployer = Address::ZERO; - let mut db = CacheDB::new(EmptyDB::default()); + let db = CacheDB::new(EmptyDB::default()); let mut context = Context::default() .with_db(db) diff --git a/tests/it/utils.rs b/tests/it/utils.rs index 178a53c1..7dc517c7 100644 --- a/tests/it/utils.rs +++ b/tests/it/utils.rs @@ -1,4 +1,4 @@ -use alloy_primitives::{Address, Bytes, U256}; +use alloy_primitives::{Address, Bytes}; use colorchoice::ColorChoice; use revm::{ context::{BlockEnv, CfgEnv, TxEnv}, @@ -6,120 +6,13 @@ use revm::{ result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction, ResultAndState}, DatabaseGetter, TransactTo, }, - database_interface::EmptyDB, handler::EthHandler, interpreter::interpreter::EthInterpreter, specification::hardfork::SpecId, - Context, Database, DatabaseCommit, Evm, EvmCommit, EvmExec, JournaledState, MainEvm, + Context, Database, DatabaseCommit, Evm, EvmCommit, EvmExec, JournaledState, }; -use revm_database::CacheDB; -use revm_inspector::{ - inspector_handler, GetInspector, Inspector, InspectorContext, InspectorHandler, - InspectorMainEvm, -}; -use revm_inspectors::tracing::{ - TraceWriter, TraceWriterConfig, TracingInspector, TracingInspectorConfig, -}; -use std::convert::Infallible; - -// type TestDb = CacheDB; - -// #[derive(Clone, Debug)] -// pub struct TestEvm { -// pub context: Context>, -// } - -// impl Default for TestEvm { -// fn default() -> Self { -// Self::new() -// } -// } - -// impl TestEvm { -// pub fn new() -> Self { -// let context = Context::default() -// .modify_block_chained(|b| { -// b.gas_limit = U256::MAX; -// }) -// .modify_tx_chained(|tx| { -// tx.gas_limit = u64::MAX; -// tx.gas_price = U256::ZERO; -// }) -// .with_db(CacheDB::new(EmptyDB::default())) -// .modify_cfg_chained(|cfg| { -// cfg.spec = SpecId::CANCUN; -// }); - -// Self { context } -// } - -// pub fn new_with_spec_id(spec_id: SpecId) -> Self { -// let mut evm = Self::new(); -// evm.context.modify_cfg(|cfg| cfg.spec = spec_id); -// evm -// } - -// pub fn env_with_tx(&self, tx_env: TxEnv) -> EnvWithHandlerCfg { -// let mut env = self.env.clone(); -// env.tx = tx_env; -// env -// } - -// pub fn simple_deploy(&mut self, data: Bytes) -> Address { -// self.deploy(data, TracingInspector::new(TracingInspectorConfig::default_geth())) -// .expect("failed to deploy contract") -// } - -// pub fn deploy GetInspector<&'a mut TestDb>>( -// &mut self, -// data: Bytes, -// inspector: I, -// ) -> Result> { -// let (_, address) = self.try_deploy(data, inspector)?; -// Ok(address.expect("failed to deploy contract")) -// } - -// pub fn try_deploy GetInspector<&'a mut TestDb>>( -// &mut self, -// data: Bytes, -// inspector: I, -// ) -> Result<(ExecutionResult, Option
), EVMError> { -// self.env.tx.data = data; -// self.env.tx.transact_to = TransactTo::Create; - -// let (ResultAndState { result, state }, env) = self.inspect(inspector)?; -// self.db.commit(state); -// self.env = env; -// match &result { -// ExecutionResult::Success { output, .. } => { -// let address = output.address().copied(); -// Ok((result, address)) -// } -// _ => Ok((result, None)), -// } -// } - -// pub fn call GetInspector<&'a mut TestDb>>( -// &mut self, -// address: Address, -// data: Bytes, -// inspector: I, -// ) -> Result> { -// self.env.tx.data = data; -// self.env.tx.transact_to = TransactTo::Call(address); -// let (ResultAndState { result, state }, env) = self.inspect(inspector)?; -// self.db.commit(state); -// self.env = env; -// Ok(result) -// } - -// pub fn inspect GetInspector<&'a mut TestDb>>( -// &mut self, -// inspector: I, -// ) -> Result<(ResultAndState, EnvWithHandlerCfg), EVMError> { -// inspect(&mut self.db, self.env.clone(), inspector) -// } -// } +use revm_inspector::{inspector_handler, GetInspector, InspectorContext, InspectorMainEvm}; +use revm_inspectors::tracing::{TraceWriter, TraceWriterConfig, TracingInspector}; pub type ContextDb = Context, ()>; @@ -161,13 +54,10 @@ pub fn deploy_contract( spec: SpecId, ) -> ExecutionResult { context.modify_tx(|tx| { - *tx = TxEnv { - caller: deployer, - gas_limit: 1000000, - transact_to: TransactTo::Create, - data: code, - ..Default::default() - }; + tx.caller = deployer; + tx.gas_limit = 1000000; + tx.transact_to = TransactTo::Create; + tx.data = code; }); context.modify_cfg(|cfg| cfg.spec = spec); diff --git a/tests/it/writer.rs b/tests/it/writer.rs index 3d60d68b..7cc7b524 100644 --- a/tests/it/writer.rs +++ b/tests/it/writer.rs @@ -3,7 +3,7 @@ use alloy_primitives::{address, b256, bytes, hex, Address, B256, U256}; use alloy_sol_types::{sol, SolCall}; use colorchoice::ColorChoice; use revm::{ - context_interface::{DatabaseGetter, TransactTo, TransactionGetter}, + context_interface::{DatabaseGetter, TransactTo}, database_interface::EmptyDB, specification::hardfork::SpecId, Context, DatabaseCommit, @@ -34,7 +34,7 @@ fn test_trace_printing() { &mut context, CREATION_CODE.parse().unwrap(), Address::default(), - SpecId::LONDON, + SpecId::CANCUN, &mut tracer, ) .created_address() From 509a16cd784163ba58e9c15334fbfc9f60d19de0 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 26 Dec 2024 00:24:15 +0100 Subject: [PATCH 12/15] enable is_precompile --- Cargo.toml | 6 +++--- src/tracing/mod.rs | 25 ++++++++++++------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 23934a3a..9c1c1a01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "d0a65323", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ "std", ] } diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 7a567842..b02f6af0 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -239,19 +239,16 @@ impl TracingInspector { /// /// Returns true if the `to` address is a precompile contract and the value is zero. #[inline] - fn is_precompile_call( + fn is_precompile_call( &self, - // TODO(rakita) - //context: &CTX, - _to: &Address, - _value: &U256, + context: &CTX, + to: &Address, + value: &U256, ) -> bool { - // TODO rakita how to support this? - //if context.precompiles.contains(to) { - // // only if this is _not_ the root call - // return self.is_deep() && value.is_zero(); - //} - let _ = self.is_deep(); + if context.journal_ref().contains_precompile(to) { + // only if this is _not_ the root call + return self.is_deep() && value.is_zero(); + } false } @@ -576,8 +573,10 @@ 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(&to, &value)); + let maybe_precompile = self + .config + .exclude_precompile_calls + .then(|| self.is_precompile_call(context, &to, &value)); self.start_trace_on_call( context, From 8e703f3e3d2bf73a140a727205a7183dae6cacc0 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 26 Dec 2024 12:20:18 +0100 Subject: [PATCH 13/15] js tracer integrated --- Cargo.toml | 2 +- src/tracing/js/bindings.rs | 49 +++++++++++++++++-------- src/tracing/js/mod.rs | 73 +++++++++++++++++++------------------- src/tracing/mod.rs | 4 +-- src/tracing/types.rs | 3 +- tests/it/geth_js.rs | 21 +++++++---- 6 files changed, 88 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c1c1a01..f8e68eaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,6 @@ revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e ] } [features] -#default = ["js-tracer"] +default = ["js-tracer"] serde = ["dep:serde", "revm/serde"] js-tracer = ["dep:boa_engine", "dep:boa_gc"] diff --git a/src/tracing/js/bindings.rs b/src/tracing/js/bindings.rs index 1d62141e..cfccf4ef 100644 --- a/src/tracing/js/bindings.rs +++ b/src/tracing/js/bindings.rs @@ -18,6 +18,7 @@ use boa_engine::{ use boa_gc::{empty_trace, Finalize, Trace}; use revm::{ bytecode::opcode::{OpCode, PUSH0, PUSH32}, + context_interface::DBErrorMarker, interpreter::{SharedMemory, Stack}, primitives::KECCAK_EMPTY, state::{AccountInfo, Bytecode, EvmState}, @@ -764,8 +765,8 @@ impl EvmDbRef { let db = JsDb(db); let js_db = unsafe { std::mem::transmute::< - Box + '_>, - Box + 'static>, + Box + '_>, + Box + 'static>, >(Box::new(db)) }; @@ -929,7 +930,7 @@ unsafe impl Trace for EvmDbRef { /// DB is the object that allows the js inspector to interact with the database. struct EvmDbRefInner { state: StateRef, - db: GcDb + 'static>>, + db: GcDb + 'static>>, } /// Guard the inner references, once this value is dropped the inner reference is also removed. @@ -938,33 +939,51 @@ struct EvmDbRefInner { #[must_use] pub(crate) struct EvmDbGuard<'a, 'b> { _state_guard: GcGuard<'a, EvmState>, - _db_guard: GcGuard<'b, Box + 'static>>, + _db_guard: GcGuard<'b, Box + 'static>>, } /// A wrapper Database for the JS context. pub(crate) struct JsDb(DB); +#[derive(Clone, Debug)] +pub(crate) struct StringError(pub String); + +impl core::error::Error for StringError {} +impl DBErrorMarker for StringError {} + +impl core::fmt::Display for StringError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for StringError { + fn from(s: String) -> Self { + Self(s) + } +} + impl DatabaseRef for JsDb where DB: DatabaseRef, DB::Error: std::fmt::Display, { - type Error = String; + type Error = StringError; fn basic_ref(&self, _address: Address) -> Result, Self::Error> { - self.0.basic_ref(_address).map_err(|e| e.to_string()) + self.0.basic_ref(_address).map_err(|e| e.to_string().into()) } fn code_by_hash_ref(&self, _code_hash: B256) -> Result { - self.0.code_by_hash_ref(_code_hash).map_err(|e| e.to_string()) + self.0.code_by_hash_ref(_code_hash).map_err(|e| e.to_string().into()) } fn storage_ref(&self, _address: Address, _index: U256) -> Result { - self.0.storage_ref(_address, _index).map_err(|e| e.to_string()) + self.0.storage_ref(_address, _index).map_err(|e| e.to_string().into()) } fn block_hash_ref(&self, _number: u64) -> Result { - self.0.block_hash_ref(_number).map_err(|e| e.to_string()) + self.0.block_hash_ref(_number).map_err(|e| e.to_string().into()) } } @@ -1161,9 +1180,9 @@ mod tests { obj.get(js_string!("step"), &mut context).unwrap().as_object().cloned().unwrap(); let mut stack = Stack::new(); - stack.push(U256::from(35000)); - stack.push(U256::from(35000)); - stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); let (stack_ref, _stack_guard) = StackRef::new(&stack); let mem = SharedMemory::new(); let (mem_ref, _mem_guard) = MemoryRef::new(&mem); @@ -1253,9 +1272,9 @@ mod tests { obj.get(js_string!("step"), &mut context).unwrap().as_object().cloned().unwrap(); let mut stack = Stack::new(); - stack.push(U256::from(35000)); - stack.push(U256::from(35000)); - stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); + let _ = stack.push(U256::from(35000)); let (stack_ref, _stack_guard) = StackRef::new(&stack); let mem = SharedMemory::new(); let (mem_ref, _mem_guard) = MemoryRef::new(&mem); diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 2e20fb78..128714ad 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -21,9 +21,10 @@ use revm::{ interpreter::{ interpreter::EthInterpreter, interpreter_types::{Jumps, LoopControl}, - return_revert, CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, - InstructionResult, Interpreter, InterpreterResult, InterpreterTypes, + CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult, + Interpreter, InterpreterResult, }, + primitives::HashSet, Database, DatabaseRef, }; use revm_inspector::{Inspector, JournalExt, JournalExtGetter}; @@ -382,11 +383,13 @@ impl JsInspector { } /// Registers the precompiles in the JS context - fn register_precompiles(&mut self, precompiles: &ContextPrecompiles) { + fn register_precompiles(&mut self, _context: &mut CTX) { if !self.precompiles_registered { return; } - let precompiles = PrecompileList(precompiles.addresses().copied().collect()); + let precompiles = PrecompileList(HashSet::default()); + // TODO(rakita) : add precompile_addresses to Journal. + // context.journal().warm_precompiles(addresses);.addresses().copied().collect()); let _ = precompiles.register_callable(&mut self.ctx); @@ -396,17 +399,18 @@ impl JsInspector { impl Inspector for JsInspector where - CTX: JournalGetter + JournalExtGetter + DatabaseGetter, + CTX: JournalGetter + JournalExtGetter + DatabaseGetter, { fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { if self.step_fn.is_none() { return; } - let (db, _db_guard) = EvmDbRef::new(&context.journal_ext().evm_state(), &context.db()); + let (db, _db_guard) = EvmDbRef::new(context.journal_ext().evm_state(), context.db_ref()); let (stack, _stack_guard) = StackRef::new(&interp.stack); - let (memory, _memory_guard) = MemoryRef::new(&interp.memory.borrow()); + let evm_memory = interp.memory.borrow(); + let (memory, _memory_guard) = MemoryRef::new(&evm_memory); let step = StepLog { stack, op: interp.bytecode.opcode().into(), @@ -414,7 +418,7 @@ where pc: interp.bytecode.pc() as u64, gas_remaining: interp.control.gas().remaining(), cost: interp.control.gas().spent(), - depth: context.journal().depth() as u64, + depth: context.journal_ref().depth() as u64, refund: interp.control.gas().refunded() as u64, error: None, contract: self.active_call().contract.clone(), @@ -431,10 +435,12 @@ where } if interp.control.instruction_result().is_revert() { - let (db, _db_guard) = EvmDbRef::new(&context.journal_ext().evm_state(), &context.db()); + let (db, _db_guard) = + EvmDbRef::new(context.journal_ext().evm_state(), context.db_ref()); let (stack, _stack_guard) = StackRef::new(&interp.stack); - let (memory, _memory_guard) = MemoryRef::new(&interp.memory.borrow()); + let mem = interp.memory.borrow(); + let (memory, _memory_guard) = MemoryRef::new(&mem); let step = StepLog { stack, op: interp.bytecode.opcode().into(), @@ -442,7 +448,7 @@ where pc: interp.bytecode.pc() as u64, gas_remaining: interp.control.gas().remaining(), cost: interp.control.gas().spent(), - depth: context.journal().depth() as u64, + depth: context.journal_ref().depth() as u64, refund: interp.control.gas().refunded() as u64, error: Some(format!("{:?}", interp.control.instruction_result())), contract: self.active_call().contract.clone(), @@ -455,7 +461,7 @@ where fn log(&mut self, _interp: &mut Interpreter, _context: &mut CTX, _log: &Log) {} fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { - self.register_precompiles(&context.precompiles); + self.register_precompiles(context); // determine contract address based on the call scheme let contract = match inputs.scheme { @@ -491,12 +497,7 @@ where None } - fn call_end( - &mut self, - _context: &mut CTX, - _inputs: &CallInputs, - mut outcome: &mut CallOutcome, - ) { + fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) { if self.can_call_exit() { let frame_result = FrameResult { gas_used: outcome.result.gas.spent(), @@ -512,7 +513,7 @@ where } fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { - self.register_precompiles(&context.precompiles); + self.register_precompiles(context); let nonce = context.journal().load_account(inputs.caller).unwrap().info.nonce; let contract = inputs.created_address(nonce); @@ -635,10 +636,15 @@ mod tests { use alloy_primitives::{hex, Address}; use revm::{ + context::TxEnv, + context_interface::{BlockGetter, TransactionGetter}, database_interface::EmptyDB, + specification::hardfork::SpecId, state::{AccountInfo, Bytecode}, + EvmExec, }; use revm_database::CacheDB; + use revm_inspector::{inspector_handler, InspectorContext, InspectorMainEvm}; use serde_json::json; #[test] @@ -690,31 +696,24 @@ mod tests { }, ); - let cfg = CfgEnvWithHandlerCfg::new(CfgEnv::default(), HandlerCfg::new(SpecId::CANCUN)); - let env = EnvWithHandlerCfg::new_with_cfg_env( - cfg.clone(), - BlockEnv::default(), - TxEnv { + let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); + + let mut context = revm::Context::default() + .modify_cfg_chained(|cfg| cfg.spec = SpecId::CANCUN) + .with_db(db) + .with_tx(TxEnv { gas_price: U256::from(1024), gas_limit: 1_000_000, transact_to: TransactTo::Call(addr), ..Default::default() - }, - ); - - let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); + }); - let res = revm::Evm::builder() - .with_db(db.clone()) - .with_external_context(&mut insp) - .with_env_with_handler_cfg(env.clone()) - .append_handler_register(inspector_handle_register) - .build() - .transact() - .unwrap(); + let ctx = InspectorContext::new(&mut context, &mut insp); + let mut evm = InspectorMainEvm::new(ctx, inspector_handler()); + let res = evm.exec().expect("pass without error"); assert_eq!(res.result.is_success(), success); - insp.json_result(res, &env, &db).unwrap() + insp.json_result(res, context.tx(), context.block(), context.db_ref()).unwrap() } #[test] diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index b02f6af0..328e2094 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -320,7 +320,7 @@ impl TracingInspector { 0, push_kind, CallTrace { - depth: context.journal().depth() as usize, + depth: context.journal().depth(), address, kind, data: input_data, @@ -501,7 +501,7 @@ impl TracingInspector { ) => { // SAFETY: (Address,key) exists if part if StorageChange let value = - context.journal_ext().evm_state()[address].storage[&key].present_value(); + context.journal_ext().evm_state()[address].storage[key].present_value(); let reason = match op { opcode::SLOAD => StorageChangeReason::SLOAD, opcode::SSTORE => StorageChangeReason::SSTORE, diff --git a/src/tracing/types.rs b/src/tracing/types.rs index b52250bf..232c0074 100644 --- a/src/tracing/types.rs +++ b/src/tracing/types.rs @@ -859,7 +859,6 @@ mod opcode_serde { D: Deserializer<'de>, { let op = u8::deserialize(deserializer)?; - Ok(OpCode::new(op) - .unwrap_or_else(|| OpCode::new(revm::interpreter::opcode::INVALID).unwrap())) + Ok(OpCode::new(op).unwrap_or_else(|| OpCode::new(revm::bytecode::opcode::INVALID).unwrap())) } } diff --git a/tests/it/geth_js.rs b/tests/it/geth_js.rs index 662197da..666dfb00 100644 --- a/tests/it/geth_js.rs +++ b/tests/it/geth_js.rs @@ -4,7 +4,9 @@ use crate::utils::{deploy_contract, inspect}; use alloy_primitives::{address, hex, Address}; use revm::{ context::TxEnv, - context_interface::{transaction::TransactionSetter, DatabaseGetter, TransactTo}, + context_interface::{ + transaction::TransactionSetter, BlockGetter, DatabaseGetter, TransactTo, TransactionGetter, + }, database_interface::EmptyDB, specification::hardfork::SpecId, Context, @@ -55,6 +57,7 @@ fn test_geth_jstracer_revert() { gas_limit: 1000000, transact_to: TransactTo::Call(addr), data: hex!("c2985578").into(), // call foo + nonce: 1, ..Default::default() }); @@ -62,24 +65,25 @@ fn test_geth_jstracer_revert() { let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); - let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db_ref()).unwrap(); // sucessful operation assert!(!result["error"].as_bool().unwrap()); // test with reverted operation - env.tx = TxEnv { + context.set_tx(TxEnv { caller: deployer, gas_limit: 1000000, transact_to: TransactTo::Call(addr), data: hex!("febb0f7e").into(), // call bar + nonce: 1, ..Default::default() - }; + }); let mut insp = JsInspector::new(code.to_string(), serde_json::Value::Null).unwrap(); let res = inspect(&mut context, &mut insp).unwrap(); assert!(!res.result.is_success()); - let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db_ref()).unwrap(); // reverted operation assert!(result["error"].as_bool().unwrap()); @@ -124,7 +128,10 @@ fn test_geth_jstracer_proxy_contract() { .unwrap(); // Deploy Proxy contract - let proxy_addr = evm.simple_deploy(proxy_code.into()); + let proxy_addr = + deploy_contract(&mut context, proxy_code.into(), Address::ZERO, SpecId::CANCUN) + .created_address() + .unwrap(); // Set input data for ProxyFactory.transfer(address) let mut input_data = hex!("1a695230").to_vec(); // keccak256("transfer(address)")[:4] @@ -160,6 +167,6 @@ fn test_geth_jstracer_proxy_contract() { let res = inspect(&mut context, &mut insp).unwrap(); assert!(res.result.is_success()); - let result = insp.json_result(res, context.tx(), context.block(), context.db()).unwrap(); + let result = insp.json_result(res, context.tx(), context.block(), context.db_ref()).unwrap(); assert_eq!(result, json!([{"event": "Transfer", "token": proxy_addr, "caller": deployer}])); } From 26703d2dc8006599abecbe7498ae16df9ecd5f43 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 26 Dec 2024 13:32:33 +0100 Subject: [PATCH 14/15] precompile addresses --- Cargo.toml | 6 +++--- src/tracing/js/builtins.rs | 3 ++- src/tracing/js/mod.rs | 7 ++----- src/tracing/mod.rs | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f8e68eaa..54d3348d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,10 +34,10 @@ alloy-rpc-types-eth = "0.8" alloy-rpc-types-trace = "0.8" alloy-sol-types = "0.8" alloy-primitives = { version = "0.8", features = ["map"] } -revm = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ +revm = { git = "https://github.com/bluealloy/revm.git", rev = "3c0c034f", default-features = false, features = [ "std", ] } -revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ +revm-inspector = { git = "https://github.com/bluealloy/revm.git", rev = "3c0c034f", default-features = false, features = [ "std", ] } @@ -55,7 +55,7 @@ boa_gc = { version = "0.19", optional = true } [dev-dependencies] snapbox = { version = "0.6", features = ["term-svg"] } -revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "90a6fc6e", default-features = false, features = [ +revm-database = { git = "https://github.com/bluealloy/revm.git", rev = "3c0c034f", default-features = false, features = [ "std", ] } diff --git a/src/tracing/js/builtins.rs b/src/tracing/js/builtins.rs index 088ae31a..93a6de7c 100644 --- a/src/tracing/js/builtins.rs +++ b/src/tracing/js/builtins.rs @@ -9,7 +9,8 @@ use boa_engine::{ Context, JsArgs, JsError, JsNativeError, JsResult, JsString, JsValue, NativeFunction, Source, }; use boa_gc::{empty_trace, Finalize, Trace}; -use std::{borrow::Borrow, collections::HashSet}; +use revm::primitives::HashSet; +use std::borrow::Borrow; /// bigIntegerJS is the minified version of . pub(crate) const BIG_INT_JS: &str = include_str!("bigint.js"); diff --git a/src/tracing/js/mod.rs b/src/tracing/js/mod.rs index 128714ad..d140d4f7 100644 --- a/src/tracing/js/mod.rs +++ b/src/tracing/js/mod.rs @@ -24,7 +24,6 @@ use revm::{ CallInputs, CallOutcome, CallScheme, CreateInputs, CreateOutcome, Gas, InstructionResult, Interpreter, InterpreterResult, }, - primitives::HashSet, Database, DatabaseRef, }; use revm_inspector::{Inspector, JournalExt, JournalExtGetter}; @@ -383,13 +382,11 @@ impl JsInspector { } /// Registers the precompiles in the JS context - fn register_precompiles(&mut self, _context: &mut CTX) { + fn register_precompiles(&mut self, context: &mut CTX) { if !self.precompiles_registered { return; } - let precompiles = PrecompileList(HashSet::default()); - // TODO(rakita) : add precompile_addresses to Journal. - // context.journal().warm_precompiles(addresses);.addresses().copied().collect()); + let precompiles = PrecompileList(context.journal().precompile_addresses().clone()); let _ = precompiles.register_callable(&mut self.ctx); diff --git a/src/tracing/mod.rs b/src/tracing/mod.rs index 328e2094..63cee351 100644 --- a/src/tracing/mod.rs +++ b/src/tracing/mod.rs @@ -245,7 +245,7 @@ impl TracingInspector { to: &Address, value: &U256, ) -> bool { - if context.journal_ref().contains_precompile(to) { + if context.journal_ref().precompile_addresses().contains(to) { // only if this is _not_ the root call return self.is_deep() && value.is_zero(); } From 5a062c36b5059ffacb09601fbc8df7fd13bcbea6 Mon Sep 17 00:00:00 2001 From: rakita Date: Thu, 26 Dec 2024 13:35:41 +0100 Subject: [PATCH 15/15] fix docs --- src/lib.rs | 2 +- src/tracing/builder/geth.rs | 4 ++-- src/tracing/builder/parity.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2646036d..17e1eb5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! revm [Inspector](revm::Inspector) implementations, such as call tracers +//! revm [Inspector](revm_inspector::Inspector) implementations, such as call tracers //! //! ## Feature Flags //! diff --git a/src/tracing/builder/geth.rs b/src/tracing/builder/geth.rs index 027a5084..830e82e4 100644 --- a/src/tracing/builder/geth.rs +++ b/src/tracing/builder/geth.rs @@ -97,7 +97,7 @@ impl<'a> GethTraceBuilder<'a> { /// Generate a geth-style trace e.g. for `debug_traceTransaction` /// /// This expects the gas used and return value for the - /// [ExecutionResult](revm::primitives::ExecutionResult) of the executed transaction. + /// [ExecutionResult](revm::context_interface::result::ExecutionResult) of the executed transaction. pub fn geth_traces( &self, receipt_gas_used: u64, @@ -129,7 +129,7 @@ impl<'a> GethTraceBuilder<'a> { /// This decodes all call frames from the recorded traces. /// /// This expects the gas used and return value for the - /// [ExecutionResult](revm::primitives::ExecutionResult) of the executed transaction. + /// [ExecutionResult](revm::context_interface::result::ExecutionResult) of the executed transaction. pub fn geth_call_traces(&self, opts: CallConfig, gas_used: u64) -> CallFrame { if self.nodes.is_empty() { return Default::default(); diff --git a/src/tracing/builder/parity.rs b/src/tracing/builder/parity.rs index db28a3a1..c8d1fca9 100644 --- a/src/tracing/builder/parity.rs +++ b/src/tracing/builder/parity.rs @@ -482,7 +482,7 @@ where /// in the [ExecutionResult] state map and compares the balance and nonce against what's in the /// `db`, which should point to the beginning of the transaction. /// -/// It's expected that `DB` is a revm [Database](revm::db::Database) which at this point already +/// It's expected that `DB` is a revm [Database](revm::database_interface::Database) which at this point already /// contains all the accounts that are in the state map and never has to fetch them from disk. pub fn populate_state_diff<'a, DB, I>( state_diff: &mut StateDiff,