Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/tracing/builder/geth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
32 changes: 30 additions & 2 deletions src/tracing/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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")]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -241,6 +268,7 @@ macro_rules! delegate {
Self::CallTracer($insp, _) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::PreStateTracer($insp, _) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::FlatCallTracer($insp) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::Erc7562Tracer($insp, _) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::Default($insp, _) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::Noop($insp) => Inspector::<CTX>::$method($insp, $($arg),*),
Self::Mux($insp, _) => Inspector::<CTX>::$method($insp, $($arg),*),
Expand Down
58 changes: 54 additions & 4 deletions tests/it/geth.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
//! 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,
database_interface::EmptyDB,
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() {
Expand Down Expand Up @@ -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::<EmptyDB>::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() {
/*
Expand Down