revm/
evm.rs

1use crate::{
2    builder::{EvmBuilder, HandlerStage, SetGenericStage},
3    db::{Database, DatabaseCommit, EmptyDB},
4    handler::Handler,
5    interpreter::{
6        CallInputs, CreateInputs, EOFCreateInputs, Host, InterpreterAction, SharedMemory,
7    },
8    primitives::{
9        specification::SpecId, BlockEnv, CfgEnv, EVMError, EVMResult, EnvWithHandlerCfg,
10        ExecutionResult, HandlerCfg, ResultAndState, TxEnv, TxKind, EOF_MAGIC_BYTES,
11    },
12    Context, ContextWithHandlerCfg, Frame, FrameOrResult, FrameResult,
13};
14use core::fmt;
15use std::{boxed::Box, vec::Vec};
16
17/// EVM call stack limit.
18pub const CALL_STACK_LIMIT: u64 = 1024;
19
20/// EVM instance containing both internal EVM context and external context
21/// and the handler that dictates the logic of EVM (or hardfork specification).
22pub struct Evm<'a, EXT, DB: Database> {
23    /// Context of execution, containing both EVM and external context.
24    pub context: Context<EXT, DB>,
25    /// Handler is a component of the of EVM that contains all the logic. Handler contains specification id
26    /// and it different depending on the specified fork.
27    pub handler: Handler<'a, Context<EXT, DB>, EXT, DB>,
28}
29
30impl<EXT, DB> fmt::Debug for Evm<'_, EXT, DB>
31where
32    EXT: fmt::Debug,
33    DB: Database + fmt::Debug,
34    DB::Error: fmt::Debug,
35{
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        f.debug_struct("Evm")
38            .field("evm context", &self.context.evm)
39            .finish_non_exhaustive()
40    }
41}
42
43impl<EXT, DB: Database + DatabaseCommit> Evm<'_, EXT, DB> {
44    /// Commit the changes to the database.
45    pub fn transact_commit(&mut self) -> Result<ExecutionResult, EVMError<DB::Error>> {
46        let ResultAndState { result, state } = self.transact()?;
47        self.context.evm.db.commit(state);
48        Ok(result)
49    }
50}
51
52impl<'a> Evm<'a, (), EmptyDB> {
53    /// Returns evm builder with empty database and empty external context.
54    pub fn builder() -> EvmBuilder<'a, SetGenericStage, (), EmptyDB> {
55        EvmBuilder::default()
56    }
57}
58
59impl<'a, EXT, DB: Database> Evm<'a, EXT, DB> {
60    /// Create new EVM.
61    pub fn new(
62        mut context: Context<EXT, DB>,
63        handler: Handler<'a, Context<EXT, DB>, EXT, DB>,
64    ) -> Evm<'a, EXT, DB> {
65        context.evm.journaled_state.set_spec_id(handler.cfg.spec_id);
66        Evm { context, handler }
67    }
68
69    /// Allow for evm setting to be modified by feeding current evm
70    /// into the builder for modifications.
71    pub fn modify(self) -> EvmBuilder<'a, HandlerStage, EXT, DB> {
72        EvmBuilder::new(self)
73    }
74
75    /// Runs main call loop.
76    #[inline]
77    pub fn run_the_loop(&mut self, first_frame: Frame) -> Result<FrameResult, EVMError<DB::Error>> {
78        let mut call_stack: Vec<Frame> = Vec::with_capacity(1025);
79        call_stack.push(first_frame);
80
81        #[cfg(feature = "memory_limit")]
82        let mut shared_memory =
83            SharedMemory::new_with_memory_limit(self.context.evm.env.cfg.memory_limit);
84        #[cfg(not(feature = "memory_limit"))]
85        let mut shared_memory = SharedMemory::new();
86
87        shared_memory.new_context();
88
89        // Peek the last stack frame.
90        let mut stack_frame = call_stack.last_mut().unwrap();
91
92        loop {
93            // Execute the frame.
94            let next_action =
95                self.handler
96                    .execute_frame(stack_frame, &mut shared_memory, &mut self.context)?;
97
98            // Take error and break the loop, if any.
99            // This error can be set in the Interpreter when it interacts with the context.
100            self.context.evm.take_error()?;
101
102            let exec = &mut self.handler.execution;
103            let frame_or_result = match next_action {
104                InterpreterAction::Call { inputs } => exec.call(&mut self.context, inputs)?,
105                InterpreterAction::Create { inputs } => exec.create(&mut self.context, inputs)?,
106                InterpreterAction::EOFCreate { inputs } => {
107                    exec.eofcreate(&mut self.context, inputs)?
108                }
109                InterpreterAction::Return { result } => {
110                    // free memory context.
111                    shared_memory.free_context();
112
113                    // pop last frame from the stack and consume it to create FrameResult.
114                    let returned_frame = call_stack
115                        .pop()
116                        .expect("We just returned from Interpreter frame");
117
118                    let ctx = &mut self.context;
119                    FrameOrResult::Result(match returned_frame {
120                        Frame::Call(frame) => {
121                            // return_call
122                            FrameResult::Call(exec.call_return(ctx, frame, result)?)
123                        }
124                        Frame::Create(frame) => {
125                            // return_create
126                            FrameResult::Create(exec.create_return(ctx, frame, result)?)
127                        }
128                        Frame::EOFCreate(frame) => {
129                            // return_eofcreate
130                            FrameResult::EOFCreate(exec.eofcreate_return(ctx, frame, result)?)
131                        }
132                    })
133                }
134                InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"),
135            };
136            // handle result
137            match frame_or_result {
138                FrameOrResult::Frame(frame) => {
139                    shared_memory.new_context();
140                    call_stack.push(frame);
141                    stack_frame = call_stack.last_mut().unwrap();
142                }
143                FrameOrResult::Result(result) => {
144                    let Some(top_frame) = call_stack.last_mut() else {
145                        // Break the loop if there are no more frames.
146                        return Ok(result);
147                    };
148                    stack_frame = top_frame;
149                    let ctx = &mut self.context;
150                    // Insert result to the top frame.
151                    match result {
152                        FrameResult::Call(outcome) => {
153                            // return_call
154                            exec.insert_call_outcome(ctx, stack_frame, &mut shared_memory, outcome)?
155                        }
156                        FrameResult::Create(outcome) => {
157                            // return_create
158                            exec.insert_create_outcome(ctx, stack_frame, outcome)?
159                        }
160                        FrameResult::EOFCreate(outcome) => {
161                            // return_eofcreate
162                            exec.insert_eofcreate_outcome(ctx, stack_frame, outcome)?
163                        }
164                    }
165                }
166            }
167        }
168    }
169}
170
171impl<EXT, DB: Database> Evm<'_, EXT, DB> {
172    /// Returns specification (hardfork) that the EVM is instanced with.
173    ///
174    /// SpecId depends on the handler.
175    pub fn spec_id(&self) -> SpecId {
176        self.handler.cfg.spec_id
177    }
178
179    /// Pre verify transaction by checking Environment, initial gas spend and if caller
180    /// has enough balance to pay for the gas.
181    #[inline]
182    pub fn preverify_transaction(&mut self) -> Result<(), EVMError<DB::Error>> {
183        let output = self.preverify_transaction_inner().map(|_| ());
184        self.clear();
185        output
186    }
187
188    /// Calls clear handle of post execution to clear the state for next execution.
189    fn clear(&mut self) {
190        self.handler.post_execution().clear(&mut self.context);
191    }
192
193    /// Transact pre-verified transaction
194    ///
195    /// This function will not validate the transaction.
196    #[inline]
197    pub fn transact_preverified(&mut self) -> EVMResult<DB::Error> {
198        let initial_gas_spend = self
199            .handler
200            .validation()
201            .initial_tx_gas(&self.context.evm.env)
202            .inspect_err(|_e| self.clear())?;
203        let output = self.transact_preverified_inner(initial_gas_spend);
204        let output = self.handler.post_execution().end(&mut self.context, output);
205        self.clear();
206        output
207    }
208
209    /// Pre verify transaction inner.
210    #[inline]
211    fn preverify_transaction_inner(&mut self) -> Result<u64, EVMError<DB::Error>> {
212        self.handler.validation().env(&self.context.evm.env)?;
213        let initial_gas_spend = self
214            .handler
215            .validation()
216            .initial_tx_gas(&self.context.evm.env)?;
217        self.handler
218            .validation()
219            .tx_against_state(&mut self.context)?;
220        Ok(initial_gas_spend)
221    }
222
223    /// Transact transaction
224    ///
225    /// This function will validate the transaction.
226    #[inline]
227    pub fn transact(&mut self) -> EVMResult<DB::Error> {
228        let initial_gas_spend = self
229            .preverify_transaction_inner()
230            .inspect_err(|_e| self.clear())?;
231
232        let output = self.transact_preverified_inner(initial_gas_spend);
233        let output = self.handler.post_execution().end(&mut self.context, output);
234        self.clear();
235        output
236    }
237
238    /// Returns the reference of handler configuration
239    #[inline]
240    pub fn handler_cfg(&self) -> &HandlerCfg {
241        &self.handler.cfg
242    }
243
244    /// Returns the reference of Env configuration
245    #[inline]
246    pub fn cfg(&self) -> &CfgEnv {
247        &self.context.env().cfg
248    }
249
250    /// Returns the mutable reference of Env configuration
251    #[inline]
252    pub fn cfg_mut(&mut self) -> &mut CfgEnv {
253        &mut self.context.evm.env.cfg
254    }
255
256    /// Returns the reference of transaction
257    #[inline]
258    pub fn tx(&self) -> &TxEnv {
259        &self.context.evm.env.tx
260    }
261
262    /// Returns the mutable reference of transaction
263    #[inline]
264    pub fn tx_mut(&mut self) -> &mut TxEnv {
265        &mut self.context.evm.env.tx
266    }
267
268    /// Returns the reference of database
269    #[inline]
270    pub fn db(&self) -> &DB {
271        &self.context.evm.db
272    }
273
274    /// Returns the mutable reference of database
275    #[inline]
276    pub fn db_mut(&mut self) -> &mut DB {
277        &mut self.context.evm.db
278    }
279
280    /// Returns the reference of block
281    #[inline]
282    pub fn block(&self) -> &BlockEnv {
283        &self.context.evm.env.block
284    }
285
286    /// Returns the mutable reference of block
287    #[inline]
288    pub fn block_mut(&mut self) -> &mut BlockEnv {
289        &mut self.context.evm.env.block
290    }
291
292    /// Modify spec id, this will create new EVM that matches this spec id.
293    pub fn modify_spec_id(&mut self, spec_id: SpecId) {
294        self.handler.modify_spec_id(spec_id);
295    }
296
297    /// Returns internal database and external struct.
298    #[inline]
299    pub fn into_context(self) -> Context<EXT, DB> {
300        self.context
301    }
302
303    /// Returns database and [`EnvWithHandlerCfg`].
304    #[inline]
305    pub fn into_db_and_env_with_handler_cfg(self) -> (DB, EnvWithHandlerCfg) {
306        (
307            self.context.evm.inner.db,
308            EnvWithHandlerCfg {
309                env: self.context.evm.inner.env,
310                handler_cfg: self.handler.cfg,
311            },
312        )
313    }
314
315    /// Returns [Context] and [HandlerCfg].
316    #[inline]
317    pub fn into_context_with_handler_cfg(self) -> ContextWithHandlerCfg<EXT, DB> {
318        ContextWithHandlerCfg::new(self.context, self.handler.cfg)
319    }
320
321    /// Transact pre-verified transaction.
322    fn transact_preverified_inner(&mut self, initial_gas_spend: u64) -> EVMResult<DB::Error> {
323        let spec_id = self.spec_id();
324        let ctx = &mut self.context;
325        let pre_exec = self.handler.pre_execution();
326
327        // load access list and beneficiary if needed.
328        pre_exec.load_accounts(ctx)?;
329
330        // load precompiles
331        let precompiles = pre_exec.load_precompiles();
332        ctx.evm.set_precompiles(precompiles);
333
334        // deduce caller balance with its limit.
335        pre_exec.deduct_caller(ctx)?;
336
337        let gas_limit = ctx.evm.env.tx.gas_limit - initial_gas_spend;
338
339        // apply EIP-7702 auth list.
340        let eip7702_gas_refund = pre_exec.apply_eip7702_auth_list(ctx)? as i64;
341
342        let exec = self.handler.execution();
343        // call inner handling of call/create
344        let first_frame_or_result = match ctx.evm.env.tx.transact_to {
345            TxKind::Call(_) => exec.call(
346                ctx,
347                CallInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(),
348            )?,
349            TxKind::Create => {
350                // if first byte of data is magic 0xEF00, then it is EOFCreate.
351                if spec_id.is_enabled_in(SpecId::OSAKA)
352                    && ctx.env().tx.data.starts_with(&EOF_MAGIC_BYTES)
353                {
354                    exec.eofcreate(
355                        ctx,
356                        Box::new(EOFCreateInputs::new_tx(&ctx.evm.env.tx, gas_limit)),
357                    )?
358                } else {
359                    // Safe to unwrap because we are sure that it is create tx.
360                    exec.create(
361                        ctx,
362                        CreateInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(),
363                    )?
364                }
365            }
366        };
367
368        // Starts the main running loop.
369        let mut result = match first_frame_or_result {
370            FrameOrResult::Frame(first_frame) => self.run_the_loop(first_frame)?,
371            FrameOrResult::Result(result) => result,
372        };
373
374        let ctx = &mut self.context;
375
376        // handle output of call/create calls.
377        self.handler
378            .execution()
379            .last_frame_return(ctx, &mut result)?;
380
381        let post_exec = self.handler.post_execution();
382        // calculate final refund and add EIP-7702 refund to gas.
383        post_exec.refund(ctx, result.gas_mut(), eip7702_gas_refund);
384        // Reimburse the caller
385        post_exec.reimburse_caller(ctx, result.gas())?;
386        // Reward beneficiary
387        post_exec.reward_beneficiary(ctx, result.gas())?;
388        // Returns output of transaction.
389        post_exec.output(ctx, result)
390    }
391}
392
393#[cfg(test)]
394mod tests {
395
396    use super::*;
397    use crate::{
398        db::BenchmarkDB,
399        interpreter::opcode::{PUSH1, SSTORE},
400        primitives::{
401            address, Authorization, Bytecode, RecoveredAuthority, RecoveredAuthorization, U256,
402        },
403    };
404
405    #[test]
406    fn sanity_eip7702_tx() {
407        let caller = address!("0000000000000000000000000000000000000001");
408        let delegate = address!("0000000000000000000000000000000000000002");
409        let auth = address!("0000000000000000000000000000000000000100");
410
411        let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
412
413        let mut evm = Evm::builder()
414            .with_spec_id(SpecId::PRAGUE)
415            .with_db(BenchmarkDB::new_bytecode(bytecode).with_target(delegate))
416            .modify_tx_env(|tx| {
417                tx.authorization_list = Some(
418                    vec![RecoveredAuthorization::new_unchecked(
419                        Authorization {
420                            chain_id: 1,
421                            address: delegate,
422                            nonce: 0,
423                        },
424                        RecoveredAuthority::Valid(auth),
425                    )]
426                    .into(),
427                );
428                tx.caller = caller;
429                tx.transact_to = TxKind::Call(auth);
430            })
431            .build();
432
433        let ok = evm.transact().unwrap();
434
435        let auth_acc = ok.state.get(&auth).unwrap();
436        assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(delegate)));
437        assert_eq!(auth_acc.info.nonce, 1);
438        assert_eq!(
439            auth_acc.storage.get(&U256::from(1)).unwrap().present_value,
440            U256::from(1)
441        );
442    }
443}