revm_interpreter/instructions/
stack.rs1use crate::{
2 interpreter_types::{Immediates, InterpreterTypes as ITy, Jumps, RuntimeFlag, StackTr},
3 Host, InstructionContext as Ictx, InstructionExecResult as Result, InstructionResult,
4};
5use primitives::U256;
6
7pub fn pop<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
11 popn!([_i], context.interpreter);
13 Ok(())
14}
15
16pub fn push0<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
20 check!(context.interpreter, SHANGHAI);
21 push!(context.interpreter, U256::ZERO);
22 Ok(())
23}
24
25pub fn push<const N: usize, IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
29 let slice = context.interpreter.bytecode.read_slice(N);
30 if !context.interpreter.stack.push_slice(slice) {
31 return Err(InstructionResult::StackOverflow);
32 }
33
34 context.interpreter.bytecode.relative_jump(N as isize);
35 Ok(())
36}
37
38pub fn dup<const N: usize, IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
42 if !context.interpreter.stack.dup(N) {
43 return Err(InstructionResult::StackOverflow);
44 }
45 Ok(())
46}
47
48pub fn swap<const N: usize, IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
52 assert!(N != 0);
53 if !context.interpreter.stack.exchange(0, N) {
54 return Err(InstructionResult::StackUnderflow);
55 }
56 Ok(())
57}
58
59pub fn dupn<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
63 if !context.host.is_amsterdam_eip8024_enabled() {
64 return Err(InstructionResult::NotActivated);
65 }
66 let x: usize = context.interpreter.bytecode.read_u8().into();
67 if let Some(n) = decode_single(x) {
68 if !context.interpreter.stack.dup(n) {
69 return Err(InstructionResult::StackOverflow);
70 }
71 context.interpreter.bytecode.relative_jump(1);
72 } else {
73 return Err(InstructionResult::InvalidImmediateEncoding);
74 }
75 Ok(())
76}
77
78pub fn swapn<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
82 if !context.host.is_amsterdam_eip8024_enabled() {
83 return Err(InstructionResult::NotActivated);
84 }
85 let x: usize = context.interpreter.bytecode.read_u8().into();
86 if let Some(n) = decode_single(x) {
87 if !context.interpreter.stack.exchange(0, n) {
88 return Err(InstructionResult::StackUnderflow);
89 }
90 context.interpreter.bytecode.relative_jump(1);
91 } else {
92 return Err(InstructionResult::InvalidImmediateEncoding);
93 }
94 Ok(())
95}
96
97pub fn exchange<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
101 if !context.host.is_amsterdam_eip8024_enabled() {
102 return Err(InstructionResult::NotActivated);
103 }
104 let x: usize = context.interpreter.bytecode.read_u8().into();
105 if let Some((n, m)) = decode_pair(x) {
106 if !context.interpreter.stack.exchange(n, m - n) {
107 return Err(InstructionResult::StackUnderflow);
108 }
109 context.interpreter.bytecode.relative_jump(1);
110 } else {
111 return Err(InstructionResult::InvalidImmediateEncoding);
112 }
113 Ok(())
114}
115
116const fn decode_single(x: usize) -> Option<usize> {
117 if x <= 90 || x >= 128 {
118 Some((x + 145) % 256)
119 } else {
120 None
121 }
122}
123
124const fn decode_pair(x: usize) -> Option<(usize, usize)> {
125 if x > 81 && x < 128 {
126 return None;
127 }
128 let k = x ^ 143;
129 let q = k / 16;
130 let r = k % 16;
131 if q < r {
132 Some((q + 1, r + 1))
133 } else {
134 Some((r + 1, 29 - q))
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use crate::{
141 host::DummyHost,
142 instructions::{gas_table, instruction_table},
143 interpreter::{EthInterpreter, ExtBytecode, InputsImpl, SharedMemory},
144 interpreter_types::LoopControl,
145 Interpreter,
146 };
147 use bytecode::opcode::*;
148 use bytecode::Bytecode;
149 use primitives::{hardfork::SpecId, Bytes, U256};
150
151 fn run_bytecode(code: &[u8]) -> Interpreter {
152 let bytecode = Bytecode::new_raw(Bytes::copy_from_slice(code));
153 let mut interpreter = Interpreter::<EthInterpreter>::new(
154 SharedMemory::new(),
155 ExtBytecode::new(bytecode),
156 InputsImpl::default(),
157 false,
158 SpecId::AMSTERDAM,
159 u64::MAX,
160 );
161 let table = instruction_table::<EthInterpreter, DummyHost>();
162 let gas = gas_table();
163 let mut host = DummyHost::new(SpecId::AMSTERDAM);
164 interpreter.run_plain(&table, &gas, &mut host);
165 interpreter
166 }
167
168 #[test]
169 fn test_dupn() {
170 let interpreter = run_bytecode(&[
171 PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
172 DUP1, DUP1, DUP1, DUP1, DUP1, DUPN, 0x80,
173 ]);
174 assert_eq!(interpreter.stack.len(), 18);
175 assert_eq!(interpreter.stack.data()[17], U256::from(1));
176 assert_eq!(interpreter.stack.data()[0], U256::from(1));
177 for i in 1..17 {
178 assert_eq!(interpreter.stack.data()[i], U256::ZERO);
179 }
180 }
181
182 #[test]
183 fn test_swapn() {
184 let interpreter = run_bytecode(&[
185 PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
186 DUP1, DUP1, DUP1, DUP1, DUP1, PUSH1, 0x02, SWAPN, 0x80,
187 ]);
188 assert_eq!(interpreter.stack.len(), 18);
189 assert_eq!(interpreter.stack.data()[17], U256::from(1));
190 assert_eq!(interpreter.stack.data()[0], U256::from(2));
191 for i in 1..17 {
192 assert_eq!(interpreter.stack.data()[i], U256::ZERO);
193 }
194 }
195
196 #[test]
197 fn test_exchange() {
198 let interpreter = run_bytecode(&[PUSH1, 0x00, PUSH1, 0x01, PUSH1, 0x02, EXCHANGE, 0x8E]);
199 assert_eq!(interpreter.stack.len(), 3);
200 assert_eq!(interpreter.stack.data()[2], U256::from(2));
201 assert_eq!(interpreter.stack.data()[1], U256::from(0));
202 assert_eq!(interpreter.stack.data()[0], U256::from(1));
203 }
204
205 #[test]
206 fn test_swapn_invalid_immediate() {
207 let mut interpreter = run_bytecode(&[SWAPN, JUMPDEST]);
208 assert!(interpreter.bytecode.instruction_result().is_none());
209 }
210
211 #[test]
212 fn test_jump_over_invalid_dupn() {
213 let interpreter = run_bytecode(&[PUSH1, 0x04, JUMP, DUPN, JUMPDEST]);
214 assert!(interpreter.bytecode.is_not_end());
215 }
216
217 #[test]
218 fn test_exchange_with_iszero() {
219 let interpreter = run_bytecode(&[
220 PUSH1, 0x00, PUSH1, 0x00, PUSH1, 0x00, EXCHANGE, 0x8E, ISZERO,
221 ]);
222 assert_eq!(interpreter.stack.len(), 3);
223 assert_eq!(interpreter.stack.data()[2], U256::from(1));
224 assert_eq!(interpreter.stack.data()[1], U256::ZERO);
225 assert_eq!(interpreter.stack.data()[0], U256::ZERO);
226 }
227}