revm_interpreter/instructions/
stack.rs1use 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 popn!([_i], context.interpreter);
15}
16
17pub 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 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}