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