anvil/eth/backend/mem/
inspector.rs
1use crate::eth::macros::node_info;
4use alloy_primitives::{Address, Log, U256};
5use foundry_evm::{
6 call_inspectors,
7 decode::decode_console_logs,
8 inspectors::{LogCollector, TracingInspector},
9 traces::{
10 CallTraceDecoder, SparsedTraceArena, TracingInspectorConfig, render_trace_arena_inner,
11 },
12};
13use revm::{
14 Inspector,
15 context::ContextTr,
16 inspector::JournalExt,
17 interpreter::{
18 CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter,
19 interpreter::EthInterpreter,
20 },
21};
22use std::sync::Arc;
23
24#[derive(Clone, Debug, Default)]
26pub struct AnvilInspector {
27 pub tracer: Option<TracingInspector>,
29 pub log_collector: Option<LogCollector>,
31}
32
33impl AnvilInspector {
34 pub fn print_logs(&self) {
38 if let Some(collector) = &self.log_collector {
39 print_logs(&collector.logs);
40 }
41 }
42
43 pub fn into_print_traces(mut self, decoder: Arc<CallTraceDecoder>) {
45 if let Some(a) = self.tracer.take() {
46 print_traces(a, decoder);
47 }
48 }
49
50 pub fn print_traces(&self, decoder: Arc<CallTraceDecoder>) {
53 if let Some(a) = self.tracer.clone() {
54 print_traces(a, decoder);
55 }
56 }
57
58 pub fn with_tracing(mut self) -> Self {
60 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().set_steps(false)));
61 self
62 }
63
64 pub fn with_tracing_config(mut self, config: TracingInspectorConfig) -> Self {
66 self.tracer = Some(TracingInspector::new(config));
67 self
68 }
69
70 pub fn with_steps_tracing(mut self) -> Self {
72 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
73 self
74 }
75
76 pub fn with_log_collector(mut self) -> Self {
78 self.log_collector = Some(Default::default());
79 self
80 }
81
82 pub fn with_trace_printer(mut self) -> Self {
84 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
85 self
86 }
87}
88
89fn print_traces(tracer: TracingInspector, decoder: Arc<CallTraceDecoder>) {
97 let arena = tokio::task::block_in_place(move || {
98 tokio::runtime::Handle::current().block_on(async move {
99 let mut arena = tracer.into_traces();
100 decoder.populate_traces(arena.nodes_mut()).await;
101 arena
102 })
103 });
104
105 let traces = SparsedTraceArena { arena, ignored: Default::default() };
106 node_info!("Traces:");
107 node_info!("{}", render_trace_arena_inner(&traces, false, true));
108}
109
110impl<CTX> Inspector<CTX, EthInterpreter> for AnvilInspector
111where
112 CTX: ContextTr<Journal: JournalExt>,
113{
114 fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
115 call_inspectors!([&mut self.tracer], |inspector| {
116 inspector.initialize_interp(interp, ecx);
117 });
118 }
119
120 fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
121 call_inspectors!([&mut self.tracer], |inspector| {
122 inspector.step(interp, ecx);
123 });
124 }
125
126 fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
127 call_inspectors!([&mut self.tracer], |inspector| {
128 inspector.step_end(interp, ecx);
129 });
130 }
131
132 #[allow(clippy::redundant_clone)]
133 fn log(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) {
134 call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {
135 inspector.log(interp, ecx, log.clone());
136 });
137 }
138
139 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
140 call_inspectors!(
141 #[ret]
142 [&mut self.tracer, &mut self.log_collector],
143 |inspector| inspector.call(ecx, inputs).map(Some),
144 );
145 None
146 }
147
148 fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
149 if let Some(tracer) = &mut self.tracer {
150 tracer.call_end(ecx, inputs, outcome);
151 }
152 }
153
154 fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
155 if let Some(tracer) = &mut self.tracer
156 && let Some(out) = tracer.create(ecx, inputs)
157 {
158 return Some(out);
159 }
160 None
161 }
162
163 fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {
164 if let Some(tracer) = &mut self.tracer {
165 tracer.create_end(ecx, inputs, outcome);
166 }
167 }
168
169 #[inline]
170 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
171 if let Some(tracer) = &mut self.tracer {
172 <TracingInspector as Inspector<CTX>>::selfdestruct(tracer, contract, target, value);
173 }
174 }
175}
176
177pub fn print_logs(logs: &[Log]) {
179 for log in decode_console_logs(logs) {
180 tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, "{}", log);
181 }
182}