1use crate::{Inspector, InspectorEvmTr, JournalExt};
2use context::journaled_state::JournalCheckpoint;
3use context::{result::ExecutionResult, ContextTr, JournalEntry, JournalTr};
4use handler::{
5 evm::FrameTr, execution::runtime_oog_unwind, post_execution::build_result_gas, EvmTr,
6 FrameResult, Handler, ItemOrResult,
7};
8use interpreter::{
9 instructions::{GasTable, InstructionTable},
10 interpreter_types::LoopControl,
11 FrameInput, GasTracker, Host, InitialAndFloorGas, InstructionResult, Interpreter,
12 InterpreterAction, InterpreterTypes,
13};
14use primitives::hints_util::cold_path;
15
16pub trait InspectorHandler: Handler
35where
36 Self::Evm:
37 InspectorEvmTr<Inspector: Inspector<<<Self as Handler>::Evm as EvmTr>::Context, Self::IT>>,
38{
39 type IT: InterpreterTypes;
41
42 fn inspect_run(
46 &mut self,
47 evm: &mut Self::Evm,
48 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
49 match self.inspect_run_without_catch_error(evm) {
50 Ok(output) => Ok(output),
51 Err(e) => self.catch_error(evm, e),
52 }
53 }
54
55 fn inspect_run_without_catch_error(
59 &mut self,
60 evm: &mut Self::Evm,
61 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
62 let init_and_floor_gas = self.validate(evm)?;
63 let mut gas = self.tx_gas(evm, &init_and_floor_gas);
66 let pre_execution = self.pre_execution(evm, &mut gas)?;
71
72 let mut refund = 0;
73 let mut exec_result = None;
74 if let Some(pre_execution) = pre_execution {
75 refund = pre_execution.eip7702_refund as i64;
76 exec_result = self.inspect_execution(evm, pre_execution.checkpoint, &mut gas)?;
77 }
78 let mut frame_result = match exec_result {
79 Some(exec_result) => exec_result,
80 None => self.runtime_oog_result(evm, &init_and_floor_gas, &mut gas)?,
81 };
82 let result_gas = self.post_execution(evm, &mut frame_result, init_and_floor_gas, refund)?;
83 self.execution_result(evm, frame_result, result_gas)
84 }
85
86 fn inspect_execution(
90 &mut self,
91 evm: &mut Self::Evm,
92 checkpoint: JournalCheckpoint,
93 gas: &mut GasTracker,
94 ) -> Result<Option<FrameResult>, Self::Error> {
95 let Some(first_frame_input) = self.first_frame_input(evm, gas)? else {
98 runtime_oog_unwind(evm.ctx(), checkpoint)?;
99 return Ok(None);
100 };
101 evm.ctx().journal_mut().checkpoint_commit();
103
104 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
106
107 self.last_frame_result(evm, &mut frame_result, gas)?;
109 Ok(Some(frame_result))
110 }
111
112 fn inspect_run_exec_loop(
123 &mut self,
124 evm: &mut Self::Evm,
125 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
126 ) -> Result<FrameResult, Self::Error> {
127 let res = evm.inspect_frame_init(first_frame_input)?;
128
129 if let ItemOrResult::Result(frame_result) = res {
130 return Ok(frame_result);
131 }
132
133 loop {
134 let call_or_result = evm.inspect_frame_run()?;
135
136 let result = match call_or_result {
137 ItemOrResult::Item(init) => {
138 match evm.inspect_frame_init(init)? {
139 ItemOrResult::Item(_) => {
140 continue;
141 }
142 ItemOrResult::Result(result) => result,
144 }
145 }
146 ItemOrResult::Result(result) => result,
147 };
148
149 if let Some(result) = evm.frame_return_result(result)? {
150 return Ok(result);
151 }
152 }
153 }
154
155 fn inspect_run_system_call(
161 &mut self,
162 evm: &mut Self::Evm,
163 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
164 let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
166 let mut gas = self.tx_gas(evm, &init_and_floor_gas);
167 let checkpoint = evm.ctx().journal_mut().checkpoint();
170 match self
172 .inspect_execution(evm, checkpoint, &mut gas)
173 .and_then(|exec_result| {
174 let exec_result = match exec_result {
175 Some(exec_result) => exec_result,
176 None => self.runtime_oog_result(evm, &init_and_floor_gas, &mut gas)?,
180 };
181 let gas = exec_result.gas();
183 let result_gas = build_result_gas(false, gas, init_and_floor_gas);
184 self.execution_result(evm, exec_result, result_gas)
185 }) {
186 out @ Ok(_) => out,
187 Err(e) => self.catch_error(evm, e),
188 }
189 }
190}
191
192pub fn frame_start<CTX, INTR: InterpreterTypes>(
194 context: &mut CTX,
195 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
196 frame_input: &mut FrameInput,
197) -> Option<FrameResult> {
198 if let Some(result) = inspector.frame_start(context, frame_input) {
200 return Some(result);
201 }
202 match frame_input {
204 FrameInput::Call(i) => {
205 if let Some(output) = inspector.call(context, i) {
206 return Some(FrameResult::Call(output));
207 }
208 }
209 FrameInput::Create(i) => {
210 if let Some(output) = inspector.create(context, i) {
211 return Some(FrameResult::Create(output));
212 }
213 }
214 FrameInput::Empty => unreachable!(),
215 }
216 None
217}
218
219pub fn frame_end<CTX, INTR: InterpreterTypes>(
221 context: &mut CTX,
222 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
223 frame_input: &FrameInput,
224 frame_output: &mut FrameResult,
225) {
226 match frame_output {
228 FrameResult::Call(outcome) => {
229 let FrameInput::Call(i) = frame_input else {
230 panic!("FrameInput::Call expected {frame_input:?}");
231 };
232 inspector.call_end(context, i, outcome);
233 }
234 FrameResult::Create(outcome) => {
235 let FrameInput::Create(i) = frame_input else {
236 panic!("FrameInput::Create expected {frame_input:?}");
237 };
238 inspector.create_end(context, i, outcome);
239 }
240 }
241 inspector.frame_end(context, frame_input, frame_output);
243}
244
245pub fn inspect_instructions<CTX, IT>(
251 context: &mut CTX,
252 interpreter: &mut Interpreter<IT>,
253 mut inspector: impl Inspector<CTX, IT>,
254 instructions: &InstructionTable<IT, CTX>,
255 gas_table: &GasTable,
256) -> InterpreterAction
257where
258 CTX: ContextTr<Journal: JournalExt> + Host,
259 IT: InterpreterTypes,
260{
261 let mut instruction_journal_i = None;
262 loop {
263 inspector.step(interpreter, context);
264 if interpreter.bytecode.is_end() {
265 cold_path();
266 break;
267 }
268
269 instruction_journal_i = Some(context.journal().journal().len());
270 let logs_i = context.journal().logs().len();
271 if let Err(e) = interpreter.step(instructions, gas_table, context) {
272 cold_path();
273 if interpreter.bytecode.action().is_none() {
274 interpreter.halt(e);
275 }
276 }
277
278 if context.journal().logs().len() != logs_i {
279 cold_path();
280 inspect_logs(Some(interpreter), context, &mut inspector, logs_i);
281 }
282
283 inspector.step_end(interpreter, context);
284
285 if interpreter.bytecode.is_end() {
286 cold_path();
287 break;
288 }
289 }
290
291 let next_action = interpreter.take_next_action();
292
293 if let InterpreterAction::Return(result) = &next_action {
295 if result.result == InstructionResult::SelfDestruct {
296 if let Some(journal_i) = instruction_journal_i {
297 inspect_selfdestruct(context, &mut inspector, journal_i);
298 }
299 }
300 }
301
302 next_action
303}
304
305#[inline(never)]
315#[cold]
316pub(crate) fn inspect_logs<CTX, IT>(
317 interpreter: Option<&mut Interpreter<IT>>,
318 context: &mut CTX,
319 inspector: &mut impl Inspector<CTX, IT>,
320 logs_i: usize,
321) where
322 CTX: ContextTr<Journal: JournalExt>,
323 IT: InterpreterTypes,
324{
325 let logs = context.journal_mut().logs()[logs_i..].to_vec();
326 match interpreter {
327 Some(interpreter) => {
328 for log in logs {
329 inspector.log_full(interpreter, context, log);
330 }
331 }
332 None => {
333 for log in logs {
334 inspector.log(context, log);
335 }
336 }
337 }
338}
339
340#[inline(never)]
341#[cold]
342fn inspect_selfdestruct<CTX, IT>(
343 context: &mut CTX,
344 inspector: &mut impl Inspector<CTX, IT>,
345 journal_i: usize,
346) where
347 CTX: ContextTr<Journal: JournalExt> + Host,
348 IT: InterpreterTypes,
349{
350 let entry = context
351 .journal_mut()
352 .journal()
353 .get(journal_i..)
354 .and_then(|entries| entries.last());
355
356 if let Some(
357 JournalEntry::AccountDestroyed {
358 address: contract,
359 target: to,
360 had_balance: balance,
361 ..
362 }
363 | JournalEntry::BalanceTransfer {
364 from: contract,
365 to,
366 balance,
367 ..
368 },
369 ) = entry
370 {
371 inspector.selfdestruct(*contract, *to, *balance);
372 }
373}