aurora_evm/core/
mod.rs

1//! Core layer for EVM.
2
3#[cfg(not(feature = "std"))]
4pub mod prelude {
5    pub use alloc::{borrow::Cow, rc::Rc, vec, vec::Vec};
6}
7#[cfg(feature = "std")]
8pub mod prelude {
9    pub use std::{borrow::Cow, rc::Rc, vec::Vec};
10}
11
12mod error;
13mod eval;
14mod external;
15mod memory;
16mod opcode;
17mod stack;
18pub mod utils;
19mod valids;
20
21pub use error::{Capture, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, Trap};
22pub use external::ExternalOperation;
23pub use memory::Memory;
24pub use opcode::Opcode;
25pub use stack::Stack;
26pub use valids::Valids;
27
28use crate::utils::U256_ZERO;
29use core::ops::Range;
30use eval::{eval, Control};
31use prelude::*;
32use primitive_types::{H160, U256};
33use utils::USIZE_MAX;
34
35/// Core execution layer for EVM.
36pub struct Machine {
37    /// Program data.
38    data: Rc<Vec<u8>>,
39    /// Program code.
40    code: Rc<Vec<u8>>,
41    /// Program counter.
42    position: Result<usize, ExitReason>,
43    /// Return value.
44    return_range: Range<U256>,
45    /// Code validity maps.
46    valids: Valids,
47    /// Memory.
48    memory: Memory,
49    /// Stack.
50    stack: Stack,
51}
52
53/// EVM interpreter handler.
54pub trait InterpreterHandler {
55    /// # Errors
56    /// Return `ExitError`
57    fn before_bytecode(
58        &mut self,
59        opcode: Opcode,
60        pc: usize,
61        machine: &Machine,
62        address: &H160,
63    ) -> Result<(), ExitError>;
64
65    // Only invoked for tracing
66    #[cfg(feature = "tracing")]
67    fn after_bytecode(&mut self, result: &Result<(), Capture<ExitReason, Trap>>, machine: &Machine);
68}
69
70impl Machine {
71    /// Reference of machine stack.
72    #[must_use]
73    pub const fn stack(&self) -> &Stack {
74        &self.stack
75    }
76    /// Mutable reference of machine stack.
77    pub const fn stack_mut(&mut self) -> &mut Stack {
78        &mut self.stack
79    }
80    /// Reference of machine memory.
81    #[must_use]
82    pub const fn memory(&self) -> &Memory {
83        &self.memory
84    }
85    /// Mutable reference of machine memory.
86    pub const fn memory_mut(&mut self) -> &mut Memory {
87        &mut self.memory
88    }
89    /// Return a reference of the program counter.
90    pub const fn position(&self) -> &Result<usize, ExitReason> {
91        &self.position
92    }
93
94    /// Create a new machine with given code and data.
95    #[must_use]
96    pub fn new(
97        code: Rc<Vec<u8>>,
98        data: Rc<Vec<u8>>,
99        stack_limit: usize,
100        memory_limit: usize,
101    ) -> Self {
102        let valids = Valids::new(&code[..]);
103
104        Self {
105            data,
106            code,
107            position: Ok(0),
108            return_range: U256_ZERO..U256_ZERO,
109            valids,
110            memory: Memory::new(memory_limit),
111            stack: Stack::new(stack_limit),
112        }
113    }
114
115    /// Explicit exit of the machine. Further step will return error.
116    pub fn exit(&mut self, reason: ExitReason) {
117        self.position = Err(reason);
118    }
119
120    /// Inspect the machine's next opcode and current stack.
121    #[must_use]
122    pub fn inspect(&self) -> Option<(Opcode, &Stack)> {
123        let Ok(position) = self.position else {
124            return None;
125        };
126        self.code.get(position).map(|v| (Opcode(*v), &self.stack))
127    }
128
129    /// Copy and get the return value of the machine, if any.
130    #[must_use]
131    pub fn return_value(&self) -> Vec<u8> {
132        if self.return_range.start > USIZE_MAX {
133            vec![0; (self.return_range.end - self.return_range.start).as_usize()]
134        } else if self.return_range.end > USIZE_MAX {
135            let mut ret = self.memory.get(
136                self.return_range.start.as_usize(),
137                usize::MAX - self.return_range.start.as_usize(),
138            );
139
140            let new_len = (self.return_range.end - self.return_range.start).as_usize();
141            if ret.len() < new_len {
142                ret.resize(new_len, 0);
143            }
144            ret
145        } else {
146            self.memory.get(
147                self.return_range.start.as_usize(),
148                (self.return_range.end - self.return_range.start).as_usize(),
149            )
150        }
151    }
152
153    /// Step the machine, executing until exit or trap.
154    ///
155    /// # Errors
156    /// Return `Capture<ExitReason, Trap>`
157    #[inline]
158    pub fn step<H: InterpreterHandler>(
159        &mut self,
160        handler: &mut H,
161        address: &H160,
162    ) -> Result<(), Capture<ExitReason, Trap>> {
163        let position = *self
164            .position
165            .as_ref()
166            .map_err(|reason| Capture::Exit(reason.clone()))?;
167        match eval(self, position, handler, address) {
168            Control::Exit(e) => {
169                self.position = Err(e.clone());
170                Err(Capture::Exit(e))
171            }
172            Control::Trap(opcode) => Err(Capture::Trap(opcode)),
173            Control::Continue(_) | Control::Jump(_) => Ok(()),
174        }
175    }
176}