revm_interpreter/instructions/
stack.rs
1use crate::{
2 gas,
3 primitives::{Spec, U256},
4 Host, Interpreter,
5};
6
7pub fn pop<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
8 gas!(interpreter, gas::BASE);
9 if let Err(result) = interpreter.stack.pop() {
10 interpreter.instruction_result = result;
11 }
12}
13
14pub fn push0<H: Host + ?Sized, SPEC: Spec>(interpreter: &mut Interpreter, _host: &mut H) {
18 check!(interpreter, SHANGHAI);
19 gas!(interpreter, gas::BASE);
20 if let Err(result) = interpreter.stack.push(U256::ZERO) {
21 interpreter.instruction_result = result;
22 }
23}
24
25pub fn push<const N: usize, H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
26 gas!(interpreter, gas::VERYLOW);
27 let ip = interpreter.instruction_pointer;
30 if let Err(result) = interpreter
31 .stack
32 .push_slice(unsafe { core::slice::from_raw_parts(ip, N) })
33 {
34 interpreter.instruction_result = result;
35 return;
36 }
37 interpreter.instruction_pointer = unsafe { ip.add(N) };
38}
39
40pub fn dup<const N: usize, H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
41 gas!(interpreter, gas::VERYLOW);
42 if let Err(result) = interpreter.stack.dup(N) {
43 interpreter.instruction_result = result;
44 }
45}
46
47pub fn swap<const N: usize, H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
48 gas!(interpreter, gas::VERYLOW);
49 if let Err(result) = interpreter.stack.swap(N) {
50 interpreter.instruction_result = result;
51 }
52}
53
54pub fn dupn<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
55 require_eof!(interpreter);
56 gas!(interpreter, gas::VERYLOW);
57 let imm = unsafe { *interpreter.instruction_pointer };
58 if let Err(result) = interpreter.stack.dup(imm as usize + 1) {
59 interpreter.instruction_result = result;
60 }
61 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) };
62}
63
64pub fn swapn<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
65 require_eof!(interpreter);
66 gas!(interpreter, gas::VERYLOW);
67 let imm = unsafe { *interpreter.instruction_pointer };
68 if let Err(result) = interpreter.stack.swap(imm as usize + 1) {
69 interpreter.instruction_result = result;
70 }
71 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) };
72}
73
74pub fn exchange<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
75 require_eof!(interpreter);
76 gas!(interpreter, gas::VERYLOW);
77 let imm = unsafe { *interpreter.instruction_pointer };
78 let n = (imm >> 4) + 1;
79 let m = (imm & 0x0F) + 1;
80 if let Err(result) = interpreter.stack.exchange(n as usize, m as usize) {
81 interpreter.instruction_result = result;
82 }
83
84 interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.offset(1) };
85}
86
87#[cfg(test)]
88mod test {
89 use super::*;
90 use crate::{
91 opcode::{make_instruction_table, DUPN, EXCHANGE, SWAPN},
92 primitives::{Bytecode, Bytes, PragueSpec},
93 DummyHost, Gas, InstructionResult,
94 };
95
96 #[test]
97 fn dupn() {
98 let table = make_instruction_table::<_, PragueSpec>();
99 let mut host = DummyHost::default();
100 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([
101 DUPN, 0x00, DUPN, 0x01, DUPN, 0x02,
102 ])));
103 interp.is_eof = true;
104 interp.gas = Gas::new(10000);
105
106 interp.stack.push(U256::from(10)).unwrap();
107 interp.stack.push(U256::from(20)).unwrap();
108 interp.step(&table, &mut host);
109 assert_eq!(interp.stack.pop(), Ok(U256::from(20)));
110 interp.step(&table, &mut host);
111 assert_eq!(interp.stack.pop(), Ok(U256::from(10)));
112 interp.step(&table, &mut host);
113 assert_eq!(interp.instruction_result, InstructionResult::StackUnderflow);
114 }
115
116 #[test]
117 fn swapn() {
118 let table = make_instruction_table::<_, PragueSpec>();
119 let mut host = DummyHost::default();
120 let mut interp =
121 Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([SWAPN, 0x00, SWAPN, 0x01])));
122 interp.is_eof = true;
123 interp.gas = Gas::new(10000);
124
125 interp.stack.push(U256::from(10)).unwrap();
126 interp.stack.push(U256::from(20)).unwrap();
127 interp.stack.push(U256::from(0)).unwrap();
128 interp.step(&table, &mut host);
129 assert_eq!(interp.stack.peek(0), Ok(U256::from(20)));
130 assert_eq!(interp.stack.peek(1), Ok(U256::from(0)));
131 interp.step(&table, &mut host);
132 assert_eq!(interp.stack.peek(0), Ok(U256::from(10)));
133 assert_eq!(interp.stack.peek(2), Ok(U256::from(20)));
134 }
135
136 #[test]
137 fn exchange() {
138 let table = make_instruction_table::<_, PragueSpec>();
139 let mut host = DummyHost::default();
140 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(Bytes::from([
141 EXCHANGE, 0x00, EXCHANGE, 0x11,
142 ])));
143 interp.is_eof = true;
144 interp.gas = Gas::new(10000);
145
146 interp.stack.push(U256::from(1)).unwrap();
147 interp.stack.push(U256::from(5)).unwrap();
148 interp.stack.push(U256::from(10)).unwrap();
149 interp.stack.push(U256::from(15)).unwrap();
150 interp.stack.push(U256::from(0)).unwrap();
151
152 interp.step(&table, &mut host);
153 assert_eq!(interp.stack.peek(1), Ok(U256::from(10)));
154 assert_eq!(interp.stack.peek(2), Ok(U256::from(15)));
155 interp.step(&table, &mut host);
156 assert_eq!(interp.stack.peek(2), Ok(U256::from(1)));
157 assert_eq!(interp.stack.peek(4), Ok(U256::from(15)));
158 }
159}