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(mut output) = frame_start(ctx, inspector, &mut frame_input) {
103            frame_end(ctx, inspector, &frame_input, &mut output);
104            return Ok(ItemOrResult::Result(output));
105        }
106        let mut ret = self.first_frame_init(evm, frame_input.clone());
107
108        // only if new frame is created call initialize_interp hook.
109        if let Ok(ItemOrResult::Item(frame)) = &mut ret {
110            let (context, inspector) = evm.ctx_inspector();
111            inspector.initialize_interp(frame.interpreter(), context);
112        } else if let Ok(ItemOrResult::Result(result)) = &mut ret {
113            let (context, inspector) = evm.ctx_inspector();
114            frame_end(context, inspector, &frame_input, result);
115        }
116        ret
117    }
118
119    /// Run inspection on frame.
120    ///
121    /// This method acts as [`Handler::frame_call`] method for inspection.
122    ///
123    /// Internally it will call [`Inspector::step`], [`Inspector::step_end`] for each instruction.
124    /// And [`Inspector::log`],[`Inspector::selfdestruct`] for each log and selfdestruct instruction.
125    #[inline]
126    fn inspect_frame_call(
127        &mut self,
128        frame: &mut Self::Frame,
129        evm: &mut Self::Evm,
130    ) -> Result<FrameInitOrResult<Self::Frame>, Self::Error> {
131        frame.run_inspect(evm)
132    }
133
134    /// Run inspection on execution loop.
135    ///
136    /// This method acts as [`Handler::run_exec_loop`] method for inspection.
137    ///
138    /// It will call:
139    /// * [`InspectorHandler::inspect_frame_call`] to inspect Interpreter execution loop.
140    /// * [`Inspector::call`],[`Inspector::create`],[`Inspector::eofcreate`] to inspect call, create and eofcreate.
141    /// * [`Inspector::call_end`],[`Inspector::create_end`],[`Inspector::eofcreate_end`] to inspect call, create and eofcreate end.
142    /// * [`Inspector::initialize_interp`] to inspect initialized interpreter.
143    fn inspect_run_exec_loop(
144        &mut self,
145        evm: &mut Self::Evm,
146        frame: Self::Frame,
147    ) -> Result<FrameResult, Self::Error> {
148        let mut frame_stack: Vec<Self::Frame> = vec![frame];
149        loop {
150            let frame = frame_stack.last_mut().unwrap();
151            let call_or_result = self.inspect_frame_call(frame, evm)?;
152
153            let result = match call_or_result {
154                ItemOrResult::Item(mut init) => {
155                    let (context, inspector) = evm.ctx_inspector();
156                    if let Some(mut output) = frame_start(context, inspector, &mut init) {
157                        frame_end(context, inspector, &init, &mut output);
158                        output
159                    } else {
160                        match self.frame_init(frame, evm, init.clone())? {
161                            ItemOrResult::Item(mut new_frame) => {
162                                // only if new frame is created call initialize_interp hook.
163                                let (context, inspector) = evm.ctx_inspector();
164                                inspector.initialize_interp(new_frame.interpreter(), context);
165                                frame_stack.push(new_frame);
166                                continue;
167                            }
168                            // Dont pop the frame as new frame was not created.
169                            ItemOrResult::Result(mut result) => {
170                                let (context, inspector) = evm.ctx_inspector();
171                                frame_end(context, inspector, &init, &mut result);
172                                result
173                            }
174                        }
175                    }
176                }
177                ItemOrResult::Result(mut result) => {
178                    let (context, inspector) = evm.ctx_inspector();
179                    frame_end(context, inspector, frame.frame_input(), &mut result);
180
181                    // Pop frame that returned result
182                    frame_stack.pop();
183                    result
184                }
185            };
186
187            let Some(frame) = frame_stack.last_mut() else {
188                return Ok(result);
189            };
190
191            self.frame_return_result(frame, evm, result)?;
192        }
193    }
194}
195
196pub fn frame_start<CTX, INTR: InterpreterTypes>(
197    context: &mut CTX,
198    inspector: &mut impl Inspector<CTX, INTR>,
199    frame_input: &mut FrameInput,
200) -> Option<FrameResult> {
201    match frame_input {
202        FrameInput::Call(i) => {
203            if let Some(output) = inspector.call(context, i) {
204                return Some(FrameResult::Call(output));
205            }
206        }
207        FrameInput::Create(i) => {
208            if let Some(output) = inspector.create(context, i) {
209                return Some(FrameResult::Create(output));
210            }
211        }
212        FrameInput::EOFCreate(i) => {
213            if let Some(output) = inspector.eofcreate(context, i) {
214                return Some(FrameResult::EOFCreate(output));
215            }
216        }
217    }
218    None
219}
220
221pub fn frame_end<CTX, INTR: InterpreterTypes>(
222    context: &mut CTX,
223    inspector: &mut impl Inspector<CTX, INTR>,
224    frame_input: &FrameInput,
225    frame_output: &mut FrameResult,
226) {
227    match frame_output {
228        FrameResult::Call(outcome) => {
229            let FrameInput::Call(i) = frame_input else {
230                panic!("FrameInput::Call expected");
231            };
232            inspector.call_end(context, i, outcome);
233        }
234        FrameResult::Create(outcome) => {
235            let FrameInput::Create(i) = frame_input else {
236                panic!("FrameInput::Create expected");
237            };
238            inspector.create_end(context, i, outcome);
239        }
240        FrameResult::EOFCreate(outcome) => {
241            let FrameInput::EOFCreate(i) = frame_input else {
242                panic!("FrameInput::EofCreate expected");
243            };
244            inspector.eofcreate_end(context, i, outcome);
245        }
246    }
247}
248
249/// Run Interpreter loop with inspection support.
250///
251/// This function is used to inspect the Interpreter loop.
252/// It will call [`Inspector::step`] and [`Inspector::step_end`] after each instruction.
253/// And [`Inspector::log`],[`Inspector::selfdestruct`] for each log and selfdestruct instruction.
254pub fn inspect_instructions<CTX, IT>(
255    context: &mut CTX,
256    interpreter: &mut Interpreter<IT>,
257    mut inspector: impl Inspector<CTX, IT>,
258    instructions: &InstructionTable<IT, CTX>,
259) -> InterpreterAction
260where
261    CTX: ContextTr<Journal: JournalExt> + Host,
262    IT: InterpreterTypes,
263{
264    interpreter.reset_control();
265
266    let mut log_num = context.journal().logs().len();
267    // Main loop
268    while interpreter.control.instruction_result().is_continue() {
269        // Get current opcode.
270        let opcode = interpreter.bytecode.opcode();
271
272        // Call Inspector step.
273        inspector.step(interpreter, context);
274        if interpreter.control.instruction_result() != InstructionResult::Continue {
275            break;
276        }
277
278        // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
279        // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction
280        // it will do noop and just stop execution of this contract
281        interpreter.bytecode.relative_jump(1);
282
283        // Execute instruction.
284        instructions[opcode as usize](interpreter, context);
285
286        // check if new log is added
287        let new_log = context.journal().logs().len();
288        if log_num < new_log {
289            // as there is a change in log number this means new log is added
290            let log = context.journal().logs().last().unwrap().clone();
291            inspector.log(interpreter, context, log);
292            log_num = new_log;
293        }
294
295        // Call step_end.
296        inspector.step_end(interpreter, context);
297    }
298
299    let next_action = interpreter.take_next_action();
300
301    // handle selfdestruct
302    if let InterpreterAction::Return { result } = &next_action {
303        if result.result == InstructionResult::SelfDestruct {
304            match context.journal().journal().last() {
305                Some(JournalEntry::AccountDestroyed {
306                    address,
307                    target,
308                    had_balance,
309                    ..
310                }) => {
311                    inspector.selfdestruct(*address, *target, *had_balance);
312                }
313                Some(JournalEntry::BalanceTransfer {
314                    from, to, balance, ..
315                }) => {
316                    inspector.selfdestruct(*from, *to, *balance);
317                }
318                _ => {}
319            }
320        }
321    }
322
323    next_action
324}