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*/