1use crate::{Inspector, InspectorEvmTr, JournalExt};
2use context::{
3 result::{ExecutionResult, ResultGas},
4 ContextTr, JournalEntry, JournalTr, Transaction,
5};
6use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult};
7use interpreter::{
8 instructions::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 init_and_floor_gas = self.validate(evm)?;
62 let eip7702_refund = self.pre_execution(evm)? as i64;
63 let mut frame_result = self.inspect_execution(evm, &init_and_floor_gas)?;
64 let result_gas =
65 self.post_execution(evm, &mut frame_result, init_and_floor_gas, eip7702_refund)?;
66 self.execution_result(evm, frame_result, result_gas)
67 }
68
69 fn inspect_execution(
73 &mut self,
74 evm: &mut Self::Evm,
75 init_and_floor_gas: &InitialAndFloorGas,
76 ) -> Result<FrameResult, Self::Error> {
77 let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
78 let first_frame_input = self.first_frame_input(evm, gas_limit)?;
80
81 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
83
84 self.last_frame_result(evm, &mut frame_result)?;
86 Ok(frame_result)
87 }
88
89 fn inspect_run_exec_loop(
100 &mut self,
101 evm: &mut Self::Evm,
102 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
103 ) -> Result<FrameResult, Self::Error> {
104 let res = evm.inspect_frame_init(first_frame_input)?;
105
106 if let ItemOrResult::Result(frame_result) = res {
107 return Ok(frame_result);
108 }
109
110 loop {
111 let call_or_result = evm.inspect_frame_run()?;
112
113 let result = match call_or_result {
114 ItemOrResult::Item(init) => {
115 match evm.inspect_frame_init(init)? {
116 ItemOrResult::Item(_) => {
117 continue;
118 }
119 ItemOrResult::Result(result) => result,
121 }
122 }
123 ItemOrResult::Result(result) => result,
124 };
125
126 if let Some(result) = evm.frame_return_result(result)? {
127 return Ok(result);
128 }
129 }
130 }
131
132 fn inspect_run_system_call(
138 &mut self,
139 evm: &mut Self::Evm,
140 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
141 let init_and_floor_gas = InitialAndFloorGas::new(0, 0);
143 match self
145 .inspect_execution(evm, &init_and_floor_gas)
146 .and_then(|exec_result| {
147 let gas = exec_result.gas();
149 let result_gas =
150 ResultGas::new(gas.limit(), gas.spent(), gas.refunded() as u64, 0, 0);
151 self.execution_result(evm, exec_result, result_gas)
152 }) {
153 out @ Ok(_) => out,
154 Err(e) => self.catch_error(evm, e),
155 }
156 }
157}
158
159pub fn frame_start<CTX, INTR: InterpreterTypes>(
161 context: &mut CTX,
162 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
163 frame_input: &mut FrameInput,
164) -> Option<FrameResult> {
165 if let Some(result) = inspector.frame_start(context, frame_input) {
167 return Some(result);
168 }
169 match frame_input {
171 FrameInput::Call(i) => {
172 if let Some(output) = inspector.call(context, i) {
173 return Some(FrameResult::Call(output));
174 }
175 }
176 FrameInput::Create(i) => {
177 if let Some(output) = inspector.create(context, i) {
178 return Some(FrameResult::Create(output));
179 }
180 }
181 FrameInput::Empty => unreachable!(),
182 }
183 None
184}
185
186pub fn frame_end<CTX, INTR: InterpreterTypes>(
188 context: &mut CTX,
189 inspector: &mut impl Inspector<CTX, INTR, FrameInput, FrameResult>,
190 frame_input: &FrameInput,
191 frame_output: &mut FrameResult,
192) {
193 match frame_output {
195 FrameResult::Call(outcome) => {
196 let FrameInput::Call(i) = frame_input else {
197 panic!("FrameInput::Call expected {frame_input:?}");
198 };
199 inspector.call_end(context, i, outcome);
200 }
201 FrameResult::Create(outcome) => {
202 let FrameInput::Create(i) = frame_input else {
203 panic!("FrameInput::Create expected {frame_input:?}");
204 };
205 inspector.create_end(context, i, outcome);
206 }
207 }
208 inspector.frame_end(context, frame_input, frame_output);
210}
211
212pub fn inspect_instructions<CTX, IT>(
218 context: &mut CTX,
219 interpreter: &mut Interpreter<IT>,
220 mut inspector: impl Inspector<CTX, IT>,
221 instructions: &InstructionTable<IT, CTX>,
222) -> InterpreterAction
223where
224 CTX: ContextTr<Journal: JournalExt> + Host,
225 IT: InterpreterTypes,
226{
227 loop {
228 inspector.step(interpreter, context);
229 if interpreter.bytecode.is_end() {
230 break;
231 }
232
233 let opcode = interpreter.bytecode.opcode();
234 interpreter.step(instructions, context);
235
236 if (opcode::LOG0..=opcode::LOG4).contains(&opcode) {
237 inspect_log(interpreter, context, &mut inspector);
238 }
239
240 inspector.step_end(interpreter, context);
241
242 if interpreter.bytecode.is_end() {
243 break;
244 }
245 }
246
247 let next_action = interpreter.take_next_action();
248
249 if let InterpreterAction::Return(result) = &next_action {
251 if result.result == InstructionResult::SelfDestruct {
252 inspect_selfdestruct(context, &mut inspector);
253 }
254 }
255
256 next_action
257}
258
259#[inline(never)]
260#[cold]
261fn inspect_log<CTX, IT>(
262 interpreter: &mut Interpreter<IT>,
263 context: &mut CTX,
264 inspector: &mut impl Inspector<CTX, IT>,
265) where
266 CTX: ContextTr<Journal: JournalExt> + Host,
267 IT: InterpreterTypes,
268{
269 if interpreter
271 .bytecode
272 .action()
273 .as_ref()
274 .is_some_and(|x| x.is_return())
275 {
276 return;
277 }
278
279 let log = context.journal_mut().logs().last().unwrap().clone();
280 inspector.log_full(interpreter, context, log);
281}
282
283#[inline(never)]
284#[cold]
285fn inspect_selfdestruct<CTX, IT>(context: &mut CTX, inspector: &mut impl Inspector<CTX, IT>)
286where
287 CTX: ContextTr<Journal: JournalExt> + Host,
288 IT: InterpreterTypes,
289{
290 if let Some(
291 JournalEntry::AccountDestroyed {
292 address: contract,
293 target: to,
294 had_balance: balance,
295 ..
296 }
297 | JournalEntry::BalanceTransfer {
298 from: contract,
299 to,
300 balance,
301 ..
302 },
303 ) = context.journal_mut().journal().last()
304 {
305 inspector.selfdestruct(*contract, *to, *balance);
306 }
307}