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#[cfg(test)]
119mod test {
120
121    use super::*;
122    use crate::{host::DummyHost, instruction_table, InstructionResult};
123    use bytecode::opcode::{DUPN, EXCHANGE, STOP, SWAPN};
124    use bytecode::Bytecode;
125    use primitives::{Bytes, U256};
126
127    #[test]
128    fn dupn() {
129        let bytecode = Bytecode::new_raw(Bytes::from(&[DUPN, 0x00, DUPN, 0x01, DUPN, 0x02, STOP]));
130        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
131
132        let table = instruction_table();
133        let mut host = DummyHost;
134
135        interpreter.runtime_flag.is_eof = true;
136        let _ = interpreter.stack.push(U256::from(10));
137        let _ = interpreter.stack.push(U256::from(20));
138        interpreter.step(&table, &mut host);
139        assert_eq!(interpreter.stack.pop(), Ok(U256::from(20)));
140        interpreter.step(&table, &mut host);
141        assert_eq!(interpreter.stack.pop(), Ok(U256::from(10)));
142        interpreter.step(&table, &mut host);
143        assert_eq!(
144            interpreter.control.instruction_result,
145            InstructionResult::StackOverflow
146        );
147    }
148
149    #[test]
150    fn swapn() {
151        let bytecode = Bytecode::new_raw(Bytes::from(&[SWAPN, 0x00, SWAPN, 0x01, STOP]));
152        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
153
154        let table = instruction_table();
155        let mut host = DummyHost;
156        interpreter.runtime_flag.is_eof = true;
157
158        let _ = interpreter.stack.push(U256::from(10));
159        let _ = interpreter.stack.push(U256::from(20));
160        let _ = interpreter.stack.push(U256::from(0));
161        interpreter.step(&table, &mut host);
162        assert_eq!(interpreter.stack.peek(0), Ok(U256::from(20)));
163        assert_eq!(interpreter.stack.peek(1), Ok(U256::from(0)));
164        interpreter.step(&table, &mut host);
165        assert_eq!(interpreter.stack.peek(0), Ok(U256::from(10)));
166        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(20)));
167    }
168
169    #[test]
170    fn exchange() {
171        let bytecode = Bytecode::new_raw(Bytes::from(&[EXCHANGE, 0x00, EXCHANGE, 0x11, STOP]));
172        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
173
174        let table = instruction_table();
175        let mut host = DummyHost;
176        interpreter.runtime_flag.is_eof = true;
177
178        let _ = interpreter.stack.push(U256::from(1));
179        let _ = interpreter.stack.push(U256::from(5));
180        let _ = interpreter.stack.push(U256::from(10));
181        let _ = interpreter.stack.push(U256::from(15));
182        let _ = interpreter.stack.push(U256::from(0));
183
184        interpreter.step(&table, &mut host);
185        assert_eq!(interpreter.stack.peek(1), Ok(U256::from(10)));
186        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(15)));
187        interpreter.step(&table, &mut host);
188        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(1)));
189        assert_eq!(interpreter.stack.peek(4), Ok(U256::from(15)));
190    }
191}