evm_rs_emulator/core_module/
stack.rs

1use super::utils::errors::ExecutionError;
2
3/// A stack data structure used in the Ethereum Virtual Machine (EVM) to store and manipulate data.
4#[derive(Debug)]
5pub struct Stack {
6    /// The stack itself
7    pub stack: Vec<[u8; 32]>,
8}
9
10/// Implements a stack data structure for the EVM emulator.
11impl Stack {
12    /// Creates a new stack instance.
13    pub fn new() -> Self {
14        Self { stack: vec![] }
15    }
16
17    /// Pushes a 32-byte word onto the stack.
18    ///
19    /// # Arguments
20    ///
21    /// * `word` - A 32-byte array representing the word to be pushed onto the stack.
22    ///
23    /// # Errors
24    ///
25    /// Returns an `ExecutionError` if the stack is too deep (i.e., has more than 1024 elements).
26    pub fn push(&mut self, word: [u8; 32]) -> Result<(), ExecutionError> {
27        // Check if the stack is too deep
28        if self.stack.len() >= 1024 {
29            // Return an error
30            return Err(ExecutionError::StackTooDeep);
31        }
32
33        Ok(self.stack.push(word))
34    }
35
36    /// Pop a word off the stack
37    ///
38    /// # Errors
39    ///
40    /// Returns an `ExecutionError` if the stack is empty.
41    pub fn pop(&mut self) -> Result<[u8; 32], ExecutionError> {
42        // Check if the stack is empty
43        if self.stack.is_empty() {
44            // Return an error
45            return Err(ExecutionError::StackTooSmall);
46        }
47
48        Ok(self.stack.pop().unwrap())
49    }
50
51    /// Duplicate a word on the stack
52    ///
53    /// # Arguments
54    ///
55    /// * `index` - The index of the word to duplicate, counting from the top of the stack
56    ///
57    /// # Errors
58    ///
59    /// Returns an `ExecutionError` if the stack is too small to perform the operation
60    ///
61    /// # Returns
62    ///
63    /// Returns the duplicated word if successful
64    pub fn dup(&mut self, index: usize) -> Result<[u8; 32], ExecutionError> {
65        // Check if the stack is long enough
66        if self.stack.len() < index {
67            return Err(ExecutionError::StackTooSmall);
68        }
69
70        let word = self.stack[self.stack.len() - index];
71        self.stack.push(word);
72
73        Ok(word)
74    }
75
76    /// Swaps the word at the top of the stack with the word at the specified index.
77    ///
78    /// # Arguments
79    ///
80    /// * `index` - The index of the word to swap with the top of the stack.
81    ///
82    /// # Errors
83    ///
84    /// Returns an `ExecutionError::StackTooSmall` error if the stack is not long enough to perform the swap.
85    ///
86    /// # Returns
87    ///
88    /// Returns an array containing the two swapped words.
89    pub fn swap(&mut self, index: usize) -> Result<[[u8; 32]; 2], ExecutionError> {
90        // Check if the stack is long enough
91        if self.stack.len() < index {
92            return Err(ExecutionError::StackTooSmall);
93        }
94
95        let len = self.stack.len();
96
97        let word1 = self.stack[len - 1];
98        let word2 = self.stack[len - 1 - index];
99
100        self.stack[len - 1] = word2;
101        self.stack[len - 1 - index] = word1;
102
103        Ok([word1, word2])
104    }
105}
106
107/// Implements the `Clone` trait for the `Stack` struct.
108impl Clone for Stack {
109    /// Returns a new instance of `Stack` with the same elements as `self`.
110    fn clone(&self) -> Self {
111        Self {
112            stack: self.stack.clone(),
113        }
114    }
115}