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