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: Into<FrameResult>;
24    /// The initialization type used to create a new frame.
25    type FrameInit: Into<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 mutable reference to the execution context
43    fn ctx(&mut self) -> &mut Self::Context;
44
45    /// Returns a mutable reference to the execution context
46    fn ctx_mut(&mut self) -> &mut Self::Context {
47        self.ctx()
48    }
49
50    /// Returns an immutable reference to the execution context
51    fn ctx_ref(&self) -> &Self::Context;
52
53    /// Returns mutable references to both the context and instruction set.
54    /// This enables atomic access to both components when needed.
55    fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions);
56
57    /// Returns mutable references to both the context and precompiles.
58    /// This enables atomic access to both components when needed.
59    fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles);
60
61    /// Returns a mutable reference to the frame stack.
62    fn frame_stack(&mut self) -> &mut FrameStack<Self::Frame>;
63
64    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
65    fn frame_init(
66        &mut self,
67        frame_input: <Self::Frame as FrameTr>::FrameInit,
68    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<Self::Context>>;
69
70    /// Run the frame from the top of the stack. Returns the frame init or result.
71    ///
72    /// If frame has returned result it would mark it as finished.
73    fn frame_run(
74        &mut self,
75    ) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<Self::Context>>;
76
77    /// Returns the result of the frame to the caller. Frame is popped from the frame stack.
78    /// Consumes the frame result or returns it if there is more frames to run.
79    fn frame_return_result(
80        &mut self,
81        result: <Self::Frame as FrameTr>::FrameResult,
82    ) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>>;
83}
84
85impl<CTX, INSP, I, P> EvmTr for Evm<CTX, INSP, I, P, EthFrame<EthInterpreter>>
86where
87    CTX: ContextTr,
88    I: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
89    P: PrecompileProvider<CTX, Output = InterpreterResult>,
90{
91    type Context = CTX;
92    type Instructions = I;
93    type Precompiles = P;
94    type Frame = EthFrame<EthInterpreter>;
95
96    #[inline]
97    fn ctx(&mut self) -> &mut Self::Context {
98        &mut self.ctx
99    }
100
101    #[inline]
102    fn ctx_ref(&self) -> &Self::Context {
103        &self.ctx
104    }
105
106    #[inline]
107    fn frame_stack(&mut self) -> &mut FrameStack<Self::Frame> {
108        &mut self.frame_stack
109    }
110
111    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
112    #[inline]
113    fn frame_init(
114        &mut self,
115        frame_input: <Self::Frame as FrameTr>::FrameInit,
116    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<CTX>> {
117        let is_first_init = self.frame_stack.index().is_none();
118        let new_frame = if is_first_init {
119            self.frame_stack.start_init()
120        } else {
121            self.frame_stack.get_next()
122        };
123
124        let ctx = &mut self.ctx;
125        let precompiles = &mut self.precompiles;
126        let res = Self::Frame::init_with_context(new_frame, ctx, precompiles, frame_input)?;
127
128        Ok(res.map_frame(|token| {
129            if is_first_init {
130                self.frame_stack.end_init(token);
131            } else {
132                self.frame_stack.push(token);
133            }
134            self.frame_stack.get()
135        }))
136    }
137
138    /// Run the frame from the top of the stack. Returns the frame init or result.
139    #[inline]
140    fn frame_run(&mut self) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<CTX>> {
141        let frame = self.frame_stack.get();
142        let context = &mut self.ctx;
143        let instructions = &mut self.instruction;
144
145        let action = frame
146            .interpreter
147            .run_plain(instructions.instruction_table(), context);
148
149        frame.process_next_action(context, action).inspect(|i| {
150            if i.is_result() {
151                frame.set_finished(true);
152            }
153        })
154    }
155
156    /// Returns the result of the frame to the caller. Frame is popped from the frame stack.
157    #[inline]
158    fn frame_return_result(
159        &mut self,
160        result: <Self::Frame as FrameTr>::FrameResult,
161    ) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>> {
162        if self.frame_stack.get().is_finished() {
163            self.frame_stack.pop();
164        }
165        if self.frame_stack.index().is_none() {
166            return Ok(Some(result));
167        }
168        self.frame_stack
169            .get()
170            .return_result::<_, ContextDbError<Self::Context>>(&mut self.ctx, result)?;
171        Ok(None)
172    }
173
174    #[inline]
175    fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) {
176        (&mut self.ctx, &mut self.instruction)
177    }
178
179    #[inline]
180    fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) {
181        (&mut self.ctx, &mut self.precompiles)
182    }
183}