diff --git a/src/tracing/builder/geth.rs b/src/tracing/builder/geth.rs index 883193c9..540492ea 100644 --- a/src/tracing/builder/geth.rs +++ b/src/tracing/builder/geth.rs @@ -472,7 +472,7 @@ impl<'a> GethTraceBuilder<'a> { if matches!(op, opcode::EXTCODESIZE | opcode::EXTCODECOPY | opcode::EXTCODEHASH) { if let Some(stack) = &step.stack { if let Some(item) = stack.get(stack.len().saturating_sub(1)) { - let address = Address::from(item.to_be_bytes()); + let address = Address::from_word((*item).into()); ext_code_access_info.push(format!("{address:?}")); if let Entry::Vacant(e) = contract_size.entry(address) { if let Ok(Some(account)) = db.basic_ref(address) { diff --git a/src/tracing/debug.rs b/src/tracing/debug.rs index 57e77850..a9907a94 100644 --- a/src/tracing/debug.rs +++ b/src/tracing/debug.rs @@ -5,8 +5,9 @@ use crate::tracing::{ use alloc::{boxed::Box, string::String}; use alloy_rpc_types_eth::TransactionInfo; use alloy_rpc_types_trace::geth::{ - mux::MuxConfig, CallConfig, FourByteFrame, GethDebugBuiltInTracerType, GethDebugTracerType, - GethDebugTracingOptions, GethDefaultTracingOptions, GethTrace, NoopFrame, PreStateConfig, + erc7562::Erc7562Config, mux::MuxConfig, CallConfig, FourByteFrame, GethDebugBuiltInTracerType, + GethDebugTracerType, GethDebugTracingOptions, GethDefaultTracingOptions, GethTrace, NoopFrame, + PreStateConfig, }; use revm::{ context_interface::{ @@ -42,6 +43,8 @@ pub enum DebugInspector { Mux(MuxInspector, MuxConfig), /// FlatCallTracer FlatCallTracer(TracingInspector), + /// Erc7562Tracer + Erc7562Tracer(TracingInspector, Erc7562Config), /// Default tracer Default(TracingInspector, GethDefaultTracingOptions), #[cfg(feature = "js-tracer")] @@ -104,6 +107,22 @@ impl DebugInspector { TracingInspectorConfig::from_flat_call_config(&flat_call_config), )) } + GethDebugBuiltInTracerType::Erc7562Tracer => { + let config = if tracer_config.is_null() { + Erc7562Config::default() + } else { + tracer_config + .from_value() + .map_err(|_| DebugInspectorError::InvalidTracerConfig)? + }; + + Self::Erc7562Tracer( + TracingInspector::new( + TracingInspectorConfig::from_geth_erc7562_config(&config), + ), + config, + ) + } _ => { // Note: this match is non-exhaustive in case we need to add support for // additional tracers @@ -149,6 +168,7 @@ impl DebugInspector { Self::CallTracer(inspector, _) | Self::PreStateTracer(inspector, _) | Self::FlatCallTracer(inspector) + | Self::Erc7562Tracer(inspector, _) | Self::Default(inspector, _) => inspector.fuse(), Self::Noop(_) => {} Self::Mux(inspector, config) => { @@ -208,6 +228,13 @@ impl DebugInspector { .into_localized_transaction_traces(tx_info) .into() } + Self::Erc7562Tracer(inspector, config) => { + inspector.set_transaction_gas_limit(tx_env.gas_limit()); + inspector + .geth_builder() + .geth_erc7562_traces(config.clone(), res.result.gas_used(), db) + .into() + } Self::Default(inspector, config) => { inspector.set_transaction_gas_limit(tx_env.gas_limit()); inspector @@ -241,6 +268,7 @@ macro_rules! delegate { Self::CallTracer($insp, _) => Inspector::::$method($insp, $($arg),*), Self::PreStateTracer($insp, _) => Inspector::::$method($insp, $($arg),*), Self::FlatCallTracer($insp) => Inspector::::$method($insp, $($arg),*), + Self::Erc7562Tracer($insp, _) => Inspector::::$method($insp, $($arg),*), Self::Default($insp, _) => Inspector::::$method($insp, $($arg),*), Self::Noop($insp) => Inspector::::$method($insp, $($arg),*), Self::Mux($insp, _) => Inspector::::$method($insp, $($arg),*), diff --git a/tests/it/geth.rs b/tests/it/geth.rs index 04c81ad4..276c7322 100644 --- a/tests/it/geth.rs +++ b/tests/it/geth.rs @@ -1,12 +1,13 @@ //! Geth tests use crate::utils::deploy_contract; -use alloy_primitives::{hex, map::HashMap, Address, Bytes, TxKind}; +use alloy_primitives::{address, hex, map::HashMap, Address, Bytes, TxKind, B256}; use alloy_rpc_types_eth::TransactionInfo; use alloy_rpc_types_trace::geth::{ - mux::MuxConfig, CallConfig, FlatCallConfig, GethDebugBuiltInTracerType, GethDebugTracerConfig, - GethTrace, PreStateConfig, PreStateFrame, + erc7562::Erc7562Config, mux::MuxConfig, CallConfig, FlatCallConfig, GethDebugBuiltInTracerType, + GethDebugTracerConfig, GethDebugTracingOptions, GethTrace, PreStateConfig, PreStateFrame, }; use revm::{ + bytecode::{opcode, Bytecode}, context::TxEnv, context_interface::{ContextTr, TransactTo}, database::CacheDB, @@ -14,9 +15,12 @@ use revm::{ handler::EvmTr, inspector::InspectorEvmTr, primitives::hardfork::SpecId, + state::AccountInfo, Context, InspectEvm, MainBuilder, MainContext, }; -use revm_inspectors::tracing::{MuxInspector, TracingInspector, TracingInspectorConfig}; +use revm_inspectors::tracing::{ + DebugInspector, MuxInspector, TracingInspector, TracingInspectorConfig, +}; #[test] fn test_geth_calltracer_logs() { @@ -104,6 +108,52 @@ fn test_geth_calltracer_logs() { assert!(call_frame.calls[2].error.is_none()); } +#[test] +fn test_geth_erc7562_tracer() { + let code = hex!("6001600052602060002060005500"); + let account = address!("1000000000000000000000000000000000000001"); + let caller = address!("1000000000000000000000000000000000000002"); + + let context = + Context::mainnet().with_db(CacheDB::::default()).modify_db_chained(|db| { + db.insert_account_info( + account, + AccountInfo { code: Some(Bytecode::new_raw(code.into())), ..Default::default() }, + ); + }); + + let opts = GethDebugTracingOptions::erc7562_tracer(Erc7562Config::default()); + let mut inspector = DebugInspector::new(opts).unwrap(); + let mut evm = context.build_mainnet().with_inspector(&mut inspector); + + let res = evm + .inspect_tx(TxEnv { + caller, + gas_limit: 1000000, + kind: TransactTo::Call(account), + data: Bytes::default(), + nonce: 0, + ..Default::default() + }) + .unwrap(); + assert!(res.result.is_success(), "{res:#?}"); + + let (ctx, inspector) = evm.ctx_inspector(); + let tx_env = ctx.tx().clone(); + let block_env = ctx.block().clone(); + let trace = inspector.get_result(None, &tx_env, &block_env, &res, ctx.db_mut()).unwrap(); + + match trace { + GethTrace::Erc7562Tracer(frame) => { + assert!(frame.used_opcodes.contains_key(&opcode::KECCAK256)); + assert!(frame.used_opcodes.contains_key(&opcode::SSTORE)); + assert!(frame.accessed_slots.writes.contains_key(&B256::ZERO)); + assert!(!frame.keccak.is_empty()); + } + _ => panic!("Expected Erc7562Tracer"), + } +} + #[test] fn test_geth_mux_tracer() { /*