revm_interpreter/instructions/
stack.rs

1use crate::{
2    gas,
3    instructions::utility::cast_slice_to_u256,
4    interpreter_types::{Immediates, InterpreterTypes, Jumps, RuntimeFlag, StackTr},
5    InstructionResult,
6};
7use primitives::U256;
8
9use crate::InstructionContext;
10
11pub fn pop<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
12    gas!(context.interpreter, gas::BASE);
13    // Can ignore return. as relative N jump is safe operation.
14    popn!([_i], context.interpreter);
15}
16
17/// EIP-3855: PUSH0 instruction
18///
19/// Introduce a new instruction which pushes the constant value 0 onto the stack.
20pub fn push0<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
21    check!(context.interpreter, SHANGHAI);
22    gas!(context.interpreter, gas::BASE);
23    push!(context.interpreter, U256::ZERO);
24}
25
26pub fn push<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
27    context: InstructionContext<'_, H, WIRE>,
28) {
29    gas!(context.interpreter, gas::VERYLOW);
30    push!(context.interpreter, U256::ZERO);
31    popn_top!([], top, context.interpreter);
32
33    let imm = context.interpreter.bytecode.read_slice(N);
34    cast_slice_to_u256(imm, top);
35
36    // Can ignore return. as relative N jump is safe operation
37    context.interpreter.bytecode.relative_jump(N as isize);
38}
39
40pub fn dup<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
41    context: InstructionContext<'_, H, WIRE>,
42) {
43    gas!(context.interpreter, gas::VERYLOW);
44    if !context.interpreter.stack.dup(N) {
45        context.interpreter.halt(InstructionResult::StackOverflow);
46    }
47}
48
49pub fn swap<const N: usize, WIRE: InterpreterTypes, H: ?Sized>(
50    context: InstructionContext<'_, H, WIRE>,
51) {
52    gas!(context.interpreter, gas::VERYLOW);
53    assert!(N != 0);
54    if !context.interpreter.stack.exchange(0, N) {
55        context.interpreter.halt(InstructionResult::StackOverflow);
56    }
57}
58
59pub fn dupn<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
60    require_eof!(context.interpreter);
61    gas!(context.interpreter, gas::VERYLOW);
62    let imm = context.interpreter.bytecode.read_u8();
63    if !context.interpreter.stack.dup(imm as usize + 1) {
64        context.interpreter.halt(InstructionResult::StackOverflow);
65    }
66    context.interpreter.bytecode.relative_jump(1);
67}
68
69pub fn swapn<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
70    require_eof!(context.interpreter);
71    gas!(context.interpreter, gas::VERYLOW);
72    let imm = context.interpreter.bytecode.read_u8();
73    if !context.interpreter.stack.exchange(0, imm as usize + 1) {
74        context.interpreter.halt(InstructionResult::StackOverflow);
75    }
76    context.interpreter.bytecode.relative_jump(1);
77}
78
79pub fn exchange<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
80    require_eof!(context.interpreter);
81    gas!(context.interpreter, gas::VERYLOW);
82    let imm = context.interpreter.bytecode.read_u8();
83    let n = (imm >> 4) + 1;
84    let m = (imm & 0x0F) + 1;
85    if !context.interpreter.stack.exchange(n as usize, m as usize) {
86        context.interpreter.halt(InstructionResult::StackOverflow);
87    }
88    context.interpreter.bytecode.relative_jump(1);
89}
90
91#[cfg(test)]
92mod test {
93    use crate::{instruction_table, InstructionResult, Interpreter, InterpreterAction};
94    use bytecode::opcode::{DUPN, EXCHANGE, STOP, SWAPN};
95    use bytecode::Bytecode;
96    use primitives::{Bytes, U256};
97
98    #[test]
99    fn dupn() {
100        let bytecode = Bytecode::new_raw(Bytes::from(&[DUPN, 0x00, DUPN, 0x01, DUPN, 0x02, STOP]));
101        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
102
103        let table = instruction_table();
104
105        interpreter.runtime_flag.is_eof = true;
106        let _ = interpreter.stack.push(U256::from(10));
107        let _ = interpreter.stack.push(U256::from(20));
108
109        interpreter.step_dummy(&table);
110        assert_eq!(interpreter.stack.pop(), Ok(U256::from(20)));
111        interpreter.step_dummy(&table);
112        assert_eq!(interpreter.stack.pop(), Ok(U256::from(10)));
113        interpreter.step_dummy(&table);
114        let gas = interpreter.gas;
115        assert_eq!(
116            interpreter.take_next_action(),
117            InterpreterAction::new_halt(InstructionResult::StackOverflow, gas)
118        );
119    }
120
121    #[test]
122    fn swapn() {
123        let bytecode = Bytecode::new_raw(Bytes::from(&[SWAPN, 0x00, SWAPN, 0x01, STOP]));
124        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
125
126        let table = instruction_table();
127        interpreter.runtime_flag.is_eof = true;
128
129        let _ = interpreter.stack.push(U256::from(10));
130        let _ = interpreter.stack.push(U256::from(20));
131        let _ = interpreter.stack.push(U256::from(0));
132
133        interpreter.step_dummy(&table);
134        assert_eq!(interpreter.stack.peek(0), Ok(U256::from(20)));
135        assert_eq!(interpreter.stack.peek(1), Ok(U256::from(0)));
136        interpreter.step_dummy(&table);
137        assert_eq!(interpreter.stack.peek(0), Ok(U256::from(10)));
138        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(20)));
139    }
140
141    #[test]
142    fn exchange() {
143        let bytecode = Bytecode::new_raw(Bytes::from(&[EXCHANGE, 0x00, EXCHANGE, 0x11, STOP]));
144        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
145
146        let table = instruction_table();
147        interpreter.runtime_flag.is_eof = true;
148
149        let _ = interpreter.stack.push(U256::from(1));
150        let _ = interpreter.stack.push(U256::from(5));
151        let _ = interpreter.stack.push(U256::from(10));
152        let _ = interpreter.stack.push(U256::from(15));
153        let _ = interpreter.stack.push(U256::from(0));
154
155        interpreter.step_dummy(&table);
156        assert_eq!(interpreter.stack.peek(1), Ok(U256::from(10)));
157        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(15)));
158        interpreter.step_dummy(&table);
159        assert_eq!(interpreter.stack.peek(2), Ok(U256::from(1)));
160        assert_eq!(interpreter.stack.peek(4), Ok(U256::from(15)));
161    }
162}