anvil/eth/backend/mem/
inspector.rs
1use crate::eth::macros::node_info;
4use alloy_evm::eth::EthEvmContext;
5use alloy_primitives::{Address, Log, U256};
6use foundry_evm::{
7 backend::DatabaseError,
8 call_inspectors,
9 decode::decode_console_logs,
10 inspectors::{LogCollector, TracingInspector},
11 traces::{
12 render_trace_arena_inner, CallTraceDecoder, SparsedTraceArena, TracingInspectorConfig,
13 },
14};
15use revm::{
16 context::ContextTr,
17 inspector::JournalExt,
18 interpreter::{
19 interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome,
20 Interpreter,
21 },
22 Database, Inspector,
23};
24
25#[derive(Clone, Debug, Default)]
27pub struct AnvilInspector {
28 pub tracer: Option<TracingInspector>,
30 pub log_collector: Option<LogCollector>,
32}
33
34impl AnvilInspector {
35 pub fn print_logs(&self) {
39 if let Some(collector) = &self.log_collector {
40 print_logs(&collector.logs);
41 }
42 }
43
44 pub fn into_print_traces(mut self) {
46 if let Some(a) = self.tracer.take() {
47 print_traces(a)
48 }
49 }
50
51 pub fn print_traces(&self) {
54 if let Some(a) = self.tracer.clone() {
55 print_traces(a)
56 }
57 }
58
59 pub fn with_tracing(mut self) -> Self {
61 self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all().set_steps(false)));
62 self
63 }
64
65 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) {
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 let decoder = CallTraceDecoder::new();
101 decoder.populate_traces(arena.nodes_mut()).await;
102 arena
103 })
104 });
105
106 let traces = SparsedTraceArena { arena, ignored: Default::default() };
107 node_info!("Traces:");
108 node_info!("{}", render_trace_arena_inner(&traces, false, true));
109}
110
111impl<CTX, D> Inspector<CTX, EthInterpreter> for AnvilInspector
112where
113 D: Database<Error = DatabaseError>,
114 CTX: ContextTr<Db = D>,
115 CTX::Journal: JournalExt,
116{
117 fn initialize_interp(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
118 call_inspectors!([&mut self.tracer], |inspector| {
119 inspector.initialize_interp(interp, ecx);
120 });
121 }
122
123 fn step(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
124 call_inspectors!([&mut self.tracer], |inspector| {
125 inspector.step(interp, ecx);
126 });
127 }
128
129 fn step_end(&mut self, interp: &mut Interpreter, ecx: &mut CTX) {
130 call_inspectors!([&mut self.tracer], |inspector| {
131 inspector.step_end(interp, ecx);
132 });
133 }
134
135 fn log(&mut self, interp: &mut Interpreter, ecx: &mut CTX, log: Log) {
136 call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {
137 inspector.log(interp, ecx, log.clone());
139 });
140 }
141
142 fn call(&mut self, ecx: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
143 call_inspectors!(
144 #[ret]
145 [&mut self.tracer, &mut self.log_collector],
146 |inspector| inspector.call(ecx, inputs).map(Some),
147 );
148 None
149 }
150
151 fn call_end(&mut self, ecx: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
152 if let Some(tracer) = &mut self.tracer {
153 tracer.call_end(ecx, inputs, outcome);
154 }
155 }
156
157 fn create(&mut self, ecx: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
158 if let Some(tracer) = &mut self.tracer {
159 if let Some(out) = tracer.create(ecx, inputs) {
160 return Some(out);
161 }
162 }
163 None
164 }
165
166 fn create_end(&mut self, ecx: &mut CTX, inputs: &CreateInputs, outcome: &mut CreateOutcome) {
167 if let Some(tracer) = &mut self.tracer {
168 tracer.create_end(ecx, inputs, outcome);
169 }
170 }
171
172 #[inline]
173 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
174 if let Some(tracer) = &mut self.tracer {
175 Inspector::<EthEvmContext<D>>::selfdestruct(tracer, contract, target, value);
176 }
177 }
178}
179
180pub fn print_logs(logs: &[Log]) {
182 for log in decode_console_logs(logs) {
183 tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, "{}", log);
184 }
185}