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    // TODO: rust-v1.87 - const fn
34    #[allow(clippy::missing_const_for_fn)]
35    pub fn len(&self) -> usize {
36        self.data.len()
37    }
38
39    /// Whether the stack is empty.
40    #[inline]
41    #[must_use]
42    // TODO: rust-v1.87 - const fn
43    #[allow(clippy::missing_const_for_fn)]
44    pub fn is_empty(&self) -> bool {
45        self.data.is_empty()
46    }
47
48    /// Stack data.
49    #[inline]
50    #[must_use]
51    pub const fn data(&self) -> &Vec<U256> {
52        &self.data
53    }
54
55    /// Pop a value from the stack. If the stack is already empty, returns the
56    /// `StackUnderflow` error.
57    ///
58    /// # Errors
59    /// Return `ExitError`
60    #[inline]
61    pub fn pop(&mut self) -> Result<U256, ExitError> {
62        self.data.pop().ok_or(ExitError::StackUnderflow)
63    }
64
65    /// # Errors
66    /// Return `ExitError`
67    #[inline]
68    pub fn pop_h256(&mut self) -> Result<H256, ExitError> {
69        self.pop().map(|it| H256(it.to_big_endian()))
70    }
71
72    /// Push a new value into the stack. If it will exceed the stack limit,
73    /// returns `StackOverflow` error and leaves the stack unchanged.
74    ///
75    /// # Errors
76    /// Return `ExitError`
77    #[inline]
78    pub fn push(&mut self, value: U256) -> Result<(), ExitError> {
79        if self.data.len() + 1 > self.limit {
80            return Err(ExitError::StackOverflow);
81        }
82        self.data.push(value);
83        Ok(())
84    }
85
86    /// Peek a value at given index for the stack, where the top of
87    /// the stack is at index `0`. If the index is too large,
88    /// `StackError::Underflow` is returned.
89    ///
90    /// # Errors
91    /// Return `ExitError`
92    #[inline]
93    pub fn peek(&self, no_from_top: usize) -> Result<U256, ExitError> {
94        if self.data.len() > no_from_top {
95            Ok(self.data[self.data.len() - no_from_top - 1])
96        } else {
97            Err(ExitError::StackUnderflow)
98        }
99    }
100
101    #[inline]
102    /// Peek a value at given index for the stack, where the top of
103    /// the stack is at index `0`. If the index is too large,
104    /// `StackError::Underflow` is returned.
105    ///
106    /// # Errors
107    /// Return `ExitError`
108    pub fn peek_h256(&self, no_from_top: usize) -> Result<H256, ExitError> {
109        self.peek(no_from_top).map(|it| H256(it.to_big_endian()))
110    }
111
112    /// Peek a value at given index for the stack as usize.
113    ///
114    /// If the value is larger than `usize::MAX`, `OutOfGas` error is returned.
115    ///
116    /// # Errors
117    /// Return `ExitError`
118    #[inline]
119    pub fn peek_usize(&self, no_from_top: usize) -> Result<usize, ExitError> {
120        let u = self.peek(no_from_top)?;
121        if u > USIZE_MAX {
122            return Err(ExitError::OutOfGas);
123        }
124        Ok(u.as_usize())
125    }
126
127    /// Set a value at given index for the stack, where the top of the
128    /// stack is at index `0`. If the index is too large,
129    /// `StackError::Underflow` is returned.
130    ///
131    /// # Errors
132    /// Return `ExitError`
133    #[inline]
134    pub fn set(&mut self, no_from_top: usize, val: U256) -> Result<(), ExitError> {
135        if self.data.len() > no_from_top {
136            let len = self.data.len();
137            self.data[len - no_from_top - 1] = val;
138            Ok(())
139        } else {
140            Err(ExitError::StackUnderflow)
141        }
142    }
143}