1use foundry_common::sh_println;
5use foundry_evm_core::backend::DatabaseError;
6use revm::{
7 bytecode::opcode::OpCode,
8 context::{ContextTr, JournalTr},
9 inspector::{inspectors::GasInspector, JournalExt},
10 interpreter::{
11 interpreter::EthInterpreter,
12 interpreter_types::{Jumps, LoopControl, MemoryTr},
13 CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter,
14 },
15 primitives::{Address, U256},
16 Database, Inspector,
17};
18
19#[derive(Clone, Debug, Default)]
23pub struct CustomPrintTracer {
24 gas_inspector: GasInspector,
25}
26
27impl<CTX, D> Inspector<CTX, EthInterpreter> for CustomPrintTracer
28where
29 D: Database<Error = DatabaseError>,
30 CTX: ContextTr<Db = D>,
31 CTX::Journal: JournalExt,
32{
33 fn initialize_interp(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
34 self.gas_inspector.initialize_interp(&interp.control.gas);
35 }
36
37 fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) {
40 let opcode = interp.bytecode.opcode();
41 let name = OpCode::name_by_op(opcode);
42
43 let gas_remaining = self.gas_inspector.gas_remaining();
44
45 let memory_size = interp.memory.size();
46
47 let _ = sh_println!(
48 "depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data size:{}",
49 context.journal().depth(),
50 interp.bytecode.pc(),
51 gas_remaining,
52 gas_remaining,
53 name,
54 opcode,
55 interp.control.gas.refunded(),
56 interp.control.gas.refunded(),
57 interp.stack.data(),
58 memory_size,
59 );
60
61 self.gas_inspector.step(&interp.control.gas);
62 }
63
64 fn step_end(&mut self, interp: &mut Interpreter, _context: &mut CTX) {
65 self.gas_inspector.step_end(interp.control.gas_mut());
66 }
67
68 fn call_end(&mut self, _context: &mut CTX, _inputs: &CallInputs, outcome: &mut CallOutcome) {
69 self.gas_inspector.call_end(outcome)
70 }
71
72 fn create_end(
73 &mut self,
74 _context: &mut CTX,
75 _inputs: &CreateInputs,
76 outcome: &mut CreateOutcome,
77 ) {
78 self.gas_inspector.create_end(outcome)
79 }
80
81 fn call(&mut self, _context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
82 let _ = sh_println!(
83 "SM Address: {:?}, caller:{:?},target:{:?} is_static:{:?}, transfer:{:?}, input_size:{:?}",
84 inputs.bytecode_address,
85 inputs.caller,
86 inputs.target_address,
87 inputs.is_static,
88 inputs.value,
89 inputs.input.len(),
90 );
91 None
92 }
93
94 fn create(&mut self, _context: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
95 let _ = sh_println!(
96 "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}",
97 inputs.caller,
98 inputs.scheme,
99 inputs.value,
100 inputs.init_code,
101 inputs.gas_limit
102 );
103 None
104 }
105
106 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
107 let _ = sh_println!(
108 "SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}",
109 contract,
110 target,
111 value
112 );
113 }
114}