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::StackOverflow);
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::StackOverflow);
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::StackOverflow);
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 {
119 Some(x + 17)
120 } else if x >= 128 {
121 Some(x - 20)
122 } else {
123 None
124 }
125}
126
127fn decode_pair(x: usize) -> Option<(usize, usize)> {
128 let k = if x <= 79 {
129 x
130 } else if x >= 128 {
131 x - 48
132 } else {
133 return None;
134 };
135 let q = k / 16;
136 let r = k % 16;
137 if q < r {
138 Some((q + 1, r + 1))
139 } else {
140 Some((r + 1, 29 - q))
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::{
147 host::DummyHost,
148 instructions::instruction_table,
149 interpreter::{EthInterpreter, ExtBytecode, InputsImpl, SharedMemory},
150 interpreter_types::LoopControl,
151 Interpreter,
152 };
153 use bytecode::opcode::*;
154 use bytecode::Bytecode;
155 use primitives::{hardfork::SpecId, Bytes, U256};
156
157 fn run_bytecode(code: &[u8]) -> Interpreter {
158 let bytecode = Bytecode::new_raw(Bytes::copy_from_slice(code));
159 let mut interpreter = Interpreter::<EthInterpreter>::new(
160 SharedMemory::new(),
161 ExtBytecode::new(bytecode),
162 InputsImpl::default(),
163 false,
164 SpecId::AMSTERDAM,
165 u64::MAX,
166 );
167 let table = instruction_table::<EthInterpreter, DummyHost>();
168 let mut host = DummyHost::new(SpecId::AMSTERDAM);
169 interpreter.run_plain(&table, &mut host);
170 interpreter
171 }
172
173 #[test]
174 fn test_dupn() {
175 let interpreter = run_bytecode(&[
176 PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
177 DUP1, DUP1, DUP1, DUP1, DUP1, DUPN, 0x00,
178 ]);
179 assert_eq!(interpreter.stack.len(), 18);
180 assert_eq!(interpreter.stack.data()[17], U256::from(1));
181 assert_eq!(interpreter.stack.data()[0], U256::from(1));
182 for i in 1..17 {
183 assert_eq!(interpreter.stack.data()[i], U256::ZERO);
184 }
185 }
186
187 #[test]
188 fn test_swapn() {
189 let interpreter = run_bytecode(&[
190 PUSH1, 0x01, PUSH1, 0x00, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1, DUP1,
191 DUP1, DUP1, DUP1, DUP1, DUP1, PUSH1, 0x02, SWAPN, 0x00,
192 ]);
193 assert_eq!(interpreter.stack.len(), 18);
194 assert_eq!(interpreter.stack.data()[17], U256::from(1));
195 assert_eq!(interpreter.stack.data()[0], U256::from(2));
196 for i in 1..17 {
197 assert_eq!(interpreter.stack.data()[i], U256::ZERO);
198 }
199 }
200
201 #[test]
202 fn test_exchange() {
203 let interpreter = run_bytecode(&[PUSH1, 0x00, PUSH1, 0x01, PUSH1, 0x02, EXCHANGE, 0x01]);
204 assert_eq!(interpreter.stack.len(), 3);
205 assert_eq!(interpreter.stack.data()[2], U256::from(2));
206 assert_eq!(interpreter.stack.data()[1], U256::from(0));
207 assert_eq!(interpreter.stack.data()[0], U256::from(1));
208 }
209
210 #[test]
211 fn test_swapn_invalid_immediate() {
212 let mut interpreter = run_bytecode(&[SWAPN, JUMPDEST]);
213 assert!(interpreter.bytecode.instruction_result().is_none());
214 }
215
216 #[test]
217 fn test_jump_over_invalid_dupn() {
218 let interpreter = run_bytecode(&[PUSH1, 0x04, JUMP, DUPN, JUMPDEST]);
219 assert!(interpreter.bytecode.is_not_end());
220 }
221
222 #[test]
223 fn test_exchange_with_iszero() {
224 let interpreter = run_bytecode(&[
225 PUSH1, 0x00, PUSH1, 0x00, PUSH1, 0x00, EXCHANGE, 0x01, ISZERO,
226 ]);
227 assert_eq!(interpreter.stack.len(), 3);
228 assert_eq!(interpreter.stack.data()[2], U256::from(1));
229 assert_eq!(interpreter.stack.data()[1], U256::ZERO);
230 assert_eq!(interpreter.stack.data()[0], U256::ZERO);
231 }
232}