mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add trace inspector config (#1729)
This commit is contained in:
75
crates/revm/revm-inspectors/src/tracing/config.rs
Normal file
75
crates/revm/revm-inspectors/src/tracing/config.rs
Normal file
@ -0,0 +1,75 @@
|
||||
/// Gives guidance to the [TracingInspector](crate::tracing::TracingInspector).
|
||||
///
|
||||
/// Use [TraceInspectorConfig::default_parity] or [TraceInspectorConfig::default_geth] to get the
|
||||
/// default configs for specific styles of traces.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub struct TraceInspectorConfig {
|
||||
/// Whether to record every individual opcode level step.
|
||||
pub record_steps: bool,
|
||||
/// Whether to record individual memory snapshots.
|
||||
pub record_memory_snapshots: bool,
|
||||
/// Whether to record individual stack snapshots.
|
||||
pub record_stack_snapshots: bool,
|
||||
/// Whether to record state diffs.
|
||||
pub record_state_diff: bool,
|
||||
}
|
||||
|
||||
impl TraceInspectorConfig {
|
||||
/// Returns a config with everything enabled.
|
||||
pub const fn all() -> Self {
|
||||
Self {
|
||||
record_steps: true,
|
||||
record_memory_snapshots: true,
|
||||
record_stack_snapshots: true,
|
||||
record_state_diff: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a config for parity style traces.
|
||||
///
|
||||
/// This config does _not_ record opcode level traces and is suited for `trace_transaction`
|
||||
pub const fn default_parity() -> Self {
|
||||
Self {
|
||||
record_steps: false,
|
||||
record_memory_snapshots: false,
|
||||
record_stack_snapshots: false,
|
||||
record_state_diff: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a config for geth style traces.
|
||||
///
|
||||
/// This config does _not_ record opcode level traces and is suited for `debug_traceTransaction`
|
||||
pub const fn default_geth() -> Self {
|
||||
Self {
|
||||
record_steps: true,
|
||||
record_memory_snapshots: true,
|
||||
record_stack_snapshots: true,
|
||||
record_state_diff: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure whether individual opcode level steps should be recorded
|
||||
pub fn set_steps(mut self, record_steps: bool) -> Self {
|
||||
self.record_steps = record_steps;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configure whether the tracer should record memory snapshots
|
||||
pub fn set_memory_snapshots(mut self, record_memory_snapshots: bool) -> Self {
|
||||
self.record_memory_snapshots = record_memory_snapshots;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configure whether the tracer should record stack snapshots
|
||||
pub fn set_stack_snapshots(mut self, record_stack_snapshots: bool) -> Self {
|
||||
self.record_stack_snapshots = record_stack_snapshots;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configure whether the tracer should record state diffs
|
||||
pub fn set_state_diffs(mut self, record_state_diff: bool) -> Self {
|
||||
self.record_state_diff = record_state_diff;
|
||||
self
|
||||
}
|
||||
}
|
||||
@ -18,8 +18,10 @@ use revm::{
|
||||
use types::{CallTrace, CallTraceStep};
|
||||
|
||||
mod arena;
|
||||
mod config;
|
||||
mod types;
|
||||
mod utils;
|
||||
pub use config::TraceInspectorConfig;
|
||||
|
||||
/// An inspector that collects call traces.
|
||||
///
|
||||
@ -29,10 +31,10 @@ mod utils;
|
||||
/// The [TracingInspector] keeps track of everything by:
|
||||
/// 1. start tracking steps/calls on [Inspector::step] and [Inspector::call]
|
||||
/// 2. complete steps/calls on [Inspector::step_end] and [Inspector::call_end]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TracingInspector {
|
||||
/// Whether to include individual steps [Inspector::step]
|
||||
record_steps: bool,
|
||||
/// Configures what and how the inspector records traces.
|
||||
config: TraceInspectorConfig,
|
||||
/// Records all call traces
|
||||
traces: CallTraceArena,
|
||||
trace_stack: Vec<usize>,
|
||||
@ -47,18 +49,22 @@ pub struct TracingInspector {
|
||||
// === impl TracingInspector ===
|
||||
|
||||
impl TracingInspector {
|
||||
/// Returns a new instance for the given config
|
||||
pub fn new(config: TraceInspectorConfig) -> Self {
|
||||
Self {
|
||||
config,
|
||||
traces: Default::default(),
|
||||
trace_stack: vec![],
|
||||
step_stack: vec![],
|
||||
gas_inspector: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the Inspector and returns the recorded.
|
||||
pub fn finalize(self) -> CallTraceArena {
|
||||
self.traces
|
||||
}
|
||||
|
||||
/// Enables step recording and uses the configured [GasInspector] to report gas costs for each
|
||||
/// step.
|
||||
pub fn with_steps_recording(mut self) -> Self {
|
||||
self.record_steps = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures a [GasInspector]
|
||||
///
|
||||
/// If this [TracingInspector] is part of a stack [InspectorStack](crate::stack::InspectorStack)
|
||||
@ -167,14 +173,19 @@ impl TracingInspector {
|
||||
|
||||
let pc = interp.program_counter();
|
||||
|
||||
let memory =
|
||||
self.config.record_memory_snapshots.then(|| interp.memory.clone()).unwrap_or_default();
|
||||
let stack =
|
||||
self.config.record_stack_snapshots.then(|| interp.stack.clone()).unwrap_or_default();
|
||||
|
||||
trace.trace.steps.push(CallTraceStep {
|
||||
depth: data.journaled_state.depth(),
|
||||
pc,
|
||||
op: OpCode::try_from_u8(interp.contract.bytecode.bytecode()[pc])
|
||||
.expect("is valid opcode;"),
|
||||
contract: interp.contract.address,
|
||||
stack: interp.stack.clone(),
|
||||
memory: interp.memory.clone(),
|
||||
stack,
|
||||
memory,
|
||||
gas: self.gas_inspector.as_ref().gas_remaining(),
|
||||
gas_refund_counter: interp.gas.refunded() as u64,
|
||||
|
||||
@ -199,6 +210,7 @@ impl TracingInspector {
|
||||
let step = &mut self.traces.arena[trace_idx].trace.steps[step_idx];
|
||||
|
||||
if let Some(pc) = interp.program_counter().checked_sub(1) {
|
||||
if self.config.record_state_diff {
|
||||
let op = interp.contract.bytecode.bytecode()[pc];
|
||||
|
||||
let journal_entry = data
|
||||
@ -216,11 +228,13 @@ impl TracingInspector {
|
||||
Some(JournalEntry::StorageChange { address, key, .. }),
|
||||
) => {
|
||||
// SAFETY: (Address,key) exists if part if StorageChange
|
||||
let value = data.journaled_state.state[address].storage[key].present_value();
|
||||
let value =
|
||||
data.journaled_state.state[address].storage[key].present_value();
|
||||
Some((*key, value))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
step.gas_cost = step.gas - self.gas_inspector.as_ref().gas_remaining();
|
||||
}
|
||||
@ -249,7 +263,7 @@ where
|
||||
data: &mut EVMData<'_, DB>,
|
||||
is_static: bool,
|
||||
) -> InstructionResult {
|
||||
if self.record_steps {
|
||||
if self.config.record_steps {
|
||||
self.gas_inspector.step(interp, data, is_static);
|
||||
self.start_step(interp, data);
|
||||
}
|
||||
@ -279,7 +293,7 @@ where
|
||||
is_static: bool,
|
||||
eval: InstructionResult,
|
||||
) -> InstructionResult {
|
||||
if self.record_steps {
|
||||
if self.config.record_steps {
|
||||
self.gas_inspector.step_end(interp, data, is_static, eval);
|
||||
self.fill_step_on_step_end(interp, data, eval);
|
||||
return eval
|
||||
|
||||
Reference in New Issue
Block a user