revm_interpreter/instructions/
stack.rs1use crate::{
2 interpreter_types::{Immediates, InterpreterTypes, Jumps, RuntimeFlag, StackTr},
3 InstructionResult,
4};
5use primitives::U256;
6
7use crate::InstructionContext;
8
9pub fn pop<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
13 popn!([_i], context.interpreter);
15}
16
17pub fn push0<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
21 check!(context.interpreter, SHANGHAI);
22 push!(context.interpreter, U256::ZERO);
23}
24
25pub fn push<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
29 context: InstructionContext<'_, H, WIRE>,
30) {
31 let slice = context.interpreter.bytecode.read_slice(N);
32 if !context.interpreter.stack.push_slice(slice) {
33 context.interpreter.halt(InstructionResult::StackOverflow);
34 return;
35 }
36
37 context.interpreter.bytecode.relative_jump(N as isize);
38}
39
40pub fn dup<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
44 context: InstructionContext<'_, H, WIRE>,
45) {
46 if !context.interpreter.stack.dup(N) {
47 context.interpreter.halt(InstructionResult::StackOverflow);
48 }
49}
50
51pub fn swap<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
55 context: InstructionContext<'_, H, WIRE>,
56) {
57 assert!(N != 0);
58 if !context.interpreter.stack.exchange(0, N) {
59 context.interpreter.halt(InstructionResult::StackUnderflow);
60 }
61}
62
63pub fn dupn<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
67 check!(context.interpreter, AMSTERDAM);
68 let x: usize = context.interpreter.bytecode.read_u8().into();
69 if let Some(n) = decode_single(x) {
70 if !context.interpreter.stack.dup(n) {
71 context.interpreter.halt(InstructionResult::StackOverflow);
72 }
73 context.interpreter.bytecode.relative_jump(1);
74 } else {
75 context
76 .interpreter
77 .halt(InstructionResult::InvalidImmediateEncoding);
78 }
79}
80
81pub fn swapn<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
85 check!(context.interpreter, AMSTERDAM);
86 let x: usize = context.interpreter.bytecode.read_u8().into();
87 if let Some(n) = decode_single(x) {
88 if !context.interpreter.stack.exchange(0, n) {
89 context.interpreter.halt(InstructionResult::StackUnderflow);
90 }
91 context.interpreter.bytecode.relative_jump(1);
92 } else {
93 context
94 .interpreter
95 .halt(InstructionResult::InvalidImmediateEncoding);
96 }
97}
98
99pub fn exchange<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
103 check!(context.interpreter, AMSTERDAM);
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 context.interpreter.halt(InstructionResult::StackUnderflow);
108 }
109 context.interpreter.bytecode.relative_jump(1);
110 } else {
111 context
112 .interpreter
113 .halt(InstructionResult::InvalidImmediateEncoding);
114 }
115}
116
117fn decode_single(x: usize) -> Option<usize> {
118 if x <= 90 || x >= 128 {
119 Some((x + 145) % 256)
120 } else {
121 None
122 }
123}
124
125fn decode_pair(x: usize) -> Option<(usize, usize)> {
126 if x > 81 && x < 128 {
127 return None;
128 }
129 let k = x ^ 143;
130 let q = k / 16;
131 let r = k % 16;
132 if q < r {
133 Some((q + 1, r + 1))
134 } else {
135 Some((r + 1, 29 - q))
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::{
142 host::DummyHost,
143 instructions::instruction_table,
144 interpreter::{EthInterpreter, ExtBytecode, InputsImpl, SharedMemory},
145 interpreter_types::LoopControl,
146 Interpreter,
147 };
148 use bytecode::opcode::*;
149 use bytecode::Bytecode;
150 use primitives::{hardfork::SpecId, Bytes, U256};
151
152 fn run_bytecode(code: &[u8]) -> Interpreter {
153 let bytecode = Bytecode::new_raw(Bytes::copy_from_slice(code));
154 let mut interpreter = Interpreter::<EthInterpreter>::new(
155 SharedMemory::new(),
156 ExtBytecode::new(bytecode),
157 InputsImpl::default(),
158 false,
159 SpecId::AMSTERDAM,
160 u64::MAX,
161 );
162 let table = instruction_table::<EthInterpreter, DummyHost>();
163 let mut host = DummyHost::new(SpecId::AMSTERDAM);
164 interpreter.run_plain(&table, &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}