rtvm_interpreter/interpreter/
stack.rs

1use crate::{
2    primitives::{B256, U256},
3    InstructionResult,
4};
5use core::fmt;
6use std::vec::Vec;
7
8/// EVM interpreter stack limit.
9pub const STACK_LIMIT: usize = 1024;
10
11/// EVM stack with [STACK_LIMIT] capacity of words.
12#[derive(Debug, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize))]
14pub struct Stack {
15    /// The underlying data of the stack.
16    data: Vec<U256>,
17}
18
19impl fmt::Display for Stack {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.write_str("[")?;
22        for (i, x) in self.data.iter().enumerate() {
23            if i > 0 {
24                f.write_str(", ")?;
25            }
26            write!(f, "{x}")?;
27        }
28        f.write_str("]")
29    }
30}
31
32impl Default for Stack {
33    #[inline]
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl Stack {
40    /// Instantiate a new stack with the [default stack limit][STACK_LIMIT].
41    #[inline]
42    pub fn new() -> Self {
43        Self {
44            // SAFETY: expansion functions assume that capacity is `STACK_LIMIT`.
45            data: Vec::with_capacity(STACK_LIMIT),
46        }
47    }
48
49    /// Returns the length of the stack in words.
50    #[inline]
51    pub fn len(&self) -> usize {
52        self.data.len()
53    }
54
55    /// Returns whether the stack is empty.
56    #[inline]
57    pub fn is_empty(&self) -> bool {
58        self.data.is_empty()
59    }
60
61    /// Returns a reference to the underlying data buffer.
62    #[inline]
63    pub fn data(&self) -> &Vec<U256> {
64        &self.data
65    }
66
67    /// Returns a mutable reference to the underlying data buffer.
68    #[inline]
69    pub fn data_mut(&mut self) -> &mut Vec<U256> {
70        &mut self.data
71    }
72
73    /// Consumes the stack and returns the underlying data buffer.
74    #[inline]
75    pub fn into_data(self) -> Vec<U256> {
76        self.data
77    }
78
79    /// Removes the topmost element from the stack and returns it, or `StackUnderflow` if it is
80    /// empty.
81    #[inline]
82    pub fn pop(&mut self) -> Result<U256, InstructionResult> {
83        self.data.pop().ok_or(InstructionResult::StackUnderflow)
84    }
85
86    /// Removes the topmost element from the stack and returns it.
87    ///
88    /// # Safety
89    ///
90    /// The caller is responsible for checking the length of the stack.
91    #[inline]
92    pub unsafe fn pop_unsafe(&mut self) -> U256 {
93        self.data.pop().unwrap_unchecked()
94    }
95
96    /// Peeks the top of the stack.
97    ///
98    /// # Safety
99    ///
100    /// The caller is responsible for checking the length of the stack.
101    #[inline]
102    pub unsafe fn top_unsafe(&mut self) -> &mut U256 {
103        let len = self.data.len();
104        self.data.get_unchecked_mut(len - 1)
105    }
106
107    /// Pop the topmost value, returning the value and the new topmost value.
108    ///
109    /// # Safety
110    ///
111    /// The caller is responsible for checking the length of the stack.
112    #[inline]
113    pub unsafe fn pop_top_unsafe(&mut self) -> (U256, &mut U256) {
114        let pop = self.pop_unsafe();
115        let top = self.top_unsafe();
116        (pop, top)
117    }
118
119    /// Pops 2 values from the stack.
120    ///
121    /// # Safety
122    ///
123    /// The caller is responsible for checking the length of the stack.
124    #[inline]
125    pub unsafe fn pop2_unsafe(&mut self) -> (U256, U256) {
126        let pop1 = self.pop_unsafe();
127        let pop2 = self.pop_unsafe();
128        (pop1, pop2)
129    }
130
131    /// Pops 2 values from the stack and returns them, in addition to the new topmost value.
132    ///
133    /// # Safety
134    ///
135    /// The caller is responsible for checking the length of the stack.
136    #[inline]
137    pub unsafe fn pop2_top_unsafe(&mut self) -> (U256, U256, &mut U256) {
138        let pop1 = self.pop_unsafe();
139        let pop2 = self.pop_unsafe();
140        let top = self.top_unsafe();
141
142        (pop1, pop2, top)
143    }
144
145    /// Pops 3 values from the stack.
146    ///
147    /// # Safety
148    ///
149    /// The caller is responsible for checking the length of the stack.
150    #[inline]
151    pub unsafe fn pop3_unsafe(&mut self) -> (U256, U256, U256) {
152        let pop1 = self.pop_unsafe();
153        let pop2 = self.pop_unsafe();
154        let pop3 = self.pop_unsafe();
155
156        (pop1, pop2, pop3)
157    }
158
159    /// Pops 4 values from the stack.
160    ///
161    /// # Safety
162    ///
163    /// The caller is responsible for checking the length of the stack.
164    #[inline]
165    pub unsafe fn pop4_unsafe(&mut self) -> (U256, U256, U256, U256) {
166        let pop1 = self.pop_unsafe();
167        let pop2 = self.pop_unsafe();
168        let pop3 = self.pop_unsafe();
169        let pop4 = self.pop_unsafe();
170
171        (pop1, pop2, pop3, pop4)
172    }
173
174    /// Pops 5 values from the stack.
175    ///
176    /// # Safety
177    ///
178    /// The caller is responsible for checking the length of the stack.
179    #[inline]
180    pub unsafe fn pop5_unsafe(&mut self) -> (U256, U256, U256, U256, U256) {
181        let pop1 = self.pop_unsafe();
182        let pop2 = self.pop_unsafe();
183        let pop3 = self.pop_unsafe();
184        let pop4 = self.pop_unsafe();
185        let pop5 = self.pop_unsafe();
186
187        (pop1, pop2, pop3, pop4, pop5)
188    }
189
190    /// Push a new value into the stack. If it will exceed the stack limit,
191    /// returns `StackOverflow` error and leaves the stack unchanged.
192    #[inline]
193    pub fn push_b256(&mut self, value: B256) -> Result<(), InstructionResult> {
194        self.push(value.into())
195    }
196
197    /// Push a new value onto the stack.
198    ///
199    /// If it will exceed the stack limit, returns `StackOverflow` error and leaves the stack
200    /// unchanged.
201    #[inline]
202    pub fn push(&mut self, value: U256) -> Result<(), InstructionResult> {
203        // Allows the compiler to optimize out the `Vec::push` capacity check.
204        assume!(self.data.capacity() == STACK_LIMIT);
205        if self.data.len() == STACK_LIMIT {
206            return Err(InstructionResult::StackOverflow);
207        }
208        self.data.push(value);
209        Ok(())
210    }
211
212    /// Peek a value at given index for the stack, where the top of
213    /// the stack is at index `0`. If the index is too large,
214    /// `StackError::Underflow` is returned.
215    #[inline]
216    pub fn peek(&self, no_from_top: usize) -> Result<U256, InstructionResult> {
217        if self.data.len() > no_from_top {
218            Ok(self.data[self.data.len() - no_from_top - 1])
219        } else {
220            Err(InstructionResult::StackUnderflow)
221        }
222    }
223
224    /// Duplicates the `N`th value from the top of the stack.
225    #[inline]
226    pub fn dup(&mut self, n: usize) -> Result<(), InstructionResult> {
227        let len = self.data.len();
228        if len < n {
229            Err(InstructionResult::StackUnderflow)
230        } else if len + 1 > STACK_LIMIT {
231            Err(InstructionResult::StackOverflow)
232        } else {
233            // SAFETY: check for out of bounds is done above and it makes this safe to do.
234            unsafe {
235                self.data.set_len(len + 1);
236            }
237            self.data[len] = self.data[len - n];
238            Ok(())
239        }
240    }
241
242    /// Swaps the topmost value with the `N`th value from the top.
243    #[inline]
244    pub fn swap(&mut self, n: usize) -> Result<(), InstructionResult> {
245        let len = self.data.len();
246        if n >= len {
247            return Err(InstructionResult::StackUnderflow);
248        }
249        let last_index = len - 1;
250        self.data.swap(last_index, last_index - n);
251        Ok(())
252    }
253
254    /// Exchange two values on the stack. where `N` is first index and second index
255    /// is calculated as N+M
256    #[inline]
257    pub fn exchange(&mut self, n: usize, m: usize) -> Result<(), InstructionResult> {
258        let len = self.data.len();
259        let n_m_index = n + m;
260        if n_m_index >= len {
261            return Err(InstructionResult::StackUnderflow);
262        }
263        let last_index = len - 1;
264        self.data.swap(last_index - n, last_index - n_m_index);
265        Ok(())
266    }
267
268    /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros
269    /// if necessary.
270    #[inline]
271    pub fn push_slice(&mut self, slice: &[u8]) -> Result<(), InstructionResult> {
272        if slice.is_empty() {
273            return Ok(());
274        }
275
276        let n_words = (slice.len() + 31) / 32;
277        let new_len = self.data.len() + n_words;
278        if new_len > STACK_LIMIT {
279            return Err(InstructionResult::StackOverflow);
280        }
281
282        // SAFETY: length checked above.
283        unsafe {
284            let dst = self.data.as_mut_ptr().add(self.data.len()).cast::<u64>();
285            self.data.set_len(new_len);
286
287            let mut i = 0;
288
289            // write full words
290            let words = slice.chunks_exact(32);
291            let partial_last_word = words.remainder();
292            for word in words {
293                // Note: we unroll `U256::from_be_bytes` here to write directly into the buffer,
294                // instead of creating a 32 byte array on the stack and then copying it over.
295                for l in word.rchunks_exact(8) {
296                    dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
297                    i += 1;
298                }
299            }
300
301            if partial_last_word.is_empty() {
302                return Ok(());
303            }
304
305            // write limbs of partial last word
306            let limbs = partial_last_word.rchunks_exact(8);
307            let partial_last_limb = limbs.remainder();
308            for l in limbs {
309                dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
310                i += 1;
311            }
312
313            // write partial last limb by padding with zeros
314            if !partial_last_limb.is_empty() {
315                let mut tmp = [0u8; 8];
316                tmp[8 - partial_last_limb.len()..].copy_from_slice(partial_last_limb);
317                dst.add(i).write(u64::from_be_bytes(tmp));
318                i += 1;
319            }
320
321            debug_assert_eq!((i + 3) / 4, n_words, "wrote too much");
322
323            // zero out upper bytes of last word
324            let m = i % 4; // 32 / 8
325            if m != 0 {
326                dst.add(i).write_bytes(0, 4 - m);
327            }
328        }
329
330        Ok(())
331    }
332
333    /// Set a value at given index for the stack, where the top of the
334    /// stack is at index `0`. If the index is too large,
335    /// `StackError::Underflow` is returned.
336    #[inline]
337    pub fn set(&mut self, no_from_top: usize, val: U256) -> Result<(), InstructionResult> {
338        if self.data.len() > no_from_top {
339            let len = self.data.len();
340            self.data[len - no_from_top - 1] = val;
341            Ok(())
342        } else {
343            Err(InstructionResult::StackUnderflow)
344        }
345    }
346}
347
348#[cfg(feature = "serde")]
349impl<'de> serde::Deserialize<'de> for Stack {
350    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
351    where
352        D: serde::Deserializer<'de>,
353    {
354        let mut data = Vec::<U256>::deserialize(deserializer)?;
355        if data.len() > STACK_LIMIT {
356            return Err(serde::de::Error::custom(std::format!(
357                "stack size exceeds limit: {} > {}",
358                data.len(),
359                STACK_LIMIT
360            )));
361        }
362        data.reserve(STACK_LIMIT - data.len());
363        Ok(Self { data })
364    }
365}
366
367#[cfg(test)]
368mod tests {
369    use super::*;
370
371    fn run(f: impl FnOnce(&mut Stack)) {
372        let mut stack = Stack::new();
373        // fill capacity with non-zero values
374        unsafe {
375            stack.data.set_len(STACK_LIMIT);
376            stack.data.fill(U256::MAX);
377            stack.data.set_len(0);
378        }
379        f(&mut stack);
380    }
381
382    #[test]
383    fn push_slices() {
384        // no-op
385        run(|stack| {
386            stack.push_slice(b"").unwrap();
387            assert_eq!(stack.data, []);
388        });
389
390        // one word
391        run(|stack| {
392            stack.push_slice(&[42]).unwrap();
393            assert_eq!(stack.data, [U256::from(42)]);
394        });
395
396        let n = 0x1111_2222_3333_4444_5555_6666_7777_8888_u128;
397        run(|stack| {
398            stack.push_slice(&n.to_be_bytes()).unwrap();
399            assert_eq!(stack.data, [U256::from(n)]);
400        });
401
402        // more than one word
403        run(|stack| {
404            let b = [U256::from(n).to_be_bytes::<32>(); 2].concat();
405            stack.push_slice(&b).unwrap();
406            assert_eq!(stack.data, [U256::from(n); 2]);
407        });
408
409        run(|stack| {
410            let b = [&[0; 32][..], &[42u8]].concat();
411            stack.push_slice(&b).unwrap();
412            assert_eq!(stack.data, [U256::ZERO, U256::from(42)]);
413        });
414
415        run(|stack| {
416            let b = [&[0; 32][..], &n.to_be_bytes()].concat();
417            stack.push_slice(&b).unwrap();
418            assert_eq!(stack.data, [U256::ZERO, U256::from(n)]);
419        });
420
421        run(|stack| {
422            let b = [&[0; 64][..], &n.to_be_bytes()].concat();
423            stack.push_slice(&b).unwrap();
424            assert_eq!(stack.data, [U256::ZERO, U256::ZERO, U256::from(n)]);
425        });
426    }
427}