1use crate::inspectors::GasInspector;
2use crate::Inspector;
3use context::{Cfg, ContextTr, JournalTr, Transaction};
4use interpreter::{
5 interpreter_types::{Jumps, LoopControl, MemoryTr, StackTr},
6 CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter, InterpreterResult,
7 InterpreterTypes, Stack,
8};
9use primitives::{hex, HashMap, B256, U256};
10use serde::Serialize;
11use state::bytecode::opcode::OpCode;
12use std::io::Write;
13
14pub struct TracerEip3155 {
16 output: Box<dyn Write>,
17 gas_inspector: GasInspector,
18 print_summary: bool,
20 stack: Vec<U256>,
21 pc: u64,
22 opcode: u8,
23 gas: u64,
24 refunded: i64,
25 mem_size: usize,
26 skip: bool,
27 include_memory: bool,
28 memory: Option<String>,
29}
30
31impl std::fmt::Debug for TracerEip3155 {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.debug_struct("TracerEip3155")
34 .field("gas_inspector", &self.gas_inspector)
35 .field("print_summary", &self.print_summary)
36 .field("stack", &self.stack)
37 .field("pc", &self.pc)
38 .field("opcode", &self.opcode)
39 .field("gas", &self.gas)
40 .field("refunded", &self.refunded)
41 .field("mem_size", &self.mem_size)
42 .field("skip", &self.skip)
43 .field("include_memory", &self.include_memory)
44 .field("memory", &self.memory)
45 .finish()
46 }
47}
48
49#[derive(Serialize)]
52#[serde(rename_all = "camelCase")]
53struct Output<'a> {
54 pc: u64,
57 op: u8,
59 #[serde(serialize_with = "serde_hex_u64")]
61 gas: u64,
62 #[serde(serialize_with = "serde_hex_u64")]
64 gas_cost: u64,
65 stack: &'a [U256],
67 depth: u64,
69 return_data: &'static str,
71 #[serde(serialize_with = "serde_hex_u64")]
73 refund: u64,
74 #[serde(serialize_with = "serde_hex_u64")]
76 mem_size: u64,
77
78 #[serde(default, skip_serializing_if = "Option::is_none")]
81 op_name: Option<&'static str>,
82 #[serde(default, skip_serializing_if = "Option::is_none")]
84 error: Option<String>,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
87 memory: Option<String>,
88 #[serde(default, skip_serializing_if = "Option::is_none")]
90 storage: Option<HashMap<String, String>>,
91 #[serde(default, skip_serializing_if = "Option::is_none")]
93 return_stack: Option<Vec<String>>,
94}
95
96#[derive(Serialize)]
98#[serde(rename_all = "camelCase")]
99struct Summary {
100 state_root: String,
103 output: String,
105 #[serde(serialize_with = "serde_hex_u64")]
107 gas_used: u64,
108 pass: bool,
110
111 #[serde(default, skip_serializing_if = "Option::is_none")]
114 time: Option<u128>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
117 fork: Option<String>,
118}
119
120impl TracerEip3155 {
121 pub fn buffered(output: impl Write + 'static) -> Self {
124 Self::new(Box::new(std::io::BufWriter::new(output)))
125 }
126
127 pub fn new_stdout() -> Self {
129 Self::buffered(std::io::stdout())
130 }
131
132 pub fn new(output: Box<dyn Write>) -> Self {
134 Self {
135 output,
136 gas_inspector: GasInspector::new(),
137 print_summary: true,
138 include_memory: false,
139 stack: Default::default(),
140 memory: Default::default(),
141 pc: 0,
142 opcode: 0,
143 gas: 0,
144 refunded: 0,
145 mem_size: 0,
146 skip: false,
147 }
148 }
149
150 pub fn set_writer(&mut self, writer: Box<dyn Write>) {
152 self.output = writer;
153 }
154
155 pub fn without_summary(mut self) -> Self {
157 self.print_summary = false;
158 self
159 }
160
161 pub fn with_memory(mut self) -> Self {
163 self.include_memory = true;
164 self
165 }
166
167 pub fn clear(&mut self) {
171 let Self {
172 gas_inspector,
173 stack,
174 pc,
175 opcode,
176 gas,
177 refunded,
178 mem_size,
179 skip,
180 ..
181 } = self;
182 *gas_inspector = GasInspector::new();
183 stack.clear();
184 *pc = 0;
185 *opcode = 0;
186 *gas = 0;
187 *refunded = 0;
188 *mem_size = 0;
189 *skip = false;
190 }
191
192 fn print_summary(&mut self, result: &InterpreterResult, context: &mut impl ContextTr) {
193 if !self.print_summary {
194 return;
195 }
196 let spec = context.cfg().spec().into();
197 let gas_limit = context.tx().gas_limit();
198 let value = Summary {
199 state_root: B256::ZERO.to_string(),
200 output: result.output.to_string(),
201 gas_used: gas_limit - self.gas_inspector.gas_remaining(),
202 pass: result.is_ok(),
203 time: None,
204 fork: Some(spec.to_string()),
205 };
206 let _ = self.write_value(&value);
207 }
208
209 fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> {
210 write_value(&mut *self.output, value)
211 }
212}
213
214pub trait CloneStack {
215 fn clone_into(&self, stack: &mut Vec<U256>);
216}
217
218impl CloneStack for Stack {
219 fn clone_into(&self, stack: &mut Vec<U256>) {
220 stack.extend_from_slice(self.data());
221 }
222}
223
224impl<CTX, INTR> Inspector<CTX, INTR> for TracerEip3155
225where
226 CTX: ContextTr,
227 INTR: InterpreterTypes<Stack: StackTr + CloneStack>,
228{
229 fn initialize_interp(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
230 self.gas_inspector.initialize_interp(&interp.gas);
231 }
232
233 fn step(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
234 self.gas_inspector.step(&interp.gas);
235 self.stack.clear();
236 interp.stack.clone_into(&mut self.stack);
237 self.memory = if self.include_memory {
238 Some(hex::encode_prefixed(
239 interp.memory.slice(0..interp.memory.size()).as_ref(),
240 ))
241 } else {
242 None
243 };
244 self.pc = interp.bytecode.pc() as u64;
245 self.opcode = interp.bytecode.opcode();
246 self.mem_size = interp.memory.size();
247 self.gas = interp.gas.remaining();
248 self.refunded = interp.gas.refunded();
249 }
250
251 fn step_end(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
252 self.gas_inspector.step_end(&mut interp.gas);
253 if self.skip {
254 self.skip = false;
255 return;
256 }
257
258 let value = Output {
259 pc: self.pc,
260 op: self.opcode,
261 gas: self.gas,
262 gas_cost: self.gas_inspector.last_gas_cost(),
263 stack: &self.stack,
264 depth: context.journal_mut().depth() as u64,
265 return_data: "0x",
266 refund: self.refunded as u64,
267 mem_size: self.mem_size as u64,
268
269 op_name: OpCode::new(self.opcode).map(|i| i.as_str()),
270 error: interp
271 .bytecode
272 .action()
273 .as_ref()
274 .and_then(|a| a.instruction_result())
275 .map(|ir| format!("{ir:?}")),
276 memory: self.memory.take(),
277 storage: None,
278 return_stack: None,
279 };
280 let _ = write_value(&mut self.output, &value);
281 }
282
283 fn call_end(&mut self, context: &mut CTX, _: &CallInputs, outcome: &mut CallOutcome) {
284 self.gas_inspector.call_end(outcome);
285
286 if context.journal_mut().depth() == 0 {
287 self.print_summary(&outcome.result, context);
288 let _ = self.output.flush();
289 self.clear();
291 }
292 }
293
294 fn create_end(&mut self, context: &mut CTX, _: &CreateInputs, outcome: &mut CreateOutcome) {
295 self.gas_inspector.create_end(outcome);
296
297 if context.journal_mut().depth() == 0 {
298 self.print_summary(&outcome.result, context);
299 let _ = self.output.flush();
300 self.clear();
302 }
303 }
304}
305
306fn write_value(
307 output: &mut dyn std::io::Write,
308 value: &impl serde::Serialize,
309) -> std::io::Result<()> {
310 serde_json::to_writer(&mut *output, value)?;
311 output.write_all(b"\n")
312}
313
314fn serde_hex_u64<S: serde::Serializer>(n: &u64, serializer: S) -> Result<S::Ok, S::Error> {
315 serializer.serialize_str(&format!("{:#x}", *n))
316}