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 include_memory: bool,
27 memory: Option<String>,
28}
29
30impl std::fmt::Debug for TracerEip3155 {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.debug_struct("TracerEip3155")
33 .field("gas_inspector", &self.gas_inspector)
34 .field("print_summary", &self.print_summary)
35 .field("stack", &self.stack)
36 .field("pc", &self.pc)
37 .field("opcode", &self.opcode)
38 .field("gas", &self.gas)
39 .field("refunded", &self.refunded)
40 .field("mem_size", &self.mem_size)
41 .field("include_memory", &self.include_memory)
42 .field("memory", &self.memory)
43 .finish()
44 }
45}
46
47#[derive(Serialize)]
50#[serde(rename_all = "camelCase")]
51struct Output<'a> {
52 pc: u64,
55 depth: u64,
57 #[serde(default, skip_serializing_if = "Option::is_none")]
59 op_name: Option<&'static str>,
60 op: u8,
62 #[serde(serialize_with = "serde_hex_u64")]
64 gas: u64,
65 #[serde(serialize_with = "serde_hex_u64")]
67 gas_cost: u64,
68 stack: &'a [U256],
70 return_data: &'static str,
72 #[serde(serialize_with = "serde_hex_u64")]
74 refund: u64,
75 #[serde(serialize_with = "serde_hex_u64")]
77 mem_size: u64,
78
79 #[serde(default, skip_serializing_if = "Option::is_none")]
82 error: Option<String>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
85 memory: Option<String>,
86 #[serde(default, skip_serializing_if = "Option::is_none")]
88 storage: Option<HashMap<String, String>>,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
91 return_stack: Option<Vec<String>>,
92}
93
94#[derive(Serialize)]
96#[serde(rename_all = "camelCase")]
97struct Summary {
98 state_root: String,
101 output: String,
103 #[serde(serialize_with = "serde_hex_u64")]
105 gas_used: u64,
106 pass: bool,
108
109 #[serde(default, skip_serializing_if = "Option::is_none")]
112 time: Option<u128>,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
115 fork: Option<String>,
116}
117
118impl TracerEip3155 {
119 pub fn buffered(output: impl Write + 'static) -> Self {
122 Self::new(Box::new(std::io::BufWriter::new(output)))
123 }
124
125 pub fn new_stdout() -> Self {
127 Self::buffered(std::io::stdout())
128 }
129
130 pub fn new(output: Box<dyn Write>) -> Self {
132 Self {
133 output,
134 gas_inspector: GasInspector::new(),
135 print_summary: true,
136 include_memory: false,
137 stack: Default::default(),
138 memory: Default::default(),
139 pc: 0,
140 opcode: 0,
141 gas: 0,
142 refunded: 0,
143 mem_size: 0,
144 }
145 }
146
147 pub fn set_writer(&mut self, writer: Box<dyn Write>) {
149 self.output = writer;
150 }
151
152 pub fn without_summary(mut self) -> Self {
154 self.print_summary = false;
155 self
156 }
157
158 pub fn with_memory(mut self) -> Self {
160 self.include_memory = true;
161 self
162 }
163
164 pub fn clear(&mut self) {
168 let Self {
169 gas_inspector,
170 stack,
171 pc,
172 opcode,
173 gas,
174 refunded,
175 mem_size,
176 ..
177 } = self;
178 *gas_inspector = GasInspector::new();
179 stack.clear();
180 *pc = 0;
181 *opcode = 0;
182 *gas = 0;
183 *refunded = 0;
184 *mem_size = 0;
185 }
186
187 fn print_summary(&mut self, result: &InterpreterResult, context: &mut impl ContextTr) {
188 if !self.print_summary {
189 return;
190 }
191 let spec = context.cfg().spec().into();
192 let gas_limit = context.tx().gas_limit();
193 let value = Summary {
194 state_root: B256::ZERO.to_string(),
195 output: result.output.to_string(),
196 gas_used: gas_limit - self.gas_inspector.gas_remaining(),
197 pass: result.is_ok(),
198 time: None,
199 fork: Some(spec.to_string()),
200 };
201 let _ = self.write_value(&value);
202 }
203
204 fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> {
205 write_value(&mut *self.output, value)
206 }
207}
208
209pub trait CloneStack {
210 fn clone_into(&self, stack: &mut Vec<U256>);
211}
212
213impl CloneStack for Stack {
214 fn clone_into(&self, stack: &mut Vec<U256>) {
215 stack.extend_from_slice(self.data());
216 }
217}
218
219impl<CTX, INTR> Inspector<CTX, INTR> for TracerEip3155
220where
221 CTX: ContextTr,
222 INTR: InterpreterTypes<Stack: StackTr + CloneStack>,
223{
224 fn initialize_interp(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
225 self.gas_inspector.initialize_interp(&interp.gas);
226 }
227
228 fn step(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
229 self.gas_inspector.step(&interp.gas);
230 self.stack.clear();
231 interp.stack.clone_into(&mut self.stack);
232 self.memory = if self.include_memory {
233 Some(hex::encode_prefixed(
234 interp.memory.slice(0..interp.memory.size()).as_ref(),
235 ))
236 } else {
237 None
238 };
239 self.pc = interp.bytecode.pc() as u64;
240 self.opcode = interp.bytecode.opcode();
241 self.mem_size = interp.memory.size();
242 self.gas = interp.gas.remaining();
243 self.refunded = interp.gas.refunded();
244 }
245
246 fn step_end(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
247 self.gas_inspector.step_end(&mut interp.gas);
248 let value = Output {
249 pc: self.pc,
250 op: self.opcode,
251 gas: self.gas,
252 gas_cost: self.gas_inspector.last_gas_cost(),
253 stack: &self.stack,
254 depth: context.journal_mut().depth() as u64,
255 return_data: "0x",
256 refund: self.refunded as u64,
257 mem_size: self.mem_size as u64,
258
259 op_name: OpCode::new(self.opcode).map(|i| i.as_str()),
260 error: interp
261 .bytecode
262 .action()
263 .as_ref()
264 .and_then(|a| a.instruction_result())
265 .map(|ir| format!("{ir:?}")),
266 memory: self.memory.take(),
267 storage: None,
268 return_stack: None,
269 };
270 let _ = write_value(&mut self.output, &value);
271 }
272
273 fn call_end(&mut self, context: &mut CTX, _: &CallInputs, outcome: &mut CallOutcome) {
274 self.gas_inspector.call_end(outcome);
275
276 if context.journal_mut().depth() == 0 {
277 self.print_summary(&outcome.result, context);
278 let _ = self.output.flush();
279 self.clear();
281 }
282 }
283
284 fn create_end(&mut self, context: &mut CTX, _: &CreateInputs, outcome: &mut CreateOutcome) {
285 self.gas_inspector.create_end(outcome);
286
287 if context.journal_mut().depth() == 0 {
288 self.print_summary(&outcome.result, context);
289 let _ = self.output.flush();
290 self.clear();
292 }
293 }
294}
295
296fn write_value(
297 output: &mut dyn std::io::Write,
298 value: &impl serde::Serialize,
299) -> std::io::Result<()> {
300 serde_json::to_writer(&mut *output, value)?;
301 output.write_all(b"\n")
302}
303
304fn serde_hex_u64<S: serde::Serializer>(n: &u64, serializer: S) -> Result<S::Ok, S::Error> {
305 serializer.serialize_str(&format!("{:#x}", *n))
306}