1use crate::{Inspector, InspectorEvmTr, JournalExt};
2use context::{result::ExecutionResult, Cfg, ContextTr, JournalEntry, JournalTr, Transaction};
3use handler::{
4 evm::FrameTr, post_execution::build_result_gas, EvmTr, FrameResult, Handler, ItemOrResult,
5};
6use interpreter::{
7 instructions::{GasTable, InstructionTable},
8 interpreter_types::{Jumps, LoopControl},
9 FrameInput, Host, InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction,
10 InterpreterTypes,
11};
12use primitives::hints_util::cold_path;
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 );
89 let first_frame_input = self.first_frame_input(evm, gas_limit, reservoir)?;
90
91 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
93
94 self.last_frame_result(evm, reservoir, &mut frame_result)?;
96 Ok(frame_result)
97 }
98
99 fn inspect_run_exec_loop(
110 &mut self,
111 evm: &mut Self::Evm,
112 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
113 ) -> Result<FrameResult, Self::Error> {
114 let res = evm.inspect_frame_init(first_frame_input)?;
115
116 if let ItemOrResult::Result(frame_result) = res {
117 return Ok(frame_result);
118 }
119
120 loop {
121 let call_or_result = evm.inspect_frame_run()?;
122
123 let result = match call_or_result {
124 ItemOrResult::Item(init) => {
125 match evm.inspect_frame_init(init)? {
126 ItemOrResult::Item(_) => {
127 continue;
128 }
129 ItemOrResult::Result(result) => result,
131 }
132 }
133 ItemOrResult::Result(result) => result,
134 };
135
136 if let Some(result) = evm.frame_return_result(result)? {
137 return Ok(result);
138 }
139 }
140 }
141
142 fn inspect_run_system_call(
148 &mut self,
149 evm: &mut Self::Evm,
150 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
151 let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
153 match self
155 .inspect_execution(evm, &init_and_floor_gas)
156 .and_then(|exec_result| {
157 let gas = exec_result.gas();
159 let result_gas = build_result_gas(false, gas, init_and_floor_gas);
160 self.execution_result(evm, exec_result, result_gas)
161 }) {
162 out @ Ok(_) => out,
163 Err(e) => self.catch_error(evm, e),
164 }
165 }
166}
167
168pub fn frame_start<CTX, INTR: InterpreterTypes>(
170 context: &mut CTX,
171 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
172 frame_input: &mut FrameInput,
173) -> Option<FrameResult> {
174 if let Some(result) = inspector.frame_start(context, frame_input) {
176 return Some(result);
177 }
178 match frame_input {
180 FrameInput::Call(i) => {
181 if let Some(output) = inspector.call(context, i) {
182 return Some(FrameResult::Call(output));
183 }
184 }
185 FrameInput::Create(i) => {
186 if let Some(output) = inspector.create(context, i) {
187 return Some(FrameResult::Create(output));
188 }
189 }
190 FrameInput::Empty => unreachable!(),
191 }
192 None
193}
194
195pub fn frame_end<CTX, INTR: InterpreterTypes>(
197 context: &mut CTX,
198 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
199 frame_input: &FrameInput,
200 frame_output: &mut FrameResult,
201) {
202 match frame_output {
204 FrameResult::Call(outcome) => {
205 let FrameInput::Call(i) = frame_input else {
206 panic!("FrameInput::Call expected {frame_input:?}");
207 };
208 inspector.call_end(context, i, outcome);
209 }
210 FrameResult::Create(outcome) => {
211 let FrameInput::Create(i) = frame_input else {
212 panic!("FrameInput::Create expected {frame_input:?}");
213 };
214 inspector.create_end(context, i, outcome);
215 }
216 }
217 inspector.frame_end(context, frame_input, frame_output);
219}
220
221pub fn inspect_instructions<CTX, IT>(
227 context: &mut CTX,
228 interpreter: &mut Interpreter<IT>,
229 mut inspector: impl Inspector<CTX, IT>,
230 instructions: &InstructionTable<IT, CTX>,
231 gas_table: &GasTable,
232) -> InterpreterAction
233where
234 CTX: ContextTr<Journal: JournalExt> + Host,
235 IT: InterpreterTypes,
236{
237 loop {
238 inspector.step(interpreter, context);
239 if interpreter.bytecode.is_end() {
240 cold_path();
241 break;
242 }
243
244 let opcode = interpreter.bytecode.opcode();
245 if let Err(e) = interpreter.step(instructions, gas_table, context) {
246 cold_path();
247 if interpreter.bytecode.action().is_none() {
248 interpreter.halt(e);
249 }
250 }
251
252 if (opcode::LOG0..=opcode::LOG4).contains(&opcode) {
253 inspect_log(interpreter, context, &mut inspector);
254 }
255
256 inspector.step_end(interpreter, context);
257
258 if interpreter.bytecode.is_end() {
259 cold_path();
260 break;
261 }
262 }
263
264 let next_action = interpreter.take_next_action();
265
266 if let InterpreterAction::Return(result) = &next_action {
268 if result.result == InstructionResult::SelfDestruct {
269 inspect_selfdestruct(context, &mut inspector);
270 }
271 }
272
273 next_action
274}
275
276#[inline(never)]
277#[cold]
278fn inspect_log<CTX, IT>(
279 interpreter: &mut Interpreter<IT>,
280 context: &mut CTX,
281 inspector: &mut impl Inspector<CTX, IT>,
282) where
283 CTX: ContextTr<Journal: JournalExt> + Host,
284 IT: InterpreterTypes,
285{
286 if interpreter
288 .bytecode
289 .action()
290 .as_ref()
291 .is_some_and(|x| x.is_return())
292 {
293 return;
294 }
295
296 let log = context.journal_mut().logs().last().unwrap().clone();
297 inspector.log_full(interpreter, context, log);
298}
299
300#[inline(never)]
301#[cold]
302fn inspect_selfdestruct<CTX, IT>(context: &mut CTX, inspector: &mut impl Inspector<CTX, IT>)
303where
304 CTX: ContextTr<Journal: JournalExt> + Host,
305 IT: InterpreterTypes,
306{
307 if let Some(
308 JournalEntry::AccountDestroyed {
309 address: contract,
310 target: to,
311 had_balance: balance,
312 ..
313 }
314 | JournalEntry::BalanceTransfer {
315 from: contract,
316 to,
317 balance,
318 ..
319 },
320 ) = context.journal_mut().journal().last()
321 {
322 inspector.selfdestruct(*contract, *to, *balance);
323 }
324}