1use crate::{Inspector, InspectorEvmTr, JournalExt};
2use context::{result::ExecutionResult, ContextTr, JournalEntry, Transaction};
3use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult};
4use interpreter::{
5 instructions::InstructionTable,
6 interpreter_types::{Jumps, LoopControl},
7 FrameInput, Host, InitialAndFloorGas, InstructionContext, InstructionResult, Interpreter,
8 InterpreterAction, InterpreterTypes,
9};
10
11pub trait InspectorHandler: Handler
27where
28 Self::Evm:
29 InspectorEvmTr<Inspector: Inspector<<<Self as Handler>::Evm as EvmTr>::Context, Self::IT>>,
30{
31 type IT: InterpreterTypes;
33
34 fn inspect_run(
38 &mut self,
39 evm: &mut Self::Evm,
40 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
41 match self.inspect_run_without_catch_error(evm) {
42 Ok(output) => Ok(output),
43 Err(e) => self.catch_error(evm, e),
44 }
45 }
46
47 fn inspect_run_without_catch_error(
51 &mut self,
52 evm: &mut Self::Evm,
53 ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> {
54 let init_and_floor_gas = self.validate(evm)?;
55 let eip7702_refund = self.pre_execution(evm)? as i64;
56 let mut frame_result = self.inspect_execution(evm, &init_and_floor_gas)?;
57 self.post_execution(evm, &mut frame_result, init_and_floor_gas, eip7702_refund)?;
58 self.execution_result(evm, frame_result)
59 }
60
61 fn inspect_execution(
65 &mut self,
66 evm: &mut Self::Evm,
67 init_and_floor_gas: &InitialAndFloorGas,
68 ) -> Result<FrameResult, Self::Error> {
69 let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
70 let first_frame_input = self.first_frame_input(evm, gas_limit)?;
72
73 let mut frame_result = self.inspect_run_exec_loop(evm, first_frame_input)?;
75
76 self.last_frame_result(evm, &mut frame_result)?;
78 Ok(frame_result)
79 }
80
81 fn inspect_run_exec_loop(
92 &mut self,
93 evm: &mut Self::Evm,
94 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
95 ) -> Result<FrameResult, Self::Error> {
96 let res = evm.inspect_frame_init(first_frame_input)?;
97
98 if let ItemOrResult::Result(frame_result) = res {
99 return Ok(frame_result);
100 }
101
102 loop {
103 let call_or_result = evm.inspect_frame_run()?;
104
105 let result = match call_or_result {
106 ItemOrResult::Item(init) => {
107 match evm.inspect_frame_init(init)? {
108 ItemOrResult::Item(_) => {
109 continue;
110 }
111 ItemOrResult::Result(result) => result,
113 }
114 }
115 ItemOrResult::Result(result) => result,
116 };
117
118 if let Some(result) = evm.frame_return_result(result)? {
119 return Ok(result);
120 }
121 }
122 }
123}
124
125pub fn frame_start<CTX, INTR: InterpreterTypes>(
127 context: &mut CTX,
128 inspector: &mut impl Inspector<CTX, INTR>,
129 frame_input: &mut FrameInput,
130) -> Option<FrameResult> {
131 match frame_input {
132 FrameInput::Call(i) => {
133 if let Some(output) = inspector.call(context, i) {
134 return Some(FrameResult::Call(output));
135 }
136 }
137 FrameInput::Create(i) => {
138 if let Some(output) = inspector.create(context, i) {
139 return Some(FrameResult::Create(output));
140 }
141 }
142 FrameInput::Empty => unreachable!(),
143 }
144 None
145}
146
147pub fn frame_end<CTX, INTR: InterpreterTypes>(
149 context: &mut CTX,
150 inspector: &mut impl Inspector<CTX, INTR>,
151 frame_input: &FrameInput,
152 frame_output: &mut FrameResult,
153) {
154 match frame_output {
155 FrameResult::Call(outcome) => {
156 let FrameInput::Call(i) = frame_input else {
157 panic!("FrameInput::Call expected {frame_input:?}");
158 };
159 inspector.call_end(context, i, outcome);
160 }
161 FrameResult::Create(outcome) => {
162 let FrameInput::Create(i) = frame_input else {
163 panic!("FrameInput::Create expected {frame_input:?}");
164 };
165 inspector.create_end(context, i, outcome);
166 }
167 }
168}
169
170pub fn inspect_instructions<CTX, IT>(
176 context: &mut CTX,
177 interpreter: &mut Interpreter<IT>,
178 mut inspector: impl Inspector<CTX, IT>,
179 instructions: &InstructionTable<IT, CTX>,
180) -> InterpreterAction
181where
182 CTX: ContextTr<Journal: JournalExt> + Host,
183 IT: InterpreterTypes,
184{
185 let mut log_num = context.journal_mut().logs().len();
186 while interpreter.bytecode.is_not_end() {
188 let opcode = interpreter.bytecode.opcode();
190
191 inspector.step(interpreter, context);
193 if interpreter.bytecode.is_end() {
194 break;
195 }
196
197 interpreter.bytecode.relative_jump(1);
201
202 let instruction_context = InstructionContext {
204 interpreter,
205 host: context,
206 };
207 instructions[opcode as usize](instruction_context);
208
209 let new_log = context.journal_mut().logs().len();
211 if log_num < new_log {
212 let log = context.journal_mut().logs().last().unwrap().clone();
214 inspector.log(interpreter, context, log);
215 log_num = new_log;
216 }
217
218 inspector.step_end(interpreter, context);
220 }
221
222 interpreter.bytecode.revert_to_previous_pointer();
223
224 let next_action = interpreter.take_next_action();
225
226 if let InterpreterAction::Return(result) = &next_action {
228 if result.result == InstructionResult::SelfDestruct {
229 match context.journal_mut().journal().last() {
230 Some(JournalEntry::AccountDestroyed {
231 address,
232 target,
233 had_balance,
234 ..
235 }) => {
236 inspector.selfdestruct(*address, *target, *had_balance);
237 }
238 Some(JournalEntry::BalanceTransfer {
239 from, to, balance, ..
240 }) => {
241 inspector.selfdestruct(*from, *to, *balance);
242 }
243 _ => {}
244 }
245 }
246 }
247
248 next_action
249}