mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +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};
|
use types::{CallTrace, CallTraceStep};
|
||||||
|
|
||||||
mod arena;
|
mod arena;
|
||||||
|
mod config;
|
||||||
mod types;
|
mod types;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
pub use config::TraceInspectorConfig;
|
||||||
|
|
||||||
/// An inspector that collects call traces.
|
/// An inspector that collects call traces.
|
||||||
///
|
///
|
||||||
@ -29,10 +31,10 @@ mod utils;
|
|||||||
/// The [TracingInspector] keeps track of everything by:
|
/// The [TracingInspector] keeps track of everything by:
|
||||||
/// 1. start tracking steps/calls on [Inspector::step] and [Inspector::call]
|
/// 1. start tracking steps/calls on [Inspector::step] and [Inspector::call]
|
||||||
/// 2. complete steps/calls on [Inspector::step_end] and [Inspector::call_end]
|
/// 2. complete steps/calls on [Inspector::step_end] and [Inspector::call_end]
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TracingInspector {
|
pub struct TracingInspector {
|
||||||
/// Whether to include individual steps [Inspector::step]
|
/// Configures what and how the inspector records traces.
|
||||||
record_steps: bool,
|
config: TraceInspectorConfig,
|
||||||
/// Records all call traces
|
/// Records all call traces
|
||||||
traces: CallTraceArena,
|
traces: CallTraceArena,
|
||||||
trace_stack: Vec<usize>,
|
trace_stack: Vec<usize>,
|
||||||
@ -47,18 +49,22 @@ pub struct TracingInspector {
|
|||||||
// === impl TracingInspector ===
|
// === impl 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.
|
/// Consumes the Inspector and returns the recorded.
|
||||||
pub fn finalize(self) -> CallTraceArena {
|
pub fn finalize(self) -> CallTraceArena {
|
||||||
self.traces
|
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]
|
/// Configures a [GasInspector]
|
||||||
///
|
///
|
||||||
/// If this [TracingInspector] is part of a stack [InspectorStack](crate::stack::InspectorStack)
|
/// If this [TracingInspector] is part of a stack [InspectorStack](crate::stack::InspectorStack)
|
||||||
@ -167,14 +173,19 @@ impl TracingInspector {
|
|||||||
|
|
||||||
let pc = interp.program_counter();
|
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 {
|
trace.trace.steps.push(CallTraceStep {
|
||||||
depth: data.journaled_state.depth(),
|
depth: data.journaled_state.depth(),
|
||||||
pc,
|
pc,
|
||||||
op: OpCode::try_from_u8(interp.contract.bytecode.bytecode()[pc])
|
op: OpCode::try_from_u8(interp.contract.bytecode.bytecode()[pc])
|
||||||
.expect("is valid opcode;"),
|
.expect("is valid opcode;"),
|
||||||
contract: interp.contract.address,
|
contract: interp.contract.address,
|
||||||
stack: interp.stack.clone(),
|
stack,
|
||||||
memory: interp.memory.clone(),
|
memory,
|
||||||
gas: self.gas_inspector.as_ref().gas_remaining(),
|
gas: self.gas_inspector.as_ref().gas_remaining(),
|
||||||
gas_refund_counter: interp.gas.refunded() as u64,
|
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];
|
let step = &mut self.traces.arena[trace_idx].trace.steps[step_idx];
|
||||||
|
|
||||||
if let Some(pc) = interp.program_counter().checked_sub(1) {
|
if let Some(pc) = interp.program_counter().checked_sub(1) {
|
||||||
|
if self.config.record_state_diff {
|
||||||
let op = interp.contract.bytecode.bytecode()[pc];
|
let op = interp.contract.bytecode.bytecode()[pc];
|
||||||
|
|
||||||
let journal_entry = data
|
let journal_entry = data
|
||||||
@ -216,11 +228,13 @@ impl TracingInspector {
|
|||||||
Some(JournalEntry::StorageChange { address, key, .. }),
|
Some(JournalEntry::StorageChange { address, key, .. }),
|
||||||
) => {
|
) => {
|
||||||
// SAFETY: (Address,key) exists if part if StorageChange
|
// 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))
|
Some((*key, value))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
step.gas_cost = step.gas - self.gas_inspector.as_ref().gas_remaining();
|
step.gas_cost = step.gas - self.gas_inspector.as_ref().gas_remaining();
|
||||||
}
|
}
|
||||||
@ -249,7 +263,7 @@ where
|
|||||||
data: &mut EVMData<'_, DB>,
|
data: &mut EVMData<'_, DB>,
|
||||||
is_static: bool,
|
is_static: bool,
|
||||||
) -> InstructionResult {
|
) -> InstructionResult {
|
||||||
if self.record_steps {
|
if self.config.record_steps {
|
||||||
self.gas_inspector.step(interp, data, is_static);
|
self.gas_inspector.step(interp, data, is_static);
|
||||||
self.start_step(interp, data);
|
self.start_step(interp, data);
|
||||||
}
|
}
|
||||||
@ -279,7 +293,7 @@ where
|
|||||||
is_static: bool,
|
is_static: bool,
|
||||||
eval: InstructionResult,
|
eval: InstructionResult,
|
||||||
) -> InstructionResult {
|
) -> InstructionResult {
|
||||||
if self.record_steps {
|
if self.config.record_steps {
|
||||||
self.gas_inspector.step_end(interp, data, is_static, eval);
|
self.gas_inspector.step_end(interp, data, is_static, eval);
|
||||||
self.fill_step_on_step_end(interp, data, eval);
|
self.fill_step_on_step_end(interp, data, eval);
|
||||||
return eval
|
return eval
|
||||||
|
|||||||
Reference in New Issue
Block a user