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
14/// EIP-3855: PUSH0 instruction
15///
16/// Introduce a new instruction which pushes the constant value 0 onto the stack.
17pub 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    // SAFETY: In analysis we append trailing bytes to the bytecode so that this is safe to do
28    // without bounds checking.
29    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}