Skip to main content

yevm_core/ops/
stack.rs

1use crate::{
2    Call, Int,
3    evm::{Context, Evm, EvmResult, EvmYield, HaltReason},
4    state::State,
5};
6
7#[inline]
8pub fn push(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
9    let op = evm.code[evm.pc];
10    let len = match op {
11        0x60..=0x7F => op as usize - 0x5F, // PUSH1=1 .. PUSH32=32
12        _ => 0,                            // PUSH0
13    };
14    if len == 0 {
15        evm.gas_charge(2)?;
16        evm.push(Int::ZERO)?;
17    } else {
18        evm.gas_charge(3)?;
19        let lo = evm.pc + 1;
20        let available = len.min(evm.code.len().saturating_sub(lo));
21        let mut buf = [0u8; 32];
22        let dst = 32 - len;
23        buf[dst..dst + available].copy_from_slice(&evm.code[lo..lo + available]);
24        evm.push(Int::from(&buf[..]))?;
25        evm.pc += len;
26    }
27    Ok(())
28}
29
30#[inline]
31pub fn dup(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
32    evm.gas_charge(3)?;
33    let op = evm.code[evm.pc];
34    let n = idx(op) - 1;
35    let Some(int) = evm.stack.iter().rev().nth(n).copied() else {
36        return Err(EvmYield::Halt(HaltReason::StackUnderflow));
37    };
38    evm.push(int)?;
39    Ok(())
40}
41
42pub fn swap(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
43    evm.gas_charge(3)?;
44    let op = evm.code[evm.pc];
45    let n = idx(op); // SWAP{k}: swap top with (k+1)th, distance = k = idx(op)
46    if evm.stack.len() <= n {
47        return Err(EvmYield::Halt(HaltReason::StackUnderflow));
48    }
49    let i = evm.stack.len() - 1;
50    let j = i - n;
51    evm.stack.swap(i, j);
52    Ok(())
53}
54
55fn idx(op: u8) -> usize {
56    match op {
57        0x60..0x80 => op as usize - 0x60 + 1, // PUSH{1..32}
58        0x80..0x90 => op as usize - 0x80 + 1, // DUP{1..16}
59        0x90..0xA0 => op as usize - 0x90 + 1, // SWAP{1..16}
60        _ => 0,
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::super::tests::{call, ctx, state};
67    use super::*;
68    use crate::call::Head;
69    use crate::{
70        Int,
71        evm::{Evm, HaltReason},
72    };
73
74    fn int(val: u64) -> Int {
75        Int::from(val)
76    }
77
78    fn is_halt(result: EvmResult<()>, expected: HaltReason) -> bool {
79        match (result, expected) {
80            (Err(EvmYield::Halt(HaltReason::StackUnderflow)), HaltReason::StackUnderflow) => true,
81            (Err(EvmYield::Halt(HaltReason::BadOpcode(a))), HaltReason::BadOpcode(b)) => a == b,
82            _ => false,
83        }
84    }
85
86    // --- PUSH ---
87
88    #[test]
89    fn test_push0() {
90        let head = Head::default();
91        let mut evm = Evm::new(head, vec![0x5F], 1000, Int::ONE, Int::ONE, vec![]); // PUSH0
92        push(&mut evm, &ctx(), &call(), &mut state()).unwrap();
93        evm.apply(&mut state());
94        assert_eq!(evm.stack, vec![Int::ZERO]);
95        assert_eq!(evm.pc, 0);
96    }
97
98    #[test]
99    fn test_push1() {
100        let head = Head::default();
101        let mut evm = Evm::new(head, vec![0x60, 0x42], 1000, Int::ONE, Int::ONE, vec![]); // PUSH1 0x42
102        push(&mut evm, &ctx(), &call(), &mut state()).unwrap();
103        evm.apply(&mut state());
104        assert_eq!(evm.stack, vec![int(0x42)]);
105        assert_eq!(evm.pc, 1);
106    }
107
108    #[test]
109    fn test_push2() {
110        let head = Head::default();
111        let mut evm = Evm::new(
112            head,
113            vec![0x61, 0x01, 0x02],
114            1000,
115            Int::ONE,
116            Int::ONE,
117            vec![],
118        ); // PUSH2 0x0102
119        push(&mut evm, &ctx(), &call(), &mut state()).unwrap();
120        evm.apply(&mut state());
121        assert_eq!(evm.stack, vec![int(0x0102)]);
122        assert_eq!(evm.pc, 2);
123    }
124
125    #[test]
126    fn test_push32() {
127        let mut code = vec![0x7F]; // PUSH32
128        code.extend(1u8..=32);
129        let head = Head::default();
130        let mut evm = Evm::new(head, code, 1000, Int::ONE, Int::ONE, vec![]);
131        push(&mut evm, &ctx(), &call(), &mut state()).unwrap();
132        evm.apply(&mut state());
133        assert_eq!(evm.stack.len(), 1);
134        assert_eq!(evm.pc, 32);
135        let expected: Vec<u8> = (1u8..=32).collect();
136        assert_eq!(evm.stack[0], Int::from(expected.as_slice()));
137    }
138
139    #[test]
140    fn test_push_truncated() {
141        let head = Head::default();
142        let mut evm = Evm::new(head, vec![0x61, 0xFF], 1000, Int::ONE, Int::ONE, vec![]);
143        push(&mut evm, &ctx(), &call(), &mut state()).unwrap();
144        evm.apply(&mut state());
145        assert_eq!(evm.stack.len(), 1);
146        assert_eq!(evm.pc, 2);
147        assert_eq!(evm.stack[0], Int::from(0xFF00));
148    }
149
150    // --- DUP ---
151
152    #[test]
153    fn test_dup1() {
154        let a = int(1);
155        let head = Head::default();
156        let mut evm = Evm::new(head, vec![0x80], 1000, Int::ONE, Int::ONE, vec![]); // DUP1
157        evm.stack.push(a);
158        dup(&mut evm, &ctx(), &call(), &mut state()).unwrap();
159        evm.apply(&mut state());
160        assert_eq!(evm.stack, vec![a, a]);
161        assert_eq!(evm.pc, 0);
162    }
163
164    #[test]
165    fn test_dup2() {
166        let (a, b) = (int(1), int(2));
167        let head = Head::default();
168        let mut evm = Evm::new(head, vec![0x81], 1000, Int::ONE, Int::ONE, vec![]); // DUP2
169        evm.stack.extend([a, b]);
170        dup(&mut evm, &ctx(), &call(), &mut state()).unwrap();
171        evm.apply(&mut state());
172        assert_eq!(evm.stack, vec![a, b, a]); // copies 2nd from top (a)
173        assert_eq!(evm.pc, 0);
174    }
175
176    #[test]
177    fn test_dup16() {
178        let vals: Vec<Int> = (1..=16).map(int).collect();
179        let head = Head::default();
180        let mut evm = Evm::new(head, vec![0x8F], 1000, Int::ONE, Int::ONE, vec![]); // DUP16
181        evm.stack.extend(vals.iter().copied());
182        dup(&mut evm, &ctx(), &call(), &mut state()).unwrap();
183        evm.apply(&mut state());
184        assert_eq!(evm.stack.len(), 17);
185        assert_eq!(*evm.stack.last().unwrap(), int(1)); // copies bottom (16th from top)
186    }
187
188    #[test]
189    fn test_dup_underflow() {
190        let head = Head::default();
191        let mut evm = Evm::new(head, vec![0x81], 1000, Int::ONE, Int::ONE, vec![]); // DUP2, but only 1 item on stack
192        evm.stack.push(int(1));
193        let result = dup(&mut evm, &ctx(), &call(), &mut state());
194        assert!(is_halt(result, HaltReason::StackUnderflow));
195    }
196
197    #[test]
198    fn test_dup_empty() {
199        let head = Head::default();
200        let mut evm = Evm::new(head, vec![0x80], 1000, Int::ONE, Int::ONE, vec![]); // DUP1 on empty stack
201        let result = dup(&mut evm, &ctx(), &call(), &mut state());
202        assert!(is_halt(result, HaltReason::StackUnderflow));
203    }
204
205    // --- SWAP ---
206
207    #[test]
208    fn test_swap1() {
209        let (a, b) = (int(1), int(2));
210        let head = Head::default();
211        let mut evm = Evm::new(head, vec![0x90], 1000, Int::ONE, Int::ONE, vec![]); // SWAP1
212        evm.stack.extend([a, b]);
213        swap(&mut evm, &ctx(), &call(), &mut state()).unwrap();
214        evm.apply(&mut state());
215        assert_eq!(evm.stack, vec![b, a]); // top swapped with 2nd
216        assert_eq!(evm.pc, 0);
217    }
218
219    #[test]
220    fn test_swap2() {
221        let (a, b, c) = (int(1), int(2), int(3));
222        let head = Head::default();
223        let mut evm = Evm::new(head, vec![0x91], 1000, Int::ONE, Int::ONE, vec![]); // SWAP2
224        evm.stack.extend([a, b, c]);
225        swap(&mut evm, &ctx(), &call(), &mut state()).unwrap();
226        evm.apply(&mut state());
227        assert_eq!(evm.stack, vec![c, b, a]); // top swapped with 3rd
228        assert_eq!(evm.pc, 0);
229    }
230
231    #[test]
232    fn test_swap16() {
233        let vals: Vec<Int> = (1..=17).map(int).collect(); // need 17 items for SWAP16
234        let head = Head::default();
235        let mut evm = Evm::new(head, vec![0x9F], 1000, Int::ONE, Int::ONE, vec![]); // SWAP16
236        evm.stack.extend(vals.iter().copied());
237        swap(&mut evm, &ctx(), &call(), &mut state()).unwrap();
238        evm.apply(&mut state());
239        assert_eq!(*evm.stack.last().unwrap(), int(1)); // bottom is now on top
240        assert_eq!(evm.stack[0], int(17)); // top is now on bottom
241    }
242
243    #[test]
244    fn test_swap1_underflow_empty() {
245        let head = Head::default();
246        let mut evm = Evm::new(head, vec![0x90], 1000, Int::ONE, Int::ONE, vec![]); // SWAP1 on empty stack
247        let result = swap(&mut evm, &ctx(), &call(), &mut state());
248        assert!(is_halt(result, HaltReason::StackUnderflow));
249    }
250
251    #[test]
252    fn test_swap1_underflow_one() {
253        let head = Head::default();
254        let mut evm = Evm::new(head, vec![0x90], 1000, Int::ONE, Int::ONE, vec![]); // SWAP1 needs 2, has 1
255        evm.stack.push(int(1));
256        let result = swap(&mut evm, &ctx(), &call(), &mut state());
257        eprintln!("RESULT: {result:?}");
258        assert!(is_halt(result, HaltReason::StackUnderflow));
259    }
260
261    #[test]
262    fn test_swap2_underflow() {
263        let head = Head::default();
264        let mut evm = Evm::new(head, vec![0x91], 1000, Int::ONE, Int::ONE, vec![]); // SWAP2 needs 3, has 2
265        evm.stack.extend([int(1), int(2)]);
266        let result = swap(&mut evm, &ctx(), &call(), &mut state());
267        assert!(is_halt(result, HaltReason::StackUnderflow));
268    }
269}