evm_interpreter/machine/
stack.rs

1use alloc::vec::Vec;
2
3use primitive_types::U256;
4
5use crate::error::{ExitError, ExitException};
6
7/// EVM stack.
8#[derive(Clone, Debug)]
9pub struct Stack {
10	data: Vec<U256>,
11	limit: usize,
12}
13
14macro_rules! impl_perform_popn_pushn {
15	(
16		$name:ident,
17		$pop_len:expr,
18		$push_len:expr,
19		($($peek_pop:expr),*),
20		($($peek_push:expr),*),
21		$pop_pushn_f:ident
22	) => {
23		/// Pop $pop_len values from the stack, and then push $push_len values
24		/// into the stack.
25		///
26		/// If `f` returns error, then the stack will not be changed.
27		#[allow(unused_parens)]
28		pub fn $name<R, F>(&mut self, f: F) -> Result<R, ExitError> where
29			F: FnOnce(
30				$(impl_perform_popn_pushn!(INTERNAL_TYPE_RU256, $peek_pop)),*
31			) -> Result<(($(impl_perform_popn_pushn!(INTERNAL_TYPE_U256, $peek_push)),*), R), ExitError>
32		{
33			match self.check_pop_push($pop_len, $push_len) {
34				Ok(()) => (),
35				Err(e) => return Err(e.into()),
36			}
37
38			let (p, ret) = match f($(self.unchecked_peek($peek_pop)),*) {
39				Ok(p1) => p1,
40				Err(e) => return Err(e.into()),
41			};
42			self.$pop_pushn_f($pop_len, p);
43
44			Ok(ret)
45		}
46	};
47	(INTERNAL_TYPE_RU256, $e:expr) => { &U256 };
48	(INTERNAL_TYPE_U256, $e:expr) => { U256 };
49}
50
51impl Stack {
52	/// Create a new stack with given limit.
53	#[must_use]
54	pub const fn new(limit: usize) -> Self {
55		Self {
56			data: Vec::new(),
57			limit,
58		}
59	}
60
61	/// Stack limit.
62	#[inline]
63	#[must_use]
64	pub const fn limit(&self) -> usize {
65		self.limit
66	}
67
68	/// Stack length.
69	#[inline]
70	#[must_use]
71	pub fn len(&self) -> usize {
72		self.data.len()
73	}
74
75	/// Whether the stack is empty.
76	#[inline]
77	#[must_use]
78	pub fn is_empty(&self) -> bool {
79		self.data.is_empty()
80	}
81
82	/// Stack data.
83	#[inline]
84	#[must_use]
85	pub const fn data(&self) -> &Vec<U256> {
86		&self.data
87	}
88
89	/// Clear the stack.
90	pub fn clear(&mut self) {
91		self.data.clear();
92	}
93
94	/// Pop a value from the stack.
95	/// If the stack is already empty, returns the `StackUnderflow` error.
96	#[inline]
97	pub fn pop(&mut self) -> Result<U256, ExitException> {
98		self.data.pop().ok_or(ExitException::StackUnderflow)
99	}
100
101	/// Push a new value into the stack.
102	/// If it exceeds the stack limit, returns `StackOverflow` error and
103	/// leaves the stack unchanged.
104	#[inline]
105	pub fn push(&mut self, value: U256) -> Result<(), ExitException> {
106		if self.data.len() + 1 > self.limit {
107			return Err(ExitException::StackOverflow);
108		}
109		self.data.push(value);
110		Ok(())
111	}
112
113	/// Check whether it's possible to pop and push enough items in the stack.
114	pub fn check_pop_push(&self, pop: usize, push: usize) -> Result<(), ExitException> {
115		if self.data.len() < pop {
116			return Err(ExitException::StackUnderflow);
117		}
118		if self.data.len() - pop + push > self.limit {
119			return Err(ExitException::StackOverflow);
120		}
121		Ok(())
122	}
123
124	fn unchecked_peek(&self, no_from_top: usize) -> &U256 {
125		&self.data[self.data.len() - no_from_top - 1]
126	}
127
128	fn unchecked_pop_push1(&mut self, pop: usize, p1: U256) {
129		for _ in 0..pop {
130			self.data.pop();
131		}
132		self.data.push(p1);
133	}
134
135	fn unchecked_pop_push0(&mut self, pop: usize, _p1: ()) {
136		for _ in 0..pop {
137			self.data.pop();
138		}
139	}
140
141	/// Peek a value at given index for the stack, where the top of
142	/// the stack is at index `0`. If the index is too large,
143	/// `StackError::Underflow` is returned.
144	#[inline]
145	pub fn peek(&self, no_from_top: usize) -> Result<U256, ExitException> {
146		if self.data.len() > no_from_top {
147			Ok(self.data[self.data.len() - no_from_top - 1])
148		} else {
149			Err(ExitException::StackUnderflow)
150		}
151	}
152
153	/// Set a value at given index for the stack, where the top of the
154	/// stack is at index `0`. If the index is too large,
155	/// `StackError::Underflow` is returned.
156	#[inline]
157	pub fn set(&mut self, no_from_top: usize, val: U256) -> Result<(), ExitException> {
158		if self.data.len() > no_from_top {
159			let len = self.data.len();
160			self.data[len - no_from_top - 1] = val;
161			Ok(())
162		} else {
163			Err(ExitException::StackUnderflow)
164		}
165	}
166
167	impl_perform_popn_pushn!(perform_pop0_push1, 0, 1, (), (0), unchecked_pop_push1);
168	impl_perform_popn_pushn!(perform_pop1_push0, 1, 0, (0), (), unchecked_pop_push0);
169	impl_perform_popn_pushn!(perform_pop1_push1, 1, 1, (0), (0), unchecked_pop_push1);
170	impl_perform_popn_pushn!(perform_pop2_push1, 2, 1, (0, 1), (0), unchecked_pop_push1);
171	impl_perform_popn_pushn!(perform_pop3_push0, 3, 0, (0, 1, 2), (), unchecked_pop_push0);
172	impl_perform_popn_pushn!(
173		perform_pop4_push0,
174		4,
175		0,
176		(0, 1, 2, 3),
177		(),
178		unchecked_pop_push0
179	);
180	impl_perform_popn_pushn!(
181		perform_pop6_push0,
182		6,
183		0,
184		(0, 1, 2, 3, 4, 5),
185		(),
186		unchecked_pop_push0
187	);
188	impl_perform_popn_pushn!(
189		perform_pop7_push0,
190		7,
191		0,
192		(0, 1, 2, 3, 4, 5, 6),
193		(),
194		unchecked_pop_push0
195	);
196}