1use revm_interpreter::CallOutcome;
5use revm_interpreter::CreateOutcome;
6use revm_interpreter::OpCode;
7
8use crate::{
9 inspectors::GasInspector,
10 interpreter::{CallInputs, CreateInputs, Interpreter},
11 primitives::{Address, U256},
12 Database, EvmContext, Inspector,
13};
14
15#[derive(Clone, Debug, Default)]
19pub struct CustomPrintTracer {
20 gas_inspector: GasInspector,
21}
22
23impl<DB: Database> Inspector<DB> for CustomPrintTracer {
24 fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
25 self.gas_inspector.initialize_interp(interp, context);
26 }
27
28 fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
31 let opcode = interp.current_opcode();
32 let name = OpCode::name_by_op(opcode);
33
34 let gas_remaining = self.gas_inspector.gas_remaining();
35
36 let memory_size = interp.shared_memory.len();
37
38 println!(
39 "depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data size:{}",
40 context.journaled_state.depth(),
41 interp.program_counter(),
42 gas_remaining,
43 gas_remaining,
44 name,
45 opcode,
46 interp.gas.refunded(),
47 interp.gas.refunded(),
48 interp.stack.data(),
49 memory_size,
50 );
51
52 self.gas_inspector.step(interp, context);
53 }
54
55 fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
56 self.gas_inspector.step_end(interp, context);
57 }
58
59 fn call_end(
60 &mut self,
61 context: &mut EvmContext<DB>,
62 inputs: &CallInputs,
63 outcome: CallOutcome,
64 ) -> CallOutcome {
65 self.gas_inspector.call_end(context, inputs, outcome)
66 }
67
68 fn create_end(
69 &mut self,
70 context: &mut EvmContext<DB>,
71 inputs: &CreateInputs,
72 outcome: CreateOutcome,
73 ) -> CreateOutcome {
74 self.gas_inspector.create_end(context, inputs, outcome)
75 }
76
77 fn call(
78 &mut self,
79 _context: &mut EvmContext<DB>,
80 inputs: &mut CallInputs,
81 ) -> Option<CallOutcome> {
82 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(
95 &mut self,
96 _context: &mut EvmContext<DB>,
97 inputs: &mut CreateInputs,
98 ) -> Option<CreateOutcome> {
99 println!(
100 "CREATE CALL: caller:{:?}, scheme:{:?}, value:{:?}, init_code:{:?}, gas:{:?}",
101 inputs.caller, inputs.scheme, inputs.value, inputs.init_code, inputs.gas_limit
102 );
103 None
104 }
105
106 fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
107 println!(
108 "SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}",
109 contract, target, value
110 );
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use crate::{
117 inspector_handle_register,
118 inspectors::CustomPrintTracer,
119 primitives::{address, bytes, SpecId},
120 Evm, InMemoryDB,
121 };
122
123 #[test]
124 fn gas_calculation_underflow() {
125 let callee = address!("5fdcca53617f4d2b9134b29090c87d01058e27e9");
126
127 let mut evm = Evm::builder()
130 .with_db(InMemoryDB::default())
131 .modify_db(|db| {
132 let code = bytes!("5b597fb075978b6c412c64d169d56d839a8fe01b3f4607ed603b2c78917ce8be1430fe6101e8527ffe64706ecad72a2f5c97a95e006e279dc57081902029ce96af7edae5de116fec610208527f9fc1ef09d4dd80683858ae3ea18869fe789ddc365d8d9d800e26c9872bac5e5b6102285260276102485360d461024953601661024a53600e61024b53607d61024c53600961024d53600b61024e5360b761024f5360596102505360796102515360a061025253607261025353603a6102545360fb61025553601261025653602861025753600761025853606f61025953601761025a53606161025b53606061025c5360a661025d53602b61025e53608961025f53607a61026053606461026153608c6102625360806102635360d56102645360826102655360ae61026653607f6101e8610146610220677a814b184591c555735fdcca53617f4d2b9134b29090c87d01058e27e962047654f259595947443b1b816b65cdb6277f4b59c10a36f4e7b8658f5a5e6f5561");
133 let info = crate::primitives::AccountInfo {
134 balance: "0x100c5d668240db8e00".parse().unwrap(),
135 code_hash: crate::primitives::keccak256(&code),
136 code: Some(crate::primitives::Bytecode::new_raw(code.clone())),
137 nonce: 1,
138 };
139 db.insert_account_info(callee, info);
140 })
141 .modify_tx_env(|tx| {
142 tx.caller = address!("5fdcca53617f4d2b9134b29090c87d01058e27e0");
143 tx.transact_to = crate::primitives::TxKind::Call(callee);
144 tx.data = crate::primitives::Bytes::new();
145 tx.value = crate::primitives::U256::ZERO;
146 })
147 .with_external_context(CustomPrintTracer::default())
148 .with_spec_id(SpecId::BERLIN)
149 .append_handler_register(inspector_handle_register)
150 .build();
151
152 evm.transact().expect("Transaction to work");
153 }
154}