revm_inspector/
inspector.rs

1use crate::{InspectorEvmTr, InspectorFrame};
2use auto_impl::auto_impl;
3use context::{
4    result::ResultAndState, Cfg, ContextTr, Database, JournalEntry, JournaledState, Transaction,
5};
6use handler::{
7    execution, EvmTr, Frame, FrameInitOrResult, FrameOrResult, FrameResult, Handler, ItemOrResult,
8};
9use interpreter::{
10    interpreter::EthInterpreter,
11    interpreter_types::{Jumps, LoopControl},
12    table::InstructionTable,
13    CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, FrameInput, Host,
14    InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction, InterpreterTypes,
15};
16use primitives::{Address, Log, U256};
17use state::EvmState;
18use std::{vec, vec::Vec};
19
20/// EVM [Interpreter] callbacks.
21#[auto_impl(&mut, Box)]
22pub trait Inspector<CTX, INTR: InterpreterTypes = EthInterpreter> {
23    /// Called before the interpreter is initialized.
24    ///
25    /// If `interp.instruction_result` is set to anything other than [InstructionResult::Continue] then the execution of the interpreter
26    /// is skipped.
27    #[inline]
28    fn initialize_interp(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
29        let _ = interp;
30        let _ = context;
31    }
32
33    /// Called on each step of the interpreter.
34    ///
35    /// Information about the current execution, including the memory, stack and more is available
36    /// on `interp` (see [Interpreter]).
37    ///
38    /// # Example
39    ///
40    /// To get the current opcode, use `interp.current_opcode()`.
41    #[inline]
42    fn step(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
43        let _ = interp;
44        let _ = context;
45    }
46
47    /// Called after `step` when the instruction has been executed.
48    ///
49    /// Setting `interp.instruction_result` to anything other than [InstructionResult::Continue] alters the execution
50    /// of the interpreter.
51    #[inline]
52    fn step_end(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX) {
53        let _ = interp;
54        let _ = context;
55    }
56
57    /// Called when a log is emitted.
58    #[inline]
59    fn log(&mut self, interp: &mut Interpreter<INTR>, context: &mut CTX, log: Log) {
60        let _ = interp;
61        let _ = context;
62        let _ = log;
63    }
64
65    /// Called whenever a call to a contract is about to start.
66    ///
67    /// InstructionResulting anything other than [InstructionResult::Continue] overrides the result of the call.
68    #[inline]
69    fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option<CallOutcome> {
70        let _ = context;
71        let _ = inputs;
72        None
73    }
74
75    /// Called when a call to a contract has concluded.
76    ///
77    /// The returned [CallOutcome] is used as the result of the call.
78    ///
79    /// This allows the inspector to modify the given `result` before returning it.
80    #[inline]
81    fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) {
82        let _ = context;
83        let _ = inputs;
84        let _ = outcome;
85    }
86
87    /// Called when a contract is about to be created.
88    ///
89    /// If this returns `Some` then the [CreateOutcome] is used to override the result of the creation.
90    ///
91    /// If this returns `None` then the creation proceeds as normal.
92    #[inline]
93    fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option<CreateOutcome> {
94        let _ = context;
95        let _ = inputs;
96        None
97    }
98
99    /// Called when a contract has been created.
100    ///
101    /// InstructionResulting anything other than the values passed to this function (`(ret, remaining_gas,
102    /// address, out)`) will alter the result of the create.
103    #[inline]
104    fn create_end(
105        &mut self,
106        context: &mut CTX,
107        inputs: &CreateInputs,
108        outcome: &mut CreateOutcome,
109    ) {
110        let _ = context;
111        let _ = inputs;
112        let _ = outcome;
113    }
114
115    /// Called when EOF creating is called.
116    ///
117    /// This can happen from create TX or from EOFCREATE opcode.
118    fn eofcreate(
119        &mut self,
120        context: &mut CTX,
121        inputs: &mut EOFCreateInputs,
122    ) -> Option<CreateOutcome> {
123        let _ = context;
124        let _ = inputs;
125        None
126    }
127
128    /// Called when eof creating has ended.
129    fn eofcreate_end(
130        &mut self,
131        context: &mut CTX,
132        inputs: &EOFCreateInputs,
133        outcome: &mut CreateOutcome,
134    ) {
135        let _ = context;
136        let _ = inputs;
137        let _ = outcome;
138    }
139
140    /// Called when a contract has been self-destructed with funds transferred to target.
141    #[inline]
142    fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
143        let _ = contract;
144        let _ = target;
145        let _ = value;
146    }
147}
148
149#[auto_impl(&mut, Box)]
150pub trait JournalExt {
151    fn logs(&self) -> &[Log];
152
153    fn last_journal(&self) -> &[JournalEntry];
154
155    fn evm_state(&self) -> &EvmState;
156
157    fn evm_state_mut(&mut self) -> &mut EvmState;
158}
159
160impl<DB: Database> JournalExt for JournaledState<DB> {
161    #[inline]
162    fn logs(&self) -> &[Log] {
163        &self.logs
164    }
165
166    #[inline]
167    fn last_journal(&self) -> &[JournalEntry] {
168        self.journal.last().expect("Journal is never empty")
169    }
170
171    #[inline]
172    fn evm_state(&self) -> &EvmState {
173        &self.state
174    }
175
176    #[inline]
177    fn evm_state_mut(&mut self) -> &mut EvmState {
178        &mut self.state
179    }
180}
181
182pub trait InspectorHandler: Handler
183where
184    Self::Evm:
185        InspectorEvmTr<Inspector: Inspector<<<Self as Handler>::Evm as EvmTr>::Context, Self::IT>>,
186    Self::Frame: InspectorFrame<IT = Self::IT>,
187{
188    type IT: InterpreterTypes;
189
190    fn inspect_run(
191        &mut self,
192        evm: &mut Self::Evm,
193    ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
194        let init_and_floor_gas = self.validate(evm)?;
195        let eip7702_refund = self.pre_execution(evm)? as i64;
196        let exec_result = self.inspect_execution(evm, &init_and_floor_gas);
197        self.post_execution(evm, exec_result?, init_and_floor_gas, eip7702_refund)
198    }
199
200    fn inspect_execution(
201        &mut self,
202        evm: &mut Self::Evm,
203        init_and_floor_gas: &InitialAndFloorGas,
204    ) -> Result<FrameResult, Self::Error> {
205        let gas_limit = evm.ctx().tx().gas_limit() - init_and_floor_gas.initial_gas;
206
207        // Create first frame action
208        let first_frame = self.inspect_create_first_frame(evm, gas_limit)?;
209        let mut frame_result = match first_frame {
210            ItemOrResult::Item(frame) => self.inspect_run_exec_loop(evm, frame)?,
211            ItemOrResult::Result(result) => result,
212        };
213
214        self.last_frame_result(evm, &mut frame_result)?;
215        Ok(frame_result)
216    }
217
218    /* EXECUTION */
219    fn inspect_create_first_frame(
220        &mut self,
221        evm: &mut Self::Evm,
222        gas_limit: u64,
223    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
224        let ctx = evm.ctx_ref();
225        let init_frame = execution::create_init_frame(ctx.tx(), ctx.cfg().spec().into(), gas_limit);
226        self.inspect_frame_init_first(evm, init_frame)
227    }
228
229    /* FRAMES */
230
231    fn inspect_frame_init_first(
232        &mut self,
233        evm: &mut Self::Evm,
234        mut frame_input: <Self::Frame as Frame>::FrameInit,
235    ) -> Result<FrameOrResult<Self::Frame>, Self::Error> {
236        let (ctx, inspector) = evm.ctx_inspector();
237        if let Some(output) = frame_start(ctx, inspector, &mut frame_input) {
238            return Ok(ItemOrResult::Result(output));
239        }
240        let mut ret = self.frame_init_first(evm, frame_input.clone());
241
242        // only if new frame is created call initialize_interp hook.
243        if let Ok(ItemOrResult::Item(frame)) = &mut ret {
244            let (context, inspector) = evm.ctx_inspector();
245            inspector.initialize_interp(frame.interpreter(), context);
246        } else if let Ok(ItemOrResult::Result(result)) = &mut ret {
247            let (context, inspector) = evm.ctx_inspector();
248            frame_end(context, inspector, &frame_input, result);
249        }
250        ret
251    }
252
253    #[inline]
254    fn inspect_frame_call(
255        &mut self,
256        frame: &mut Self::Frame,
257        evm: &mut Self::Evm,
258    ) -> Result<FrameInitOrResult<Self::Frame>, Self::Error> {
259        frame.run_inspect(evm)
260    }
261
262    fn inspect_run_exec_loop(
263        &mut self,
264        evm: &mut Self::Evm,
265        frame: Self::Frame,
266    ) -> Result<FrameResult, Self::Error> {
267        let mut frame_stack: Vec<Self::Frame> = vec![frame];
268        loop {
269            let frame = frame_stack.last_mut().unwrap();
270            let call_or_result = self.inspect_frame_call(frame, evm)?;
271
272            let result = match call_or_result {
273                ItemOrResult::Item(mut init) => {
274                    let (context, inspector) = evm.ctx_inspector();
275                    if let Some(output) = frame_start(context, inspector, &mut init) {
276                        output
277                    } else {
278                        match self.frame_init(frame, evm, init.clone())? {
279                            ItemOrResult::Item(mut new_frame) => {
280                                // only if new frame is created call initialize_interp hook.
281                                let (context, inspector) = evm.ctx_inspector();
282                                inspector.initialize_interp(new_frame.interpreter(), context);
283                                frame_stack.push(new_frame);
284                                continue;
285                            }
286                            // Dont pop the frame as new frame was not created.
287                            ItemOrResult::Result(mut result) => {
288                                let (context, inspector) = evm.ctx_inspector();
289                                frame_end(context, inspector, &init, &mut result);
290                                result
291                            }
292                        }
293                    }
294                }
295                ItemOrResult::Result(mut result) => {
296                    let (context, inspector) = evm.ctx_inspector();
297                    frame_end(context, inspector, frame.frame_input(), &mut result);
298
299                    // Pop frame that returned result
300                    frame_stack.pop();
301                    result
302                }
303            };
304
305            let Some(frame) = frame_stack.last_mut() else {
306                return Ok(result);
307            };
308
309            self.frame_return_result(frame, evm, result)?;
310        }
311    }
312}
313
314fn frame_start<CTX, INTR: InterpreterTypes>(
315    context: &mut CTX,
316    inspector: &mut impl Inspector<CTX, INTR>,
317    frame_input: &mut FrameInput,
318) -> Option<FrameResult> {
319    match frame_input {
320        FrameInput::Call(i) => {
321            if let Some(output) = inspector.call(context, i) {
322                return Some(FrameResult::Call(output));
323            }
324        }
325        FrameInput::Create(i) => {
326            if let Some(output) = inspector.create(context, i) {
327                return Some(FrameResult::Create(output));
328            }
329        }
330        FrameInput::EOFCreate(i) => {
331            if let Some(output) = inspector.eofcreate(context, i) {
332                return Some(FrameResult::EOFCreate(output));
333            }
334        }
335    }
336    None
337}
338
339fn frame_end<CTX, INTR: InterpreterTypes>(
340    context: &mut CTX,
341    inspector: &mut impl Inspector<CTX, INTR>,
342    frame_input: &FrameInput,
343    frame_output: &mut FrameResult,
344) {
345    match frame_output {
346        FrameResult::Call(outcome) => {
347            let FrameInput::Call(i) = frame_input else {
348                panic!("FrameInput::Call expected");
349            };
350            inspector.call_end(context, i, outcome);
351        }
352        FrameResult::Create(outcome) => {
353            let FrameInput::Create(i) = frame_input else {
354                panic!("FrameInput::Create expected");
355            };
356            inspector.create_end(context, i, outcome);
357        }
358        FrameResult::EOFCreate(outcome) => {
359            let FrameInput::EOFCreate(i) = frame_input else {
360                panic!("FrameInput::EofCreate expected");
361            };
362            inspector.eofcreate_end(context, i, outcome);
363        }
364    }
365}
366
367pub fn inspect_instructions<CTX, IT>(
368    context: &mut CTX,
369    interpreter: &mut Interpreter<IT>,
370    mut inspector: impl Inspector<CTX, IT>,
371    instructions: &InstructionTable<IT, CTX>,
372) -> InterpreterAction
373where
374    CTX: ContextTr<Journal: JournalExt> + Host,
375    IT: InterpreterTypes,
376{
377    interpreter.reset_control();
378
379    let mut log_num = context.journal().logs().len();
380    // Main loop
381    while interpreter.control.instruction_result().is_continue() {
382        // Get current opcode.
383        let opcode = interpreter.bytecode.opcode();
384
385        // Call Inspector step.
386        inspector.step(interpreter, context);
387        if interpreter.control.instruction_result() != InstructionResult::Continue {
388            break;
389        }
390
391        // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
392        // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction
393        // it will do noop and just stop execution of this contract
394        interpreter.bytecode.relative_jump(1);
395
396        // Execute instruction.
397        instructions[opcode as usize](interpreter, context);
398
399        // check if new log is added
400        let new_log = context.journal().logs().len();
401        if log_num < new_log {
402            // as there is a change in log number this means new log is added
403            let log = context.journal().logs().last().unwrap().clone();
404            inspector.log(interpreter, context, log);
405            log_num = new_log;
406        }
407
408        // Call step_end.
409        inspector.step_end(interpreter, context);
410    }
411
412    let next_action = interpreter.take_next_action();
413
414    // handle selfdestruct
415    if let InterpreterAction::Return { result } = &next_action {
416        if result.result == InstructionResult::SelfDestruct {
417            match context.journal().last_journal().last() {
418                Some(JournalEntry::AccountDestroyed {
419                    address,
420                    target,
421                    had_balance,
422                    ..
423                }) => {
424                    inspector.selfdestruct(*address, *target, *had_balance);
425                }
426                Some(JournalEntry::BalanceTransfer {
427                    from, to, balance, ..
428                }) => {
429                    inspector.selfdestruct(*from, *to, *balance);
430                }
431                _ => {}
432            }
433        }
434    }
435
436    next_action
437}