revm_handler/
evm.rs

1use crate::{
2    instructions::InstructionProvider, item_or_result::FrameInitOrResult, EthFrame, FrameResult,
3    ItemOrResult, PrecompileProvider,
4};
5use auto_impl::auto_impl;
6use context::{ContextTr, Database, Evm, FrameStack};
7use context_interface::context::ContextError;
8use interpreter::{interpreter::EthInterpreter, interpreter_action::FrameInit, InterpreterResult};
9
10/// Type alias for database error within a context
11pub type ContextDbError<CTX> = ContextError<ContextTrDbError<CTX>>;
12
13/// Type alias for frame error within a context
14pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
15
16/// Type alias for frame init result
17pub type FrameInitResult<'a, F> = ItemOrResult<&'a mut F, <F as FrameTr>::FrameResult>;
18
19/// Trait for defining a frame type used in EVM execution.
20#[auto_impl(&mut, Box)]
21pub trait FrameTr {
22    /// The result type returned when a frame completes execution.
23    type FrameResult: From<FrameResult>;
24    /// The initialization type used to create a new frame.
25    type FrameInit: From<FrameInit>;
26}
27
28/// A trait that integrates context, instruction set, and precompiles to create an EVM struct.
29///
30/// In addition to execution capabilities, this trait provides getter methods for its component fields.
31#[auto_impl(&mut, Box)]
32pub trait EvmTr {
33    /// The context type that implements ContextTr to provide access to execution state
34    type Context: ContextTr;
35    /// The instruction set type that implements InstructionProvider to define available operations
36    type Instructions: InstructionProvider;
37    /// The type containing the available precompiled contracts
38    type Precompiles: PrecompileProvider<Self::Context>;
39    /// The type containing the frame
40    type Frame: FrameTr;
41
42    /// Returns a tuple of references to the context, the frame and the instructions.
43    #[allow(clippy::type_complexity)]
44    fn all(
45        &self,
46    ) -> (
47        &Self::Context,
48        &Self::Instructions,
49        &Self::Precompiles,
50        &FrameStack<Self::Frame>,
51    );
52
53    /// Returns a tuple of mutable references to the context, the frame and the instructions.
54    #[allow(clippy::type_complexity)]
55    fn all_mut(
56        &mut self,
57    ) -> (
58        &mut Self::Context,
59        &mut Self::Instructions,
60        &mut Self::Precompiles,
61        &mut FrameStack<Self::Frame>,
62    );
63
64    /// Returns a mutable reference to the execution context
65    #[inline]
66    fn ctx(&mut self) -> &mut Self::Context {
67        let (ctx, _, _, _) = self.all_mut();
68        ctx
69    }
70
71    /// Returns a mutable reference to the execution context
72    #[inline]
73    fn ctx_mut(&mut self) -> &mut Self::Context {
74        self.ctx()
75    }
76
77    /// Returns an immutable reference to the execution context
78    #[inline]
79    fn ctx_ref(&self) -> &Self::Context {
80        let (ctx, _, _, _) = self.all();
81        ctx
82    }
83
84    /// Returns mutable references to both the context and instruction set.
85    /// This enables atomic access to both components when needed.
86    #[inline]
87    fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) {
88        let (ctx, instructions, _, _) = self.all_mut();
89        (ctx, instructions)
90    }
91
92    /// Returns mutable references to both the context and precompiles.
93    /// This enables atomic access to both components when needed.
94    #[inline]
95    fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) {
96        let (ctx, _, precompiles, _) = self.all_mut();
97        (ctx, precompiles)
98    }
99
100    /// Returns a mutable reference to the frame stack.
101    #[inline]
102    fn frame_stack(&mut self) -> &mut FrameStack<Self::Frame> {
103        let (_, _, _, frame_stack) = self.all_mut();
104        frame_stack
105    }
106
107    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
108    fn frame_init(
109        &mut self,
110        frame_input: <Self::Frame as FrameTr>::FrameInit,
111    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<Self::Context>>;
112
113    /// Run the frame from the top of the stack. Returns the frame init or result.
114    ///
115    /// If frame has returned result it would mark it as finished.
116    fn frame_run(
117        &mut self,
118    ) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<Self::Context>>;
119
120    /// Returns the result of the frame to the caller. Frame is popped from the frame stack.
121    /// Consumes the frame result or returns it if there is more frames to run.
122    fn frame_return_result(
123        &mut self,
124        result: <Self::Frame as FrameTr>::FrameResult,
125    ) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>>;
126}
127
128impl<CTX, INSP, I, P> EvmTr for Evm<CTX, INSP, I, P, EthFrame<EthInterpreter>>
129where
130    CTX: ContextTr,
131    I: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
132    P: PrecompileProvider<CTX, Output = InterpreterResult>,
133{
134    type Context = CTX;
135    type Instructions = I;
136    type Precompiles = P;
137    type Frame = EthFrame<EthInterpreter>;
138
139    #[inline]
140    fn all(
141        &self,
142    ) -> (
143        &Self::Context,
144        &Self::Instructions,
145        &Self::Precompiles,
146        &FrameStack<Self::Frame>,
147    ) {
148        let ctx = &self.ctx;
149        let instructions = &self.instruction;
150        let precompiles = &self.precompiles;
151        let frame_stack = &self.frame_stack;
152        (ctx, instructions, precompiles, frame_stack)
153    }
154
155    #[inline]
156    fn all_mut(
157        &mut self,
158    ) -> (
159        &mut Self::Context,
160        &mut Self::Instructions,
161        &mut Self::Precompiles,
162        &mut FrameStack<Self::Frame>,
163    ) {
164        let ctx = &mut self.ctx;
165        let instructions = &mut self.instruction;
166        let precompiles = &mut self.precompiles;
167        let frame_stack = &mut self.frame_stack;
168        (ctx, instructions, precompiles, frame_stack)
169    }
170
171    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
172    #[inline]
173    fn frame_init(
174        &mut self,
175        frame_input: <Self::Frame as FrameTr>::FrameInit,
176    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<CTX>> {
177        let is_first_init = self.frame_stack.index().is_none();
178        let new_frame = if is_first_init {
179            self.frame_stack.start_init()
180        } else {
181            self.frame_stack.get_next()
182        };
183
184        let ctx = &mut self.ctx;
185        let precompiles = &mut self.precompiles;
186        let res = Self::Frame::init_with_context(new_frame, ctx, precompiles, frame_input)?;
187
188        Ok(res.map_frame(|token| {
189            if is_first_init {
190                unsafe { self.frame_stack.end_init(token) };
191            } else {
192                unsafe { self.frame_stack.push(token) };
193            }
194            self.frame_stack.get()
195        }))
196    }
197
198    /// Run the frame from the top of the stack. Returns the frame init or result.
199    #[inline]
200    fn frame_run(&mut self) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<CTX>> {
201        let frame = self.frame_stack.get();
202        let context = &mut self.ctx;
203        let instructions = &mut self.instruction;
204
205        let action = frame
206            .interpreter
207            .run_plain(instructions.instruction_table(), context);
208
209        frame.process_next_action(context, action).inspect(|i| {
210            if i.is_result() {
211                frame.set_finished(true);
212            }
213        })
214    }
215
216    /// Returns the result of the frame to the caller. Frame is popped from the frame stack.
217    #[inline]
218    fn frame_return_result(
219        &mut self,
220        result: <Self::Frame as FrameTr>::FrameResult,
221    ) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>> {
222        if self.frame_stack.get().is_finished() {
223            self.frame_stack.pop();
224        }
225        if self.frame_stack.index().is_none() {
226            return Ok(Some(result));
227        }
228        self.frame_stack
229            .get()
230            .return_result::<_, ContextDbError<Self::Context>>(&mut self.ctx, result)?;
231        Ok(None)
232    }
233}