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 primitives::hints_util::cold_path;
14use state::bytecode::opcode;
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 mut init_and_floor_gas = self.validate(evm)?;
63 let eip7702_regular_refund = self.pre_execution(evm, &mut init_and_floor_gas)? as i64;
66
67 let mut frame_result = self.inspect_execution(evm, &init_and_floor_gas)?;
68 let result_gas = self.post_execution(
69 evm,
70 &mut frame_result,
71 init_and_floor_gas,
72 eip7702_regular_refund,
73 )?;
74 self.execution_result(evm, frame_result, result_gas)
75 }
76
77 fn inspect_execution(
81 &mut self,
82 evm: &mut Self::Evm,
83 init_and_floor_gas: &InitialAndFloorGas,
84 ) -> Result<FrameResult, Self::Error> {
85 let (gas_limit, reservoir) = init_and_floor_gas.initial_gas_and_reservoir(
87 evm.ctx().tx().gas_limit(),
88 evm.ctx().cfg().tx_gas_limit_cap(),
89 evm.ctx().cfg().is_amsterdam_eip8037_enabled(),
90 );
91 let first_frame_input = self.first_frame_input(evm, gas_limit, reservoir)?;
92
93 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
95
96 self.last_frame_result(evm, &mut frame_result)?;
98 Ok(frame_result)
99 }
100
101 fn inspect_run_exec_loop(
112 &mut self,
113 evm: &mut Self::Evm,
114 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
115 ) -> Result<FrameResult, Self::Error> {
116 let res = evm.inspect_frame_init(first_frame_input)?;
117
118 if let ItemOrResult::Result(frame_result) = res {
119 return Ok(frame_result);
120 }
121
122 loop {
123 let call_or_result = evm.inspect_frame_run()?;
124
125 let result = match call_or_result {
126 ItemOrResult::Item(init) => {
127 match evm.inspect_frame_init(init)? {
128 ItemOrResult::Item(_) => {
129 continue;
130 }
131 ItemOrResult::Result(result) => result,
133 }
134 }
135 ItemOrResult::Result(result) => result,
136 };
137
138 if let Some(result) = evm.frame_return_result(result)? {
139 return Ok(result);
140 }
141 }
142 }
143
144 fn inspect_run_system_call(
150 &mut self,
151 evm: &mut Self::Evm,
152 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
153 let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
155 match self
157 .inspect_execution(evm, &init_and_floor_gas)
158 .and_then(|exec_result| {
159 let gas = exec_result.gas();
161 let result_gas = ResultGas::default()
162 .with_total_gas_spent(gas.total_gas_spent())
163 .with_refunded(gas.refunded() as u64)
164 .with_state_gas_spent(gas.state_gas_spent());
165 self.execution_result(evm, exec_result, result_gas)
166 }) {
167 out @ Ok(_) => out,
168 Err(e) => self.catch_error(evm, e),
169 }
170 }
171}
172
173pub fn frame_start<CTX, INTR: InterpreterTypes>(
175 context: &mut CTX,
176 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
177 frame_input: &mut FrameInput,
178) -> Option<FrameResult> {
179 if let Some(result) = inspector.frame_start(context, frame_input) {
181 return Some(result);
182 }
183 match frame_input {
185 FrameInput::Call(i) => {
186 if let Some(output) = inspector.call(context, i) {
187 return Some(FrameResult::Call(output));
188 }
189 }
190 FrameInput::Create(i) => {
191 if let Some(output) = inspector.create(context, i) {
192 return Some(FrameResult::Create(output));
193 }
194 }
195 FrameInput::Empty => unreachable!(),
196 }
197 None
198}
199
200pub fn frame_end<CTX, INTR: InterpreterTypes>(
202 context: &mut CTX,
203 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
204 frame_input: &FrameInput,
205 frame_output: &mut FrameResult,
206) {
207 match frame_output {
209 FrameResult::Call(outcome) => {
210 let FrameInput::Call(i) = frame_input else {
211 panic!("FrameInput::Call expected {frame_input:?}");
212 };
213 inspector.call_end(context, i, outcome);
214 }
215 FrameResult::Create(outcome) => {
216 let FrameInput::Create(i) = frame_input else {
217 panic!("FrameInput::Create expected {frame_input:?}");
218 };
219 inspector.create_end(context, i, outcome);
220 }
221 }
222 inspector.frame_end(context, frame_input, frame_output);
224}
225
226pub fn inspect_instructions<CTX, IT>(
232 context: &mut CTX,
233 interpreter: &mut Interpreter<IT>,
234 mut inspector: impl Inspector<CTX, IT>,
235 instructions: &InstructionTable<IT, CTX>,
236 gas_table: &GasTable,
237) -> InterpreterAction
238where
239 CTX: ContextTr<Journal: JournalExt> + Host,
240 IT: InterpreterTypes,
241{
242 loop {
243 inspector.step(interpreter, context);
244 if interpreter.bytecode.is_end() {
245 cold_path();
246 break;
247 }
248
249 let opcode = interpreter.bytecode.opcode();
250 if let Err(e) = interpreter.step(instructions, gas_table, context) {
251 cold_path();
252 if interpreter.bytecode.action().is_none() {
253 interpreter.halt(e);
254 }
255 }
256
257 if (opcode::LOG0..=opcode::LOG4).contains(&opcode) {
258 inspect_log(interpreter, context, &mut inspector);
259 }
260
261 inspector.step_end(interpreter, context);
262
263 if interpreter.bytecode.is_end() {
264 cold_path();
265 break;
266 }
267 }
268
269 let next_action = interpreter.take_next_action();
270
271 if let InterpreterAction::Return(result) = &next_action {
273 if result.result == InstructionResult::SelfDestruct {
274 inspect_selfdestruct(context, &mut inspector);
275 }
276 }
277
278 next_action
279}
280
281#[inline(never)]
282#[cold]
283fn inspect_log<CTX, IT>(
284 interpreter: &mut Interpreter<IT>,
285 context: &mut CTX,
286 inspector: &mut impl Inspector<CTX, IT>,
287) where
288 CTX: ContextTr<Journal: JournalExt> + Host,
289 IT: InterpreterTypes,
290{
291 if interpreter
293 .bytecode
294 .action()
295 .as_ref()
296 .is_some_and(|x| x.is_return())
297 {
298 return;
299 }
300
301 let log = context.journal_mut().logs().last().unwrap().clone();
302 inspector.log_full(interpreter, context, log);
303}
304
305#[inline(never)]
306#[cold]
307fn inspect_selfdestruct<CTX, IT>(context: &mut CTX, inspector: &mut impl Inspector<CTX, IT>)
308where
309 CTX: ContextTr<Journal: JournalExt> + Host,
310 IT: InterpreterTypes,
311{
312 if let Some(
313 JournalEntry::AccountDestroyed {
314 address: contract,
315 target: to,
316 had_balance: balance,
317 ..
318 }
319 | JournalEntry::BalanceTransfer {
320 from: contract,
321 to,
322 balance,
323 ..
324 },
325 ) = context.journal_mut().journal().last()
326 {
327 inspector.selfdestruct(*contract, *to, *balance);
328 }
329}