Skip to main content

example_my_evm/
evm.rs

1use crate::frame::MyFrame;
2use revm::{
3    context::{ContextSetters, ContextTr, FrameStack, OutFrame},
4    handler::{
5        evm::{ContextDbError, FrameInitResult, FrameTr},
6        instructions::{EthInstructions, InstructionProvider},
7        EthFrame, EthPrecompiles, EvmTr, FrameInitOrResult,
8    },
9    inspector::{InspectorEvmTr, JournalExt},
10    interpreter::interpreter::EthInterpreter,
11    primitives::hardfork::SpecId,
12    Inspector,
13};
14
15/// MyEvm variant of the EVM.
16///
17/// Implements [`EvmTr`] manually as the stock implementation is only provided
18/// for `Evm` parameterized with [`EthFrame`]. Frame handling is delegated to
19/// the [`EthFrame`] wrapped inside [`MyFrame`].
20#[derive(Debug)]
21pub struct MyEvm<CTX, INSP> {
22    /// [`ContextTr`] of the EVM, it is used to fetch data from database.
23    pub ctx: CTX,
24    /// Inspector of the EVM it is used to inspect the EVM.
25    /// Its trait are defined in revm-inspector crate.
26    pub inspector: INSP,
27    /// Instructions provider of the EVM it is used to execute instructions.
28    /// `InstructionProvider` trait is defined in revm-handler crate.
29    pub instruction: EthInstructions<EthInterpreter, CTX>,
30    /// Precompile provider of the EVM it is used to execute precompiles.
31    /// `PrecompileProvider` trait is defined in revm-handler crate.
32    pub precompiles: EthPrecompiles,
33    /// The custom frame stack that is going to be executed.
34    pub frame_stack: FrameStack<MyFrame>,
35}
36
37impl<CTX: ContextTr, INSP> MyEvm<CTX, INSP> {
38    /// Creates a new instance of MyEvm with the provided context and inspector.
39    pub fn new(ctx: CTX, inspector: INSP) -> Self {
40        Self {
41            ctx,
42            inspector,
43            instruction: EthInstructions::new_mainnet_with_spec(SpecId::default()),
44            precompiles: EthPrecompiles::new(SpecId::default()),
45            frame_stack: FrameStack::new(),
46        }
47    }
48}
49
50impl<CTX: ContextTr, INSP> EvmTr for MyEvm<CTX, INSP> {
51    type Context = CTX;
52    type Instructions = EthInstructions<EthInterpreter, CTX>;
53    type Precompiles = EthPrecompiles;
54    type Frame = MyFrame;
55
56    #[inline]
57    fn all(
58        &self,
59    ) -> (
60        &Self::Context,
61        &Self::Instructions,
62        &Self::Precompiles,
63        &FrameStack<Self::Frame>,
64    ) {
65        (
66            &self.ctx,
67            &self.instruction,
68            &self.precompiles,
69            &self.frame_stack,
70        )
71    }
72
73    #[inline]
74    fn all_mut(
75        &mut self,
76    ) -> (
77        &mut Self::Context,
78        &mut Self::Instructions,
79        &mut Self::Precompiles,
80        &mut FrameStack<Self::Frame>,
81    ) {
82        (
83            &mut self.ctx,
84            &mut self.instruction,
85            &mut self.precompiles,
86            &mut self.frame_stack,
87        )
88    }
89
90    /// Initializes the frame for the given frame input. Frame is pushed to the frame stack.
91    #[inline]
92    fn frame_init(
93        &mut self,
94        frame_input: <Self::Frame as FrameTr>::FrameInit,
95    ) -> Result<FrameInitResult<'_, Self::Frame>, ContextDbError<CTX>> {
96        let is_first_init = self.frame_stack.index().is_none();
97        let mut new_frame = if is_first_init {
98            self.frame_stack.start_init()
99        } else {
100            self.frame_stack.get_next()
101        };
102
103        // Materialize the custom frame and initialize the wrapped EthFrame in place.
104        // `invalid()` must stay allocation-free as an early result overwrites it without drop.
105        let frame = new_frame.get(MyFrame::invalid);
106        let res = EthFrame::init_with_context(
107            OutFrame::new_init(&mut frame.eth_frame),
108            &mut self.ctx,
109            &mut self.precompiles,
110            frame_input,
111        )?;
112        let token = new_frame.consume();
113
114        Ok(res.map_item(|_inner_token| {
115            if is_first_init {
116                unsafe { self.frame_stack.end_init(token) };
117            } else {
118                unsafe { self.frame_stack.push(token) };
119            }
120            self.frame_stack.get()
121        }))
122    }
123
124    /// Run the frame from the top of the stack. Returns the frame init or result.
125    ///
126    /// If frame has returned result it would mark it as finished.
127    #[inline]
128    fn frame_run(&mut self) -> Result<FrameInitOrResult<Self::Frame>, ContextDbError<CTX>> {
129        let frame = self.frame_stack.get();
130        let context = &mut self.ctx;
131        let instructions = &mut self.instruction;
132
133        let action = frame.eth_frame.interpreter.run_plain(
134            instructions.instruction_table(),
135            instructions.gas_table(),
136            context,
137        );
138
139        frame
140            .eth_frame
141            .process_next_action(context, action)
142            .inspect(|i| {
143                if i.is_result() {
144                    frame.eth_frame.set_finished(true);
145                }
146            })
147    }
148
149    /// Returns the result of the frame to the caller. Frame is popped from the frame stack.
150    /// Consumes the frame result or returns it if there is more frames to run.
151    #[inline]
152    fn frame_return_result(
153        &mut self,
154        result: <Self::Frame as FrameTr>::FrameResult,
155    ) -> Result<Option<<Self::Frame as FrameTr>::FrameResult>, ContextDbError<Self::Context>> {
156        if self.frame_stack.get().is_finished() {
157            self.frame_stack.pop();
158        }
159        if self.frame_stack.index().is_none() {
160            return Ok(Some(result));
161        }
162        self.frame_stack
163            .get()
164            .eth_frame
165            .return_result::<_, ContextDbError<Self::Context>>(&mut self.ctx, result)?;
166        Ok(None)
167    }
168}
169
170impl<CTX: ContextTr, INSP> InspectorEvmTr for MyEvm<CTX, INSP>
171where
172    CTX: ContextSetters<Journal: JournalExt>,
173    INSP: Inspector<CTX, EthInterpreter>,
174{
175    type Inspector = INSP;
176
177    fn all_inspector(
178        &self,
179    ) -> (
180        &Self::Context,
181        &Self::Instructions,
182        &Self::Precompiles,
183        &FrameStack<Self::Frame>,
184        &Self::Inspector,
185    ) {
186        (
187            &self.ctx,
188            &self.instruction,
189            &self.precompiles,
190            &self.frame_stack,
191            &self.inspector,
192        )
193    }
194
195    fn all_mut_inspector(
196        &mut self,
197    ) -> (
198        &mut Self::Context,
199        &mut Self::Instructions,
200        &mut Self::Precompiles,
201        &mut FrameStack<Self::Frame>,
202        &mut Self::Inspector,
203    ) {
204        (
205            &mut self.ctx,
206            &mut self.instruction,
207            &mut self.precompiles,
208            &mut self.frame_stack,
209            &mut self.inspector,
210        )
211    }
212}