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