revm_inspector/
eip3155.rs

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
14/// [EIP-3155](https://eips.ethereum.org/EIPS/eip-3155) tracer [Inspector].
15pub struct TracerEip3155 {
16    output: Box<dyn Write>,
17    gas_inspector: GasInspector,
18    /// Print summary of the execution.
19    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// # Output
50// The CUT MUST output a `json` object for EACH operation.
51#[derive(Serialize)]
52#[serde(rename_all = "camelCase")]
53struct Output<'a> {
54    // Required fields:
55    /// Program counter
56    pc: u64,
57    /// OpCode
58    op: u8,
59    /// Gas left before executing this operation
60    #[serde(serialize_with = "serde_hex_u64")]
61    gas: u64,
62    /// Gas cost of this operation
63    #[serde(serialize_with = "serde_hex_u64")]
64    gas_cost: u64,
65    /// Array of all values on the stack
66    stack: &'a [U256],
67    /// Depth of the call stack
68    depth: u64,
69    /// Data returned by the function call
70    return_data: &'static str,
71    /// Amount of **global** gas refunded
72    #[serde(serialize_with = "serde_hex_u64")]
73    refund: u64,
74    /// Size of memory array
75    #[serde(serialize_with = "serde_hex_u64")]
76    mem_size: u64,
77
78    // Optional fields:
79    /// Name of the operation
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    op_name: Option<&'static str>,
82    /// Description of an error (should contain revert reason if supported)
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    error: Option<String>,
85    /// Array of all allocated values
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    memory: Option<String>,
88    /// Array of all stored values
89    #[serde(default, skip_serializing_if = "Option::is_none")]
90    storage: Option<HashMap<String, String>>,
91    /// Array of values, Stack of the called function
92    #[serde(default, skip_serializing_if = "Option::is_none")]
93    return_stack: Option<Vec<String>>,
94}
95
96// # Summary and error handling
97#[derive(Serialize)]
98#[serde(rename_all = "camelCase")]
99struct Summary {
100    // Required fields:
101    /// Root of the state trie after executing the transaction
102    state_root: String,
103    /// Return values of the function
104    output: String,
105    /// All gas used by the transaction
106    #[serde(serialize_with = "serde_hex_u64")]
107    gas_used: u64,
108    /// Bool whether transaction was executed successfully
109    pass: bool,
110
111    // Optional fields:
112    /// Time in nanoseconds needed to execute the transaction
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    time: Option<u128>,
115    /// Name of the fork rules used for execution
116    #[serde(default, skip_serializing_if = "Option::is_none")]
117    fork: Option<String>,
118}
119
120impl TracerEip3155 {
121    /// Creates a new EIP-3155 tracer with the given output writer, by first wrapping it in a
122    /// [`BufWriter`](std::io::BufWriter).
123    pub fn buffered(output: impl Write + 'static) -> Self {
124        Self::new(Box::new(std::io::BufWriter::new(output)))
125    }
126
127    /// Creates a new EIP-3155 tracer with a stdout output.
128    pub fn new_stdout() -> Self {
129        Self::buffered(std::io::stdout())
130    }
131
132    /// Creates a new EIP-3155 tracer with the given output writer.
133    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    /// Sets the writer to use for the output.
151    pub fn set_writer(&mut self, writer: Box<dyn Write>) {
152        self.output = writer;
153    }
154
155    /// Don't include a summary at the end of the trace
156    pub fn without_summary(mut self) -> Self {
157        self.print_summary = false;
158        self
159    }
160
161    /// Include a memory field for each step. This significantly increases processing time and output size.
162    pub fn with_memory(mut self) -> Self {
163        self.include_memory = true;
164        self
165    }
166
167    /// Resets the tracer to its initial state of [`Self::new`].
168    ///
169    /// This makes the inspector ready to be used again.
170    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            // Clear the state if we are at the top level.
290            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            // Clear the state if we are at the top level.
301            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}