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>,
163 frame_input: &mut FrameInput,
164) -> Option<FrameResult> {
165 match frame_input {
166 FrameInput::Call(i) => {
167 if let Some(output) = inspector.call(context, i) {
168 return Some(FrameResult::Call(output));
169 }
170 }
171 FrameInput::Create(i) => {
172 if let Some(output) = inspector.create(context, i) {
173 return Some(FrameResult::Create(output));
174 }
175 }
176 FrameInput::Empty => unreachable!(),
177 }
178 None
179}
180
181pub fn frame_end<CTX, INTR: InterpreterTypes>(
183 context: &mut CTX,
184 inspector: &mut impl Inspector<CTX, INTR>,
185 frame_input: &FrameInput,
186 frame_output: &mut FrameResult,
187) {
188 match frame_output {
189 FrameResult::Call(outcome) => {
190 let FrameInput::Call(i) = frame_input else {
191 panic!("FrameInput::Call expected {frame_input:?}");
192 };
193 inspector.call_end(context, i, outcome);
194 }
195 FrameResult::Create(outcome) => {
196 let FrameInput::Create(i) = frame_input else {
197 panic!("FrameInput::Create expected {frame_input:?}");
198 };
199 inspector.create_end(context, i, outcome);
200 }
201 }
202}
203
204pub fn inspect_instructions<CTX, IT>(
210 context: &mut CTX,
211 interpreter: &mut Interpreter<IT>,
212 mut inspector: impl Inspector<CTX, IT>,
213 instructions: &InstructionTable<IT, CTX>,
214) -> InterpreterAction
215where
216 CTX: ContextTr<Journal: JournalExt> + Host,
217 IT: InterpreterTypes,
218{
219 loop {
220 inspector.step(interpreter, context);
221 if interpreter.bytecode.is_end() {
222 break;
223 }
224
225 let opcode = interpreter.bytecode.opcode();
226 interpreter.step(instructions, context);
227
228 if (opcode::LOG0..=opcode::LOG4).contains(&opcode) {
229 inspect_log(interpreter, context, &mut inspector);
230 }
231
232 inspector.step_end(interpreter, context);
233
234 if interpreter.bytecode.is_end() {
235 break;
236 }
237 }
238
239 let next_action = interpreter.take_next_action();
240
241 if let InterpreterAction::Return(result) = &next_action {
243 if result.result == InstructionResult::SelfDestruct {
244 inspect_selfdestruct(context, &mut inspector);
245 }
246 }
247
248 next_action
249}
250
251#[inline(never)]
252#[cold]
253fn inspect_log<CTX, IT>(
254 interpreter: &mut Interpreter<IT>,
255 context: &mut CTX,
256 inspector: &mut impl Inspector<CTX, IT>,
257) where
258 CTX: ContextTr<Journal: JournalExt> + Host,
259 IT: InterpreterTypes,
260{
261 if interpreter
263 .bytecode
264 .action()
265 .as_ref()
266 .is_some_and(|x| x.is_return())
267 {
268 return;
269 }
270
271 let log = context.journal_mut().logs().last().unwrap().clone();
272 inspector.log_full(interpreter, context, log);
273}
274
275#[inline(never)]
276#[cold]
277fn inspect_selfdestruct<CTX, IT>(context: &mut CTX, inspector: &mut impl Inspector<CTX, IT>)
278where
279 CTX: ContextTr<Journal: JournalExt> + Host,
280 IT: InterpreterTypes,
281{
282 if let Some(
283 JournalEntry::AccountDestroyed {
284 address: contract,
285 target: to,
286 had_balance: balance,
287 ..
288 }
289 | JournalEntry::BalanceTransfer {
290 from: contract,
291 to,
292 balance,
293 ..
294 },
295 ) = context.journal_mut().journal().last()
296 {
297 inspector.selfdestruct(*contract, *to, *balance);
298 }
299}