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}