revm_inspector/
handler.rs

1use crate::{Inspector, InspectorEvmTr, InspectorFrame, JournalExt};
2use context::{result::ResultAndState, ContextTr, JournalEntry, Transaction};
3use handler::{EvmTr, Frame, FrameInitOrResult, FrameOrResult, FrameResult, Handler, ItemOrResult};
4use interpreter::{
5    instructions::InstructionTable,
6    interpreter_types::{Jumps, LoopControl},
7    FrameInput, Host, InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction,
8    InterpreterTypes,
9};
10
11use std::{vec, vec::Vec};
12
13/// Trait that extends [`Handler`] with inspection functionality.
14///
15/// Similar how [`Handler::run`] method serves as the entry point,
16/// [`InspectorHandler::inspect_run`] method serves as the entry point for inspection.
17///
18/// Notice that when inspection is run it skips few functions from handler, this can be
19/// a problem if custom EVM is implemented and some of skipped functions have changed logic.
20/// For custom EVM, those changed functions would need to be also changed in [`InspectorHandler`].
21///
22/// List of functions that are skipped in [`InspectorHandler`]:
23/// * [`Handler::run`] replaced with [`InspectorHandler::inspect_run`]
24/// * [`Handler::run_without_catch_error`] replaced with [`InspectorHandler::inspect_run_without_catch_error`]
25/// * [`Handler::execution`] replaced with [`InspectorHandler::inspect_execution`]
26/// * [`Handler::first_frame_init`] replaced with [`InspectorHandler::inspect_first_frame_init`]
27/// * [`Handler::frame_call`] replaced with [`InspectorHandler::inspect_frame_call`]
28/// * [`Handler::run_exec_loop`] replaced with [`InspectorHandler::inspect_run_exec_loop`]
29pub trait InspectorHandler: Handler
30where
31    Self::Evm:
32        InspectorEvmTr<Inspector: Inspector<<<Self as Handler>::Evm as EvmTr>::Context, Self::IT>>,
33    Self::Frame: InspectorFrame<IT = Self::IT>,
34{
35    type IT: InterpreterTypes;
36
37    /// Entry point for inspection.
38    ///
39    /// This method is acts as [`Handler::run`] method for inspection.
40    fn inspect_run(
41        &mut self,
42        evm: &mut Self::Evm,
43    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
44        match self.inspect_run_without_catch_error(evm) {
45            Ok(output) => Ok(output),
46            Err(e) => self.catch_error(evm, e),
47        }
48    }
49
50    /// Run inspection without catching error.
51    ///
52    /// This method is acts as [`Handler::run_without_catch_error`] method for inspection.
53    fn inspect_run_without_catch_error(
54        &mut self,
55        evm: &mut Self::Evm,
56    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
57        let init_and_floor_gas = self.validate(evm)?;
58        let eip7702_refund = self.pre_execution(evm)? as i64;
59        let exec_result = self.inspect_execution(evm, &init_and_floor_gas);
60        self.post_execution(evm, exec_result?, init_and_floor_gas, eip7702_refund)
61    }
62
63    /// Run execution loop with inspection support
64    ///
65    /// This method acts as [`Handler::execution`] method for inspection.
66    fn inspect_execution(
67        &mut self,
68        evm: &mut Self::Evm,
69        init_and_floor_gas: &InitialAndFloorGas,
70    ) -> Result<FrameResult, Self::Error> {
71        let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
72
73        // Create first frame action
74        let first_frame_input = self.first_frame_input(evm, gas_limit)?;
75        let first_frame = self.inspect_first_frame_init(evm, first_frame_input)?;
76
77        let mut frame_result = match first_frame {
78            ItemOrResult::Item(frame) => self.inspect_run_exec_loop(evm, frame)?,
79            ItemOrResult::Result(result) => result,
80        };
81
82        self.last_frame_result(evm, &mut frame_result)?;
83        Ok(frame_result)
84    }
85
86    /* FRAMES */
87
88    /// Initialize first frame.
89    ///
90    /// This method replaces the [`Handler::first_frame_init`] method from [`Handler`].
91    ///
92    /// * It calls [`Inspector::call`]/[`Inspector::create`]/[`Inspector::eofcreate`] methods to allow inspection of
93    ///   the frame and its modification.
94    /// * If new frame is created a [`Inspector::initialize_interp`] method will be called.
95    /// * If creation of new frame returns the result, the [`Inspector`] `_end` methods will be called.
96    fn inspect_first_frame_init(
97        &mut self,
98        evm: &mut Self::Evm,
99        mut frame_input: <Self::Frame as Frame>::FrameInit,
100    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
101        let (ctx, inspector) = evm.ctx_inspector();
102        if let Some(output) = frame_start(ctx, inspector, &mut frame_input) {
103            return Ok(ItemOrResult::Result(output));
104        }
105        let mut ret = self.first_frame_init(evm, frame_input.clone());
106
107        // only if new frame is created call initialize_interp hook.
108        if let Ok(ItemOrResult::Item(frame)) = &mut ret {
109            let (context, inspector) = evm.ctx_inspector();
110            inspector.initialize_interp(frame.interpreter(), context);
111        } else if let Ok(ItemOrResult::Result(result)) = &mut ret {
112            let (context, inspector) = evm.ctx_inspector();
113            frame_end(context, inspector, &frame_input, result);
114        }
115        ret
116    }
117
118    /// Run inspection on frame.
119    ///
120    /// This method acts as [`Handler::frame_call`] method for inspection.
121    ///
122    /// Internally it will call [`Inspector::step`], [`Inspector::step_end`] for each instruction.
123    /// And [`Inspector::log`],[`Inspector::selfdestruct`] for each log and selfdestruct instruction.
124    #[inline]
125    fn inspect_frame_call(
126        &mut self,
127        frame: &mut Self::Frame,
128        evm: &mut Self::Evm,
129    ) -> Result<FrameInitOrResult<Self::Frame>, Self::Error> {
130        frame.run_inspect(evm)
131    }
132
133    /// Run inspection on execution loop.
134    ///
135    /// This method acts as [`Handler::run_exec_loop`] method for inspection.
136    ///
137    /// It will call:
138    /// * [`InspectorHandler::inspect_frame_call`] to inspect Interpreter execution loop.
139    /// * [`Inspector::call`],[`Inspector::create`],[`Inspector::eofcreate`] to inspect call, create and eofcreate.
140    /// * [`Inspector::call_end`],[`Inspector::create_end`],[`Inspector::eofcreate_end`] to inspect call, create and eofcreate end.
141    /// * [`Inspector::initialize_interp`] to inspect initialized interpreter.
142    fn inspect_run_exec_loop(
143        &mut self,
144        evm: &mut Self::Evm,
145        frame: Self::Frame,
146    ) -> Result<FrameResult, Self::Error> {
147        let mut frame_stack: Vec<Self::Frame> = vec![frame];
148        loop {
149            let frame = frame_stack.last_mut().unwrap();
150            let call_or_result = self.inspect_frame_call(frame, evm)?;
151
152            let result = match call_or_result {
153                ItemOrResult::Item(mut init) => {
154                    let (context, inspector) = evm.ctx_inspector();
155                    if let Some(output) = frame_start(context, inspector, &mut init) {
156                        output
157                    } else {
158                        match self.frame_init(frame, evm, init.clone())? {
159                            ItemOrResult::Item(mut new_frame) => {
160                                // only if new frame is created call initialize_interp hook.
161                                let (context, inspector) = evm.ctx_inspector();
162                                inspector.initialize_interp(new_frame.interpreter(), context);
163                                frame_stack.push(new_frame);
164                                continue;
165                            }
166                            // Dont pop the frame as new frame was not created.
167                            ItemOrResult::Result(mut result) => {
168                                let (context, inspector) = evm.ctx_inspector();
169                                frame_end(context, inspector, &init, &mut result);
170                                result
171                            }
172                        }
173                    }
174                }
175                ItemOrResult::Result(mut result) => {
176                    let (context, inspector) = evm.ctx_inspector();
177                    frame_end(context, inspector, frame.frame_input(), &mut result);
178
179                    // Pop frame that returned result
180                    frame_stack.pop();
181                    result
182                }
183            };
184
185            let Some(frame) = frame_stack.last_mut() else {
186                return Ok(result);
187            };
188
189            self.frame_return_result(frame, evm, result)?;
190        }
191    }
192}
193
194pub fn frame_start<CTX, INTR: InterpreterTypes>(
195    context: &mut CTX,
196    inspector: &mut impl Inspector<CTX, INTR>,
197    frame_input: &mut FrameInput,
198) -> Option<FrameResult> {
199    match frame_input {
200        FrameInput::Call(i) => {
201            if let Some(output) = inspector.call(context, i) {
202                return Some(FrameResult::Call(output));
203            }
204        }
205        FrameInput::Create(i) => {
206            if let Some(output) = inspector.create(context, i) {
207                return Some(FrameResult::Create(output));
208            }
209        }
210        FrameInput::EOFCreate(i) => {
211            if let Some(output) = inspector.eofcreate(context, i) {
212                return Some(FrameResult::EOFCreate(output));
213            }
214        }
215    }
216    None
217}
218
219pub fn frame_end<CTX, INTR: InterpreterTypes>(
220    context: &mut CTX,
221    inspector: &mut impl Inspector<CTX, INTR>,
222    frame_input: &FrameInput,
223    frame_output: &mut FrameResult,
224) {
225    match frame_output {
226        FrameResult::Call(outcome) => {
227            let FrameInput::Call(i) = frame_input else {
228                panic!("FrameInput::Call expected");
229            };
230            inspector.call_end(context, i, outcome);
231        }
232        FrameResult::Create(outcome) => {
233            let FrameInput::Create(i) = frame_input else {
234                panic!("FrameInput::Create expected");
235            };
236            inspector.create_end(context, i, outcome);
237        }
238        FrameResult::EOFCreate(outcome) => {
239            let FrameInput::EOFCreate(i) = frame_input else {
240                panic!("FrameInput::EofCreate expected");
241            };
242            inspector.eofcreate_end(context, i, outcome);
243        }
244    }
245}
246
247/// Run Interpreter loop with inspection support.
248///
249/// This function is used to inspect the Interpreter loop.
250/// It will call [`Inspector::step`] and [`Inspector::step_end`] after each instruction.
251/// And [`Inspector::log`],[`Inspector::selfdestruct`] for each log and selfdestruct instruction.
252pub fn inspect_instructions<CTX, IT>(
253    context: &mut CTX,
254    interpreter: &mut Interpreter<IT>,
255    mut inspector: impl Inspector<CTX, IT>,
256    instructions: &InstructionTable<IT, CTX>,
257) -> InterpreterAction
258where
259    CTX: ContextTr<Journal: JournalExt> + Host,
260    IT: InterpreterTypes,
261{
262    interpreter.reset_control();
263
264    let mut log_num = context.journal().logs().len();
265    // Main loop
266    while interpreter.control.instruction_result().is_continue() {
267        // Get current opcode.
268        let opcode = interpreter.bytecode.opcode();
269
270        // Call Inspector step.
271        inspector.step(interpreter, context);
272        if interpreter.control.instruction_result() != InstructionResult::Continue {
273            break;
274        }
275
276        // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
277        // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction
278        // it will do noop and just stop execution of this contract
279        interpreter.bytecode.relative_jump(1);
280
281        // Execute instruction.
282        instructions[opcode as usize](interpreter, context);
283
284        // check if new log is added
285        let new_log = context.journal().logs().len();
286        if log_num < new_log {
287            // as there is a change in log number this means new log is added
288            let log = context.journal().logs().last().unwrap().clone();
289            inspector.log(interpreter, context, log);
290            log_num = new_log;
291        }
292
293        // Call step_end.
294        inspector.step_end(interpreter, context);
295    }
296
297    let next_action = interpreter.take_next_action();
298
299    // handle selfdestruct
300    if let InterpreterAction::Return { result } = &next_action {
301        if result.result == InstructionResult::SelfDestruct {
302            match context.journal().last_journal().last() {
303                Some(JournalEntry::AccountDestroyed {
304                    address,
305                    target,
306                    had_balance,
307                    ..
308                }) => {
309                    inspector.selfdestruct(*address, *target, *had_balance);
310                }
311                Some(JournalEntry::BalanceTransfer {
312                    from, to, balance, ..
313                }) => {
314                    inspector.selfdestruct(*from, *to, *balance);
315                }
316                _ => {}
317            }
318        }
319    }
320
321    next_action
322}