anvil/eth/backend/mem/
inspector.rs1use 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};
22
23#[derive(Clone, Debug, Default)]
25pub struct AnvilInspector {
26 pub tracer: Option<TracingInspector>,
28 pub log_collector: Option<LogCollector>,
30}
31
32impl AnvilInspector {
33 pub fn print_logs(&self) {
37 if let Some(collector) = &self.log_collector {
38 print_logs(&collector.logs);
39 }
40 }
41
42 pub fn into_print_traces(mut self) {
44 if let Some(a) = self.tracer.take() {
45 print_traces(a)
46 }
47 }
48
49 pub fn print_traces(&self) {
52 if let Some(a) = self.tracer.clone() {
53 print_traces(a)
54 }
55 }
56
57 pub fn with_tracing(mut self) -> Self {
59 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().set_steps(false)));
60 self
61 }
62
63 pub fn with_tracing_config(mut self, config: TracingInspectorConfig) -> Self {
64 self.tracer = Some(TracingInspector::new(config));
65 self
66 }
67
68 pub fn with_steps_tracing(mut self) -> Self {
70 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
71 self
72 }
73
74 pub fn with_log_collector(mut self) -> Self {
76 self.log_collector = Some(Default::default());
77 self
78 }
79
80 pub fn with_trace_printer(mut self) -> Self {
82 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
83 self
84 }
85}
86
87fn print_traces(tracer: TracingInspector) {
95 let arena = tokio::task::block_in_place(move || {
96 tokio::runtime::Handle::current().block_on(async move {
97 let mut arena = tracer.into_traces();
98 let decoder = CallTraceDecoder::new();
99 decoder.populate_traces(arena.nodes_mut()).await;
100 arena
101 })
102 });
103
104 let traces = SparsedTraceArena { arena, ignored: Default::default() };
105 node_info!("Traces:");
106 node_info!("{}", render_trace_arena_inner(&traces, false, true));
107}
108
109impl<CTX> Inspector<CTX, EthInterpreter> for AnvilInspector
110where
111 CTX: ContextTr<Journal: JournalExt>,
112{
113 fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
114 call_inspectors!([&mut self.tracer], |inspector| {
115 inspector.initialize_interp(interp, ecx);
116 });
117 }
118
119 fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
120 call_inspectors!([&mut self.tracer], |inspector| {
121 inspector.step(interp, ecx);
122 });
123 }
124
125 fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
126 call_inspectors!([&mut self.tracer], |inspector| {
127 inspector.step_end(interp, ecx);
128 });
129 }
130
131 fn log(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) {
132 call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {
133 inspector.log(interp, ecx, log.clone());
135 });
136 }
137
138 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
139 call_inspectors!(
140 #[ret]
141 [&mut self.tracer, &mut self.log_collector],
142 |inspector| inspector.call(ecx, inputs).map(Some),
143 );
144 None
145 }
146
147 fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
148 if let Some(tracer) = &mut self.tracer {
149 tracer.call_end(ecx, inputs, outcome);
150 }
151 }
152
153 fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
154 if let Some(tracer) = &mut self.tracer
155 && let Some(out) = tracer.create(ecx, inputs)
156 {
157 return Some(out);
158 }
159 None
160 }
161
162 fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {
163 if let Some(tracer) = &mut self.tracer {
164 tracer.create_end(ecx, inputs, outcome);
165 }
166 }
167
168 #[inline]
169 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
170 if let Some(tracer) = &mut self.tracer {
171 <TracingInspector as Inspector<CTX>>::selfdestruct(tracer, contract, target, value);
172 }
173 }
174}
175
176pub fn print_logs(logs: &[Log]) {
178 for log in decode_console_logs(logs) {
179 tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, "{}", log);
180 }
181}