1use crate::{Inspector, InspectorEvmTr, JournalExt};
2use context::{
3 result::{ExecutionResult, ResultGas},
4 Cfg, ContextTr, JournalEntry, JournalTr, Transaction,
5};
6use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult};
7use interpreter::{
8 instructions::{GasTable, InstructionTable},
9 interpreter_types::{Jumps, LoopControl},
10 FrameInput, Host, InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction,
11 InterpreterTypes,
12};
13use state::bytecode::opcode;
14
15pub trait InspectorHandler: Handler
34where
35 Self::Evm:
36 InspectorEvmTr<Inspector: Inspector<<<Self as Handler>::Evm as EvmTr>::Context, Self::IT>>,
37{
38 type IT: InterpreterTypes;
40
41 fn inspect_run(
45 &mut self,
46 evm: &mut Self::Evm,
47 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
48 match self.inspect_run_without_catch_error(evm) {
49 Ok(output) => Ok(output),
50 Err(e) => self.catch_error(evm, e),
51 }
52 }
53
54 fn inspect_run_without_catch_error(
58 &mut self,
59 evm: &mut Self::Evm,
60 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
61 let mut init_and_floor_gas = self.validate(evm)?;
62 let eip7702_regular_refund = self.pre_execution(evm, &mut init_and_floor_gas)? as i64;
65
66 let mut frame_result = self.inspect_execution(evm, &init_and_floor_gas)?;
67 let result_gas = self.post_execution(
68 evm,
69 &mut frame_result,
70 init_and_floor_gas,
71 eip7702_regular_refund,
72 )?;
73 self.execution_result(evm, frame_result, result_gas)
74 }
75
76 fn inspect_execution(
80 &mut self,
81 evm: &mut Self::Evm,
82 init_and_floor_gas: &InitialAndFloorGas,
83 ) -> Result<FrameResult, Self::Error> {
84 let (gas_limit, reservoir) = init_and_floor_gas.initial_gas_and_reservoir(
86 evm.ctx().tx().gas_limit(),
87 evm.ctx().cfg().tx_gas_limit_cap(),
88 evm.ctx().cfg().is_amsterdam_eip8037_enabled(),
89 );
90 let first_frame_input = self.first_frame_input(evm, gas_limit, reservoir)?;
91
92 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
94
95 self.last_frame_result(evm, &mut frame_result)?;
97 Ok(frame_result)
98 }
99
100 fn inspect_run_exec_loop(
111 &mut self,
112 evm: &mut Self::Evm,
113 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
114 ) -> Result<FrameResult, Self::Error> {
115 let res = evm.inspect_frame_init(first_frame_input)?;
116
117 if let ItemOrResult::Result(frame_result) = res {
118 return Ok(frame_result);
119 }
120
121 loop {
122 let call_or_result = evm.inspect_frame_run()?;
123
124 let result = match call_or_result {
125 ItemOrResult::Item(init) => {
126 match evm.inspect_frame_init(init)? {
127 ItemOrResult::Item(_) => {
128 continue;
129 }
130 ItemOrResult::Result(result) => result,
132 }
133 }
134 ItemOrResult::Result(result) => result,
135 };
136
137 if let Some(result) = evm.frame_return_result(result)? {
138 return Ok(result);
139 }
140 }
141 }
142
143 fn inspect_run_system_call(
149 &mut self,
150 evm: &mut Self::Evm,
151 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
152 let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
154 match self
156 .inspect_execution(evm, &init_and_floor_gas)
157 .and_then(|exec_result| {
158 let gas = exec_result.gas();
160 let result_gas = ResultGas::default()
161 .with_total_gas_spent(gas.total_gas_spent())
162 .with_refunded(gas.refunded() as u64)
163 .with_state_gas_spent(gas.state_gas_spent());
164 self.execution_result(evm, exec_result, result_gas)
165 }) {
166 out @ Ok(_) => out,
167 Err(e) => self.catch_error(evm, e),
168 }
169 }
170}
171
172pub fn frame_start<CTX, INTR: InterpreterTypes>(
174 context: &mut CTX,
175 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
176 frame_input: &mut FrameInput,
177) -> Option<FrameResult> {
178 if let Some(result) = inspector.frame_start(context, frame_input) {
180 return Some(result);
181 }
182 match frame_input {
184 FrameInput::Call(i) => {
185 if let Some(output) = inspector.call(context, i) {
186 return Some(FrameResult::Call(output));
187 }
188 }
189 FrameInput::Create(i) => {
190 if let Some(output) = inspector.create(context, i) {
191 return Some(FrameResult::Create(output));
192 }
193 }
194 FrameInput::Empty => unreachable!(),
195 }
196 None
197}
198
199pub fn frame_end<CTX, INTR: InterpreterTypes>(
201 context: &mut CTX,
202 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
203 frame_input: &FrameInput,
204 frame_output: &mut FrameResult,
205) {
206 match frame_output {
208 FrameResult::Call(outcome) => {
209 let FrameInput::Call(i) = frame_input else {
210 panic!("FrameInput::Call expected {frame_input:?}");
211 };
212 inspector.call_end(context, i, outcome);
213 }
214 FrameResult::Create(outcome) => {
215 let FrameInput::Create(i) = frame_input else {
216 panic!("FrameInput::Create expected {frame_input:?}");
217 };
218 inspector.create_end(context, i, outcome);
219 }
220 }
221 inspector.frame_end(context, frame_input, frame_output);
223}
224
225pub fn inspect_instructions<CTX, IT>(
231 context: &mut CTX,
232 interpreter: &mut Interpreter<IT>,
233 mut inspector: impl Inspector<CTX, IT>,
234 instructions: &InstructionTable<IT, CTX>,
235 gas_table: &GasTable,
236) -> InterpreterAction
237where
238 CTX: ContextTr<Journal: JournalExt> + Host,
239 IT: InterpreterTypes,
240{
241 loop {
242 inspector.step(interpreter, context);
243 if interpreter.bytecode.is_end() {
244 break;
245 }
246
247 let opcode = interpreter.bytecode.opcode();
248 interpreter.step(instructions, gas_table, context);
249
250 if (opcode::LOG0..=opcode::LOG4).contains(&opcode) {
251 inspect_log(interpreter, context, &mut inspector);
252 }
253
254 inspector.step_end(interpreter, context);
255
256 if interpreter.bytecode.is_end() {
257 break;
258 }
259 }
260
261 let next_action = interpreter.take_next_action();
262
263 if let InterpreterAction::Return(result) = &next_action {
265 if result.result == InstructionResult::SelfDestruct {
266 inspect_selfdestruct(context, &mut inspector);
267 }
268 }
269
270 next_action
271}
272
273#[inline(never)]
274#[cold]
275fn inspect_log<CTX, IT>(
276 interpreter: &mut Interpreter<IT>,
277 context: &mut CTX,
278 inspector: &mut impl Inspector<CTX, IT>,
279) where
280 CTX: ContextTr<Journal: JournalExt> + Host,
281 IT: InterpreterTypes,
282{
283 if interpreter
285 .bytecode
286 .action()
287 .as_ref()
288 .is_some_and(|x| x.is_return())
289 {
290 return;
291 }
292
293 let log = context.journal_mut().logs().last().unwrap().clone();
294 inspector.log_full(interpreter, context, log);
295}
296
297#[inline(never)]
298#[cold]
299fn inspect_selfdestruct<CTX, IT>(context: &mut CTX, inspector: &mut impl Inspector<CTX, IT>)
300where
301 CTX: ContextTr<Journal: JournalExt> + Host,
302 IT: InterpreterTypes,
303{
304 if let Some(
305 JournalEntry::AccountDestroyed {
306 address: contract,
307 target: to,
308 had_balance: balance,
309 ..
310 }
311 | JournalEntry::BalanceTransfer {
312 from: contract,
313 to,
314 balance,
315 ..
316 },
317 ) = context.journal_mut().journal().last()
318 {
319 inspector.selfdestruct(*contract, *to, *balance);
320 }
321}