Skip to main content

revm_inspector/
traits.rs

1use context::{ContextTr, FrameStack, JournalTr};
2use handler::{
3    evm::{ContextDbError, FrameInitResult, FrameTr},
4    instructions::InstructionProvider,
5    EthFrame, EvmTr, FrameInitOrResult, FrameResult, ItemOrResult,
6};
7use interpreter::{
8    interpreter::EthInterpreter, interpreter_action::FrameInit, CallOutcome, FrameInput,
9    InterpreterTypes,
10};
11
12use crate::{
13    handler::{frame_end, frame_start, inspect_logs},
14    inspect_instructions, Inspector, JournalExt,
15};
16
17/// Inspector EVM trait. Extends the [`EvmTr`] trait with inspector related methods.
18///
19/// It contains execution of interpreter with [`crate::Inspector`] calls [`crate::Inspector::step`] and [`crate::Inspector::step_end`] calls.
20///
21/// It is used inside [`crate::InspectorHandler`] to extend evm with support for inspection.
22pub trait InspectorEvmTr:
23    EvmTr<
24    Frame: InspectorFrame<IT = EthInterpreter>,
25    Instructions: InstructionProvider<InterpreterTypes = EthInterpreter, Context = Self::Context>,
26    Context: ContextTr<Journal: JournalExt>,
27>
28{
29    /// The inspector type used for EVM execution inspection.
30    type Inspector: Inspector<Self::Context, EthInterpreter, FrameInput, FrameResult>;
31
32    /// Returns a tuple of mutable references to the context, the inspector, the frame and the instructions.
33    ///
34    /// This is one of two functions that need to be implemented for Evm. Second one is `all_mut`.
35    #[expect(clippy::type_complexity)]
36    fn all_inspector(
37        &self,
38    ) -> (
39        &Self::Context,
40        &Self::Instructions,
41        &Self::Precompiles,
42        &FrameStack<Self::Frame>,
43        &Self::Inspector,
44    );
45
46    /// Returns a tuple of mutable references to the context, the inspector, the frame and the instructions.
47    ///
48    /// This is one of two functions that need to be implemented for Evm. Second one is `all`.
49    #[expect(clippy::type_complexity)]
50    fn all_mut_inspector(
51        &mut self,
52    ) -> (
53        &mut Self::Context,
54        &mut Self::Instructions,
55        &mut Self::Precompiles,
56        &mut FrameStack<Self::Frame>,
57        &mut Self::Inspector,
58    );
59
60    /// Returns a mutable reference to the inspector.
61    fn inspector(&mut self) -> &mut Self::Inspector {
62        let (_, _, _, _, inspector) = self.all_mut_inspector();
63        inspector
64    }
65
66    /// Returns a tuple of mutable references to the context and the inspector.
67    ///
68    /// Useful when you want to allow inspector to modify the context.
69    fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) {
70        let (ctx, _, _, _, inspector) = self.all_mut_inspector();
71        (ctx, inspector)
72    }
73
74    /// Returns a tuple of mutable references to the context, the inspector and the frame.
75    ///
76    /// Useful when you want to allow inspector to modify the context and the frame.
77    fn ctx_inspector_frame(
78        &mut self,
79    ) -> (&mut Self::Context, &mut Self::Inspector, &mut Self::Frame) {
80        let (ctx, _, _, frame, inspector) = self.all_mut_inspector();
81        (ctx, inspector, frame.get())
82    }
83
84    /// Returns a tuple of mutable references to the context, the inspector, the frame and the instructions.
85    fn ctx_inspector_frame_instructions(
86        &mut self,
87    ) -> (
88        &mut Self::Context,
89        &mut Self::Inspector,
90        &mut Self::Frame,
91        &mut Self::Instructions,
92    ) {
93        let (ctx, instructions, _, frame, inspector) = self.all_mut_inspector();
94        (ctx, inspector, frame.get(), instructions)
95    }
96
97    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
98    #[inline]
99    fn inspect_frame_init(
100        &mut self,
101        mut frame_init: <Self::Frame as FrameTr>::FrameInit,
102    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<Self::Context>> {
103        let (ctx, inspector) = self.ctx_inspector();
104        if let Some(mut output) = frame_start(ctx, inspector, &mut frame_init.frame_input) {
105            frame_end(ctx, inspector, &frame_init.frame_input, &mut output);
106            return Ok(ItemOrResult::Result(output));
107        }
108
109        let frame_input = frame_init.frame_input.clone();
110        let logs_i = ctx.journal().logs().len();
111        if let ItemOrResult::Result(mut output) = self.frame_init(frame_init)? {
112            let (ctx, inspector) = self.ctx_inspector();
113            // Logs journaled by the frame: the EIP-7708 transfer log, and the
114            // logs of a precompile when one was called.
115            if ctx.journal().logs().len() != logs_i {
116                inspect_logs(None, ctx, inspector, logs_i);
117            }
118            // Custom precompiles gather their logs outside the journal.
119            if let FrameResult::Call(CallOutcome {
120                was_precompile_called: true,
121                precompile_call_logs,
122                ..
123            }) = &output
124            {
125                for log in precompile_call_logs.clone() {
126                    inspector.log(ctx, log);
127                }
128            }
129            frame_end(ctx, inspector, &frame_input, &mut output);
130            return Ok(ItemOrResult::Result(output));
131        }
132
133        // if it is new frame, initialize the interpreter.
134        let (ctx, inspector, frame) = self.ctx_inspector_frame();
135        if ctx.journal().logs().len() != logs_i {
136            inspect_logs(None, ctx, inspector, logs_i);
137        }
138        if let Some(frame) = frame.eth_frame() {
139            let interp = &mut frame.interpreter;
140            inspector.initialize_interp(interp, ctx);
141        };
142        Ok(ItemOrResult::Item(frame))
143    }
144
145    /// Run the frame from the top of the stack. Returns the frame init or result.
146    ///
147    /// If frame has returned result it would mark it as finished.
148    #[inline]
149    fn inspect_frame_run(
150        &mut self,
151    ) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<Self::Context>> {
152        let (ctx, inspector, frame, instructions) = self.ctx_inspector_frame_instructions();
153
154        let Some(frame) = frame.eth_frame() else {
155            return self.frame_run();
156        };
157
158        let next_action = inspect_instructions(
159            ctx,
160            &mut frame.interpreter,
161            inspector,
162            instructions.instruction_table(),
163            instructions.gas_table(),
164        );
165        let mut result = frame.process_next_action(ctx, next_action);
166
167        if let Ok(ItemOrResult::Result(frame_result)) = &mut result {
168            let (ctx, inspector, frame) = self.ctx_inspector_frame();
169            // TODO When all_mut fn is added we can fetch inspector at the top of the function.s
170            if let Some(frame) = frame.eth_frame() {
171                frame_end(ctx, inspector, &frame.input, frame_result);
172                frame.set_finished(true);
173            }
174        };
175        result
176    }
177}
178
179/// Trait that extends the [`FrameTr`] trait with additional functionality that is needed for inspection.
180pub trait InspectorFrame: FrameTr<FrameResult = FrameResult, FrameInit = FrameInit> {
181    /// The interpreter types used by this frame.
182    type IT: InterpreterTypes;
183
184    /// Returns a mutable reference to the EthFrame.
185    ///
186    /// If this frame does not have support for tracing (does not contain
187    /// the EthFrame) Inspector calls for this frame will be skipped.
188    fn eth_frame(&mut self) -> Option<&mut EthFrame<EthInterpreter>>;
189}
190
191/// Impl InspectorFrame for EthFrame.
192impl InspectorFrame for EthFrame<EthInterpreter> {
193    type IT = EthInterpreter;
194
195    fn eth_frame(&mut self) -> Option<&mut EthFrame<EthInterpreter>> {
196        Some(self)
197    }
198}