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 revm_inspectors::transfer::TransferInspector;
23use std::sync::Arc;
24
25#[derive(Clone, Debug, Default)]
27pub struct AnvilInspector {
28 pub tracer: Option<TracingInspector>,
30 pub log_collector: Option<LogCollector>,
32 pub transfer: Option<TransferInspector>,
34}
35
36impl AnvilInspector {
37 pub fn print_logs(&self) {
41 if let Some(collector) = &self.log_collector {
42 print_logs(&collector.logs);
43 }
44 }
45
46 pub fn into_print_traces(mut self, decoder: Arc<CallTraceDecoder>) {
48 if let Some(a) = self.tracer.take() {
49 print_traces(a, decoder);
50 }
51 }
52
53 pub fn print_traces(&self, decoder: Arc<CallTraceDecoder>) {
56 if let Some(a) = self.tracer.clone() {
57 print_traces(a, decoder);
58 }
59 }
60
61 pub fn with_tracing(mut self) -> Self {
63 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().set_steps(false)));
64 self
65 }
66
67 pub fn with_tracing_config(mut self, config: TracingInspectorConfig) -> Self {
69 self.tracer = Some(TracingInspector::new(config));
70 self
71 }
72
73 pub fn with_steps_tracing(mut self) -> Self {
75 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
76 self
77 }
78
79 pub fn with_log_collector(mut self) -> Self {
81 self.log_collector = Some(Default::default());
82 self
83 }
84
85 pub fn with_transfers(mut self) -> Self {
87 self.transfer = Some(TransferInspector::new(false).with_logs(true));
88 self
89 }
90
91 pub fn with_trace_printer(mut self) -> Self {
93 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().with_state_diffs()));
94 self
95 }
96}
97
98fn print_traces(tracer: TracingInspector, decoder: Arc<CallTraceDecoder>) {
106 let arena = tokio::task::block_in_place(move || {
107 tokio::runtime::Handle::current().block_on(async move {
108 let mut arena = tracer.into_traces();
109 decoder.populate_traces(arena.nodes_mut()).await;
110 arena
111 })
112 });
113
114 let traces = SparsedTraceArena { arena, ignored: Default::default() };
115 node_info!("Traces:");
116 node_info!("{}", render_trace_arena_inner(&traces, false, true));
117}
118
119impl<CTX> Inspector<CTX, EthInterpreter> for AnvilInspector
120where
121 CTX: ContextTr<Journal: JournalExt>,
122{
123 fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
124 call_inspectors!([&mut self.tracer], |inspector| {
125 inspector.initialize_interp(interp, ecx);
126 });
127 }
128
129 fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
130 call_inspectors!([&mut self.tracer], |inspector| {
131 inspector.step(interp, ecx);
132 });
133 }
134
135 fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
136 call_inspectors!([&mut self.tracer], |inspector| {
137 inspector.step_end(interp, ecx);
138 });
139 }
140
141 #[allow(clippy::redundant_clone)]
142 fn log(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) {
143 call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {
144 inspector.log(interp, ecx, log.clone());
145 });
146 }
147
148 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
149 call_inspectors!(
150 #[ret]
151 [&mut self.tracer, &mut self.log_collector, &mut self.transfer],
152 |inspector| inspector.call(ecx, inputs).map(Some),
153 );
154 None
155 }
156
157 fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
158 if let Some(tracer) = &mut self.tracer {
159 tracer.call_end(ecx, inputs, outcome);
160 }
161 }
162
163 fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
164 call_inspectors!(
165 #[ret]
166 [&mut self.tracer, &mut self.transfer],
167 |inspector| inspector.create(ecx, inputs).map(Some),
168 );
169 None
170 }
171
172 fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {
173 if let Some(tracer) = &mut self.tracer {
174 tracer.create_end(ecx, inputs, outcome);
175 }
176 }
177
178 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
179 call_inspectors!([&mut self.tracer, &mut self.transfer], |inspector| {
180 Inspector::<CTX, EthInterpreter>::selfdestruct(inspector, contract, target, value)
181 });
182 }
183}
184
185pub fn print_logs(logs: &[Log]) {
187 for log in decode_console_logs(logs) {
188 tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, "{}", log);
189 }
190}