revm_interpreter/instructions/stack.rs
1use crate::{
2 gas,
3 instructions::utility::cast_slice_to_u256,
4 interpreter::Interpreter,
5 interpreter_types::{Immediates, InterpreterTypes, Jumps, LoopControl, RuntimeFlag, StackTr},
6 Host,
7};
8use primitives::U256;
9
10pub fn pop<WIRE: InterpreterTypes, H: Host + ?Sized>(
11 interpreter: &mut Interpreter<WIRE>,
12 _host: &mut H,
13) {
14 gas!(interpreter, gas::BASE);
15 // Can ignore return. as relative N jump is safe operation.
16 popn!([_i], interpreter);
17}
18
19/// EIP-3855: PUSH0 instruction
20///
21/// Introduce a new instruction which pushes the constant value 0 onto the stack.
22pub fn push0<WIRE: InterpreterTypes, H: Host + ?Sized>(
23 interpreter: &mut Interpreter<WIRE>,
24 _host: &mut H,
25) {
26 check!(interpreter, SHANGHAI);
27 gas!(interpreter, gas::BASE);
28 push!(interpreter, U256::ZERO);
29}
30
31pub fn push<const N: usize, WIRE: InterpreterTypes, H: Host + ?Sized>(
32 interpreter: &mut Interpreter<WIRE>,
33 _host: &mut H,
34) {
35 gas!(interpreter, gas::VERYLOW);
36 push!(interpreter, U256::ZERO);
37 popn_top!([], top, interpreter);
38
39 let imm = interpreter.bytecode.read_slice(N);
40 cast_slice_to_u256(imm, top);
41
42 // Can ignore return. as relative N jump is safe operation
43 interpreter.bytecode.relative_jump(N as isize);
44}
45
46pub fn dup<const N: usize, WIRE: InterpreterTypes, H: Host + ?Sized>(
47 interpreter: &mut Interpreter<WIRE>,
48 _host: &mut H,
49) {
50 gas!(interpreter, gas::VERYLOW);
51 if !interpreter.stack.dup(N) {
52 interpreter
53 .control
54 .set_instruction_result(crate::InstructionResult::StackOverflow);
55 }
56}
57
58pub fn swap<const N: usize, WIRE: InterpreterTypes, H: Host + ?Sized>(
59 interpreter: &mut Interpreter<WIRE>,
60 _host: &mut H,
61) {
62 gas!(interpreter, gas::VERYLOW);
63 assert!(N != 0);
64 if !interpreter.stack.exchange(0, N) {
65 interpreter
66 .control
67 .set_instruction_result(crate::InstructionResult::StackOverflow);
68 }
69}
70
71pub fn dupn<WIRE: InterpreterTypes, H: Host + ?Sized>(
72 interpreter: &mut Interpreter<WIRE>,
73 _host: &mut H,
74) {
75 require_eof!(interpreter);
76 gas!(interpreter, gas::VERYLOW);
77 let imm = interpreter.bytecode.read_u8();
78 if !interpreter.stack.dup(imm as usize + 1) {
79 interpreter
80 .control
81 .set_instruction_result(crate::InstructionResult::StackOverflow);
82 }
83 interpreter.bytecode.relative_jump(1);
84}
85
86pub fn swapn<WIRE: InterpreterTypes, H: Host + ?Sized>(
87 interpreter: &mut Interpreter<WIRE>,
88 _host: &mut H,
89) {
90 require_eof!(interpreter);
91 gas!(interpreter, gas::VERYLOW);
92 let imm = interpreter.bytecode.read_u8();
93 if !interpreter.stack.exchange(0, imm as usize + 1) {
94 interpreter
95 .control
96 .set_instruction_result(crate::InstructionResult::StackOverflow);
97 }
98 interpreter.bytecode.relative_jump(1);
99}
100
101pub fn exchange<WIRE: InterpreterTypes, H: Host + ?Sized>(
102 interpreter: &mut Interpreter<WIRE>,
103 _host: &mut H,
104) {
105 require_eof!(interpreter);
106 gas!(interpreter, gas::VERYLOW);
107 let imm = interpreter.bytecode.read_u8();
108 let n = (imm >> 4) + 1;
109 let m = (imm & 0x0F) + 1;
110 if !interpreter.stack.exchange(n as usize, m as usize) {
111 interpreter
112 .control
113 .set_instruction_result(crate::InstructionResult::StackOverflow);
114 }
115 interpreter.bytecode.relative_jump(1);
116}
117
118// TODO : Tests
119/*
120#[cfg(test)]
121mod test {
122
123 use super::*;
124 use crate::{table::make_instruction_table, DummyHost, Gas, InstructionResult};
125 use bytecode::opcode::{DUPN, EXCHANGE, SWAPN};
126 use bytecode::Bytecode;
127 use specification::hardfork::SpecId;
128 use context_interface::DefaultEthereumWiring;
129
130 #[test]
131 fn dupn() {
132 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
133 let mut host = DummyHost::default();
134 let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
135 [DUPN, 0x00, DUPN, 0x01, DUPN, 0x02].into(),
136 ));
137 interp.is_eof = true;
138 interp.spec_id = SpecId::PRAGUE;
139 interp.gas = Gas::new(10000);
140
141 interp.stack.push(U256::from(10)).unwrap();
142 interp.stack.push(U256::from(20)).unwrap();
143 interp.step(&table, &mut host);
144 assert_eq!(interp.stack.pop(), Ok(U256::from(20)));
145 interp.step(&table, &mut host);
146 assert_eq!(interp.stack.pop(), Ok(U256::from(10)));
147 interp.step(&table, &mut host);
148 assert_eq!(interp.instruction_result, InstructionResult::StackUnderflow);
149 }
150
151 #[test]
152 fn swapn() {
153 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
154 let mut host = DummyHost::default();
155 let mut interp =
156 Interpreter::new_bytecode(Bytecode::LegacyRaw([SWAPN, 0x00, SWAPN, 0x01].into()));
157 interp.is_eof = true;
158 interp.gas = Gas::new(10000);
159 interp.spec_id = SpecId::PRAGUE;
160
161 interp.stack.push(U256::from(10)).unwrap();
162 interp.stack.push(U256::from(20)).unwrap();
163 interp.stack.push(U256::from(0)).unwrap();
164 interp.step(&table, &mut host);
165 assert_eq!(interp.stack.peek(0), Ok(U256::from(20)));
166 assert_eq!(interp.stack.peek(1), Ok(U256::from(0)));
167 interp.step(&table, &mut host);
168 assert_eq!(interp.stack.peek(0), Ok(U256::from(10)));
169 assert_eq!(interp.stack.peek(2), Ok(U256::from(20)));
170 }
171
172 #[test]
173 fn exchange() {
174 let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
175 let mut host = DummyHost::default();
176 let mut interp =
177 Interpreter::new_bytecode(Bytecode::LegacyRaw([EXCHANGE, 0x00, EXCHANGE, 0x11].into()));
178 interp.is_eof = true;
179 interp.gas = Gas::new(10000);
180 interp.spec_id = SpecId::PRAGUE;
181
182 interp.stack.push(U256::from(1)).unwrap();
183 interp.stack.push(U256::from(5)).unwrap();
184 interp.stack.push(U256::from(10)).unwrap();
185 interp.stack.push(U256::from(15)).unwrap();
186 interp.stack.push(U256::from(0)).unwrap();
187
188 interp.step(&table, &mut host);
189 assert_eq!(interp.stack.peek(1), Ok(U256::from(10)));
190 assert_eq!(interp.stack.peek(2), Ok(U256::from(15)));
191 interp.step(&table, &mut host);
192 assert_eq!(interp.stack.peek(2), Ok(U256::from(1)));
193 assert_eq!(interp.stack.peek(4), Ok(U256::from(15)));
194 }
195}
196*/