1use crate::inspectors::GasInspector;
2use crate::Inspector;
3use context::{Cfg, ContextTr, JournalTr, Transaction};
4use interpreter::{
5 interpreter_types::{Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr, SubRoutineStack},
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 section: Option<u64>,
23 function_depth: Option<u64>,
24 opcode: u8,
25 gas: u64,
26 refunded: i64,
27 mem_size: usize,
28 skip: bool,
29 include_memory: bool,
30 memory: Option<String>,
31}
32
33#[derive(Serialize)]
36#[serde(rename_all = "camelCase")]
37struct Output<'a> {
38 pc: u64,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
43 section: Option<u64>,
44 op: u8,
46 #[serde(serialize_with = "serde_hex_u64")]
48 gas: u64,
49 #[serde(serialize_with = "serde_hex_u64")]
51 gas_cost: u64,
52 stack: &'a [U256],
54 depth: u64,
56 #[serde(default, skip_serializing_if = "Option::is_none")]
58 function_depth: Option<u64>,
59 return_data: &'static str,
61 #[serde(serialize_with = "serde_hex_u64")]
63 refund: u64,
64 #[serde(serialize_with = "serde_hex_u64")]
66 mem_size: u64,
67
68 #[serde(default, skip_serializing_if = "Option::is_none")]
71 op_name: Option<&'static str>,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 error: Option<String>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
77 memory: Option<String>,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
80 storage: Option<HashMap<String, String>>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 return_stack: Option<Vec<String>>,
84}
85
86#[derive(Serialize)]
88#[serde(rename_all = "camelCase")]
89struct Summary {
90 state_root: String,
93 output: String,
95 #[serde(serialize_with = "serde_hex_u64")]
97 gas_used: u64,
98 pass: bool,
100
101 #[serde(default, skip_serializing_if = "Option::is_none")]
104 time: Option<u128>,
105 #[serde(default, skip_serializing_if = "Option::is_none")]
107 fork: Option<String>,
108}
109
110impl TracerEip3155 {
111 pub fn buffered(output: impl Write + 'static) -> Self {
114 Self::new(Box::new(std::io::BufWriter::new(output)))
115 }
116
117 pub fn new_stdout() -> Self {
119 Self::buffered(std::io::stdout())
120 }
121
122 pub fn new(output: Box<dyn Write>) -> Self {
124 Self {
125 output,
126 gas_inspector: GasInspector::new(),
127 print_summary: true,
128 include_memory: false,
129 stack: Default::default(),
130 memory: Default::default(),
131 pc: 0,
132 section: None,
133 function_depth: None,
134 opcode: 0,
135 gas: 0,
136 refunded: 0,
137 mem_size: 0,
138 skip: false,
139 }
140 }
141
142 pub fn set_writer(&mut self, writer: Box<dyn Write>) {
144 self.output = writer;
145 }
146
147 pub fn without_summary(mut self) -> Self {
149 self.print_summary = false;
150 self
151 }
152
153 pub fn with_memory(mut self) -> Self {
155 self.include_memory = true;
156 self
157 }
158
159 pub fn clear(&mut self) {
163 let Self {
164 gas_inspector,
165 stack,
166 pc,
167 opcode,
168 gas,
169 refunded,
170 mem_size,
171 skip,
172 ..
173 } = self;
174 *gas_inspector = GasInspector::new();
175 stack.clear();
176 *pc = 0;
177 *opcode = 0;
178 *gas = 0;
179 *refunded = 0;
180 *mem_size = 0;
181 *skip = false;
182 }
183
184 fn print_summary(&mut self, result: &InterpreterResult, context: &mut impl ContextTr) {
185 if !self.print_summary {
186 return;
187 }
188 let spec = context.cfg().spec().into();
189 let gas_limit = context.tx().gas_limit();
190 let value = Summary {
191 state_root: B256::ZERO.to_string(),
192 output: result.output.to_string(),
193 gas_used: gas_limit - self.gas_inspector.gas_remaining(),
194 pass: result.is_ok(),
195 time: None,
196 fork: Some(spec.to_string()),
197 };
198 let _ = self.write_value(&value);
199 }
200
201 fn write_value(&mut self, value: &impl serde::Serialize) -> std::io::Result<()> {
202 write_value(&mut *self.output, value)
203 }
204}
205
206pub trait CloneStack {
207 fn clone_into(&self, stack: &mut Vec<U256>);
208}
209
210impl CloneStack for Stack {
211 fn clone_into(&self, stack: &mut Vec<U256>) {
212 stack.extend_from_slice(self.data());
213 }
214}
215
216impl<CTX, INTR> Inspector<CTX, INTR> for TracerEip3155
217where
218 CTX: ContextTr,
219 INTR: InterpreterTypes<Stack: StackTr + CloneStack>,
220{
221 fn initialize_interp(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
222 self.gas_inspector.initialize_interp(interp.control.gas());
223 }
224
225 fn step(&mut self, interp: &mut Interpreter<INTR>, _: &mut CTX) {
226 self.gas_inspector.step(interp.control.gas());
227 self.stack.clear();
228 interp.stack.clone_into(&mut self.stack);
229 self.memory = if self.include_memory {
230 Some(hex::encode_prefixed(
231 interp.memory.slice(0..interp.memory.size()).as_ref(),
232 ))
233 } else {
234 None
235 };
236 self.pc = interp.bytecode.pc() as u64;
237 self.section = if interp.runtime_flag.is_eof() {
238 Some(interp.sub_routine.routine_idx() as u64)
239 } else {
240 None
241 };
242 self.function_depth = if interp.runtime_flag.is_eof() {
243 Some(interp.sub_routine.len() as u64 + 1)
244 } else {
245 None
246 };
247 self.opcode = interp.bytecode.opcode();
248 self.mem_size = interp.memory.size();
249 self.gas = interp.control.gas().remaining();
250 self.refunded = interp.control.gas().refunded();
251 }
252
253 fn step_end(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
254 self.gas_inspector.step_end(interp.control.gas_mut());
255 if self.skip {
256 self.skip = false;
257 return;
258 }
259
260 let value = Output {
261 pc: self.pc,
262 section: self.section,
263 op: self.opcode,
264 gas: self.gas,
265 gas_cost: self.gas_inspector.last_gas_cost(),
266 stack: &self.stack,
267 depth: context.journal().depth() as u64,
268 function_depth: self.function_depth,
269 return_data: "0x",
270 refund: self.refunded as u64,
271 mem_size: self.mem_size as u64,
272
273 op_name: OpCode::new(self.opcode).map(|i| i.as_str()),
274 error: (!interp.control.instruction_result().is_ok())
275 .then(|| format!("{:?}", interp.control.instruction_result())),
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().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().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}