aurora_evm/core/
stack.rs

1use crate::prelude::Vec;
2use crate::utils::USIZE_MAX;
3use crate::ExitError;
4use primitive_types::{H256, U256};
5
6/// EVM stack.
7#[derive(Clone, Debug)]
8pub struct Stack {
9    data: Vec<U256>,
10    limit: usize,
11}
12
13impl Stack {
14    /// Create a new stack with given limit.
15    #[must_use]
16    pub const fn new(limit: usize) -> Self {
17        Self {
18            data: Vec::new(),
19            limit,
20        }
21    }
22
23    /// Stack limit.
24    #[inline]
25    #[must_use]
26    pub const fn limit(&self) -> usize {
27        self.limit
28    }
29
30    /// Stack length.
31    #[inline]
32    #[must_use]
33    pub fn len(&self) -> usize {
34        self.data.len()
35    }
36
37    /// Whether the stack is empty.
38    #[inline]
39    #[must_use]
40    pub fn is_empty(&self) -> bool {
41        self.data.is_empty()
42    }
43
44    /// Stack data.
45    #[inline]
46    #[must_use]
47    pub const fn data(&self) -> &Vec<U256> {
48        &self.data
49    }
50
51    /// Pop a value from the stack. If the stack is already empty, returns the
52    /// `StackUnderflow` error.
53    ///
54    /// # Errors
55    /// Return `ExitError`
56    #[inline]
57    pub fn pop(&mut self) -> Result<U256, ExitError> {
58        self.data.pop().ok_or(ExitError::StackUnderflow)
59    }
60
61    /// # Errors
62    /// Return `ExitError`
63    #[inline]
64    pub fn pop_h256(&mut self) -> Result<H256, ExitError> {
65        self.pop().map(|it| H256(it.to_big_endian()))
66    }
67
68    /// Push a new value into the stack. If it will exceed the stack limit,
69    /// returns `StackOverflow` error and leaves the stack unchanged.
70    ///
71    /// # Errors
72    /// Return `ExitError`
73    #[inline]
74    pub fn push(&mut self, value: U256) -> Result<(), ExitError> {
75        if self.data.len() + 1 > self.limit {
76            return Err(ExitError::StackOverflow);
77        }
78        self.data.push(value);
79        Ok(())
80    }
81
82    /// Peek a value at given index for the stack, where the top of
83    /// the stack is at index `0`. If the index is too large,
84    /// `StackError::Underflow` is returned.
85    ///
86    /// # Errors
87    /// Return `ExitError`
88    #[inline]
89    pub fn peek(&self, no_from_top: usize) -> Result<U256, ExitError> {
90        if self.data.len() > no_from_top {
91            Ok(self.data[self.data.len() - no_from_top - 1])
92        } else {
93            Err(ExitError::StackUnderflow)
94        }
95    }
96
97    #[inline]
98    /// Peek a value at given index for the stack, where the top of
99    /// the stack is at index `0`. If the index is too large,
100    /// `StackError::Underflow` is returned.
101    ///
102    /// # Errors
103    /// Return `ExitError`
104    pub fn peek_h256(&self, no_from_top: usize) -> Result<H256, ExitError> {
105        self.peek(no_from_top).map(|it| H256(it.to_big_endian()))
106    }
107
108    /// Peek a value at given index for the stack as usize.
109    ///
110    /// If the value is larger than `usize::MAX`, `OutOfGas` error is returned.
111    ///
112    /// # Errors
113    /// Return `ExitError`
114    #[inline]
115    pub fn peek_usize(&self, no_from_top: usize) -> Result<usize, ExitError> {
116        let u = self.peek(no_from_top)?;
117        if u > USIZE_MAX {
118            return Err(ExitError::OutOfGas);
119        }
120        Ok(u.as_usize())
121    }
122
123    /// Set a value at given index for the stack, where the top of the
124    /// stack is at index `0`. If the index is too large,
125    /// `StackError::Underflow` is returned.
126    ///
127    /// # Errors
128    /// Return `ExitError`
129    #[inline]
130    pub fn set(&mut self, no_from_top: usize, val: U256) -> Result<(), ExitError> {
131        if self.data.len() > no_from_top {
132            let len = self.data.len();
133            self.data[len - no_from_top - 1] = val;
134            Ok(())
135        } else {
136            Err(ExitError::StackUnderflow)
137        }
138    }
139}