evm_interpreter/machine/
stack.rs

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