xevm/opcodes/
ops.rs

1use super::ExecutionResult;
2use super::OpcodeHandler;
3use crate::context::Context;
4use crate::error::ExecError;
5use crate::error::RevertError;
6use crate::machine::CallInfo;
7use crate::machine::Machine;
8use crate::machine::Word;
9
10pub enum OpcodeBinaryOp {
11    Add,
12    Mul,
13    Sub,
14    Div,
15    Sdiv,
16    Mod,
17    Smod,
18    Exp,
19    Shl,
20    Shr,
21    Sar,
22    And,
23    Or,
24    Xor,
25    Byte,
26    Lt,
27    Gt,
28    Slt,
29    Sgt,
30    Eq,
31    SignExtend,
32}
33
34pub enum OpcodeUnaryOp {
35    IsZero,
36    Not,
37}
38
39pub enum OpcodeModularOp {
40    AddMod,
41    MulMod,
42}
43
44impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeModularOp {
45    fn call(
46        &self,
47        _ctx: &mut C,
48        machine: &mut Machine<W>,
49        _call_info: &CallInfo<W>,
50    ) -> Result<Option<ExecutionResult>, ExecError> {
51        let a = machine.pop_stack()?;
52        let b = machine.pop_stack()?;
53        let n = machine.pop_stack()?;
54        machine.stack.push(match self {
55            Self::AddMod => a.addmod(b, n),
56            Self::MulMod => a.mulmod(b, n),
57        });
58        machine.pc += 1;
59        Ok(None)
60    }
61}
62
63impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeUnaryOp {
64    fn call(
65        &self,
66        _ctx: &mut C,
67        machine: &mut Machine<W>,
68        _call_info: &CallInfo<W>,
69    ) -> Result<Option<ExecutionResult>, ExecError> {
70        let a = machine.pop_stack()?;
71        machine.stack.push(match self {
72            Self::IsZero => W::from_u64((a == W::ZERO) as u64),
73            Self::Not => a.not(),
74        });
75        machine.pc += 1;
76        Ok(None)
77    }
78}
79
80impl<W: Word, C: Context<W>> OpcodeHandler<W, C> for OpcodeBinaryOp {
81    fn call(
82        &self,
83        _ctx: &mut C,
84        machine: &mut Machine<W>,
85        _call_info: &CallInfo<W>,
86    ) -> Result<Option<ExecutionResult>, ExecError> {
87        let a = machine.pop_stack()?;
88        let b = machine.pop_stack()?;
89        machine.stack.push(match self {
90            Self::Add => a.add(b),
91            Self::Mul => a.mul(b),
92            Self::Sub => a.sub(b),
93            Self::Div => {
94                if b == W::ZERO {
95                    W::ZERO
96                } else {
97                    a.div(b)
98                }
99            }
100            Self::Sdiv => match (a.is_neg(), b.is_neg()) {
101                (false, false) => a.div(b),
102                (true, true) => a.neg().div(b.neg()),
103                (false, true) => if a.rem(b.neg()) == W::ZERO {
104                    a.div(b.neg())
105                } else {
106                    a.div(b.neg()).add(W::ONE)
107                }
108                .neg(),
109                (true, false) => if a.neg().rem(b) == W::ZERO {
110                    a.neg().div(b)
111                } else {
112                    a.neg().div(b).add(W::ONE)
113                }
114                .neg(),
115            },
116            Self::Mod => a.rem(b),
117            Self::Smod => match (a.is_neg(), b.is_neg()) {
118                (false, false) => a.rem(b),
119                (true, true) => a.neg().rem(b.neg()).neg(),
120                (false, true) => {
121                    if a.rem(b.neg()) == W::ZERO {
122                        W::ZERO
123                    } else {
124                        b.neg().sub(a.rem(b.neg())).neg()
125                    }
126                }
127                (true, false) => {
128                    if a.neg().rem(b) == W::ZERO {
129                        W::ZERO
130                    } else {
131                        b.sub(a.neg().rem(b))
132                    }
133                }
134            },
135            Self::Exp => a.pow(b),
136            Self::Shl => b.shl(a),
137            Self::Shr => b.shr(a),
138            Self::And => a.and(b),
139            Self::Or => a.or(b),
140            Self::Xor => a.xor(b),
141            Self::Lt => W::from_u64((a < b) as u64),
142            Self::Gt => W::from_u64((a > b) as u64),
143            Self::Slt => W::from_u64(match (a.is_neg(), b.is_neg()) {
144                (false, false) => a.lt(b),
145                (false, true) => false,
146                (true, false) => true,
147                (true, true) => a.neg().gt(b.neg()),
148            } as u64),
149            Self::Sgt => W::from_u64(match (a.is_neg(), b.is_neg()) {
150                (false, false) => a.gt(b),
151                (false, true) => true,
152                (true, false) => false,
153                (true, true) => a.neg().lt(b.neg()),
154            } as u64),
155            Self::Eq => W::from_u64((a == b) as u64),
156            Self::Byte => {
157                let i = a.to_usize()?;
158                let x = b.to_big_endian();
159                W::from_u64(if i < 32 { x[i] as u64 } else { 0 })
160            }
161            Self::Sar => {
162                let mut result = b.shr(a);
163                if b.is_neg() {
164                    let addition = W::MAX.shl(W::from_u64(256).sub(a));
165                    result = result.add(addition);
166                }
167                result
168            }
169            Self::SignExtend => {
170                let bytes_1 = a.to_usize()?;
171                if bytes_1 > 31 {
172                    return Err(ExecError::Revert(RevertError::OutOfBounds));
173                }
174                let bytes = bytes_1 + 1;
175                let is_neg = b.bit(bytes_1 * 8 + 7);
176                let x = b
177                    .shl(W::from_u64((256 - bytes * 8) as u64))
178                    .shr(W::from_u64((256 - bytes * 8) as u64));
179                if is_neg {
180                    x.add(W::MAX.shl(W::from_u64(((bytes_1 + 1) * 8) as u64)))
181                } else {
182                    x
183                }
184            }
185        });
186        machine.pc += 1;
187        Ok(None)
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use crate::u256::U256;
194
195    use super::super::tests::test;
196    use super::*;
197
198    #[test]
199    fn test_opcode_sar() {
200        test(
201            OpcodeBinaryOp::Sar,
202            &[
203                (&[], None),
204                (&[U256::from(123)], None),
205                (&[U256::from(0), U256::from(123)], Some(&[U256::from(123)])),
206                (&[U256::from(1), U256::from(123)], Some(&[U256::from(61)])),
207                (&[U256::from(2), U256::from(123)], Some(&[U256::from(30)])),
208                (&[U256::from(3), U256::from(123)], Some(&[U256::from(15)])),
209                (&[U256::from(100), U256::from(123)], Some(&[U256::from(0)])),
210                (&[U256::from(1), -U256::from(123)], Some(&[-U256::from(62)])),
211                (&[U256::from(2), -U256::from(123)], Some(&[-U256::from(31)])),
212                (&[U256::from(3), -U256::from(123)], Some(&[-U256::from(16)])),
213                (
214                    &[U256::from(100), -U256::from(123)],
215                    Some(&[-U256::from(1)]),
216                ),
217                (
218                    &[U256::from(128), U256::MAX >> U256::ONE],
219                    Some(&[U256::MAX >> U256::from(129)]),
220                ),
221                (&[U256::from(128), U256::MAX], Some(&[U256::MAX])),
222            ],
223        );
224    }
225
226    #[test]
227    fn test_opcode_lt() {
228        test(
229            OpcodeBinaryOp::Lt,
230            &[
231                (&[], None),
232                (&[U256::from(123)], None),
233                (&[U256::from(123), U256::from(120)], Some(&[U256::ZERO])),
234                (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
235                (&[U256::from(123), U256::from(234)], Some(&[U256::ONE])),
236                (
237                    &[U256::MAX, U256::MAX - U256::from(123)],
238                    Some(&[U256::ZERO]),
239                ),
240                (&[U256::MAX, U256::MAX], Some(&[U256::ZERO])),
241                (
242                    &[U256::MAX - U256::from(123), U256::MAX],
243                    Some(&[U256::ONE]),
244                ),
245            ],
246        );
247    }
248
249    #[test]
250    fn test_opcode_gt() {
251        test(
252            OpcodeBinaryOp::Gt,
253            &[
254                (&[], None),
255                (&[U256::from(123)], None),
256                (&[U256::from(123), U256::from(120)], Some(&[U256::ONE])),
257                (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
258                (&[U256::from(123), U256::from(234)], Some(&[U256::ZERO])),
259                (
260                    &[U256::MAX, U256::MAX - U256::from(123)],
261                    Some(&[U256::ONE]),
262                ),
263                (&[U256::MAX, U256::MAX], Some(&[U256::ZERO])),
264                (
265                    &[U256::MAX - U256::from(123), U256::MAX],
266                    Some(&[U256::ZERO]),
267                ),
268            ],
269        );
270    }
271
272    #[test]
273    fn test_opcode_slt() {
274        test(
275            OpcodeBinaryOp::Slt,
276            &[
277                (&[], None),
278                (&[U256::from(123)], None),
279                (&[U256::from(123), U256::from(120)], Some(&[U256::ZERO])),
280                (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
281                (&[U256::from(123), U256::from(234)], Some(&[U256::ONE])),
282                (&[-U256::from(123), U256::from(123)], Some(&[U256::ONE])),
283                (&[U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
284                (&[-U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
285                (&[-U256::from(123), -U256::from(234)], Some(&[U256::ZERO])),
286                (&[-U256::from(234), -U256::from(123)], Some(&[U256::ONE])),
287            ],
288        );
289    }
290
291    #[test]
292    fn test_opcode_sgt() {
293        test(
294            OpcodeBinaryOp::Sgt,
295            &[
296                (&[], None),
297                (&[U256::from(123)], None),
298                (&[U256::from(123), U256::from(120)], Some(&[U256::ONE])),
299                (&[U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
300                (&[U256::from(123), U256::from(234)], Some(&[U256::ZERO])),
301                (&[-U256::from(123), U256::from(123)], Some(&[U256::ZERO])),
302                (&[U256::from(123), -U256::from(123)], Some(&[U256::ONE])),
303                (&[-U256::from(123), -U256::from(123)], Some(&[U256::ZERO])),
304                (&[-U256::from(123), -U256::from(234)], Some(&[U256::ONE])),
305                (&[-U256::from(234), -U256::from(123)], Some(&[U256::ZERO])),
306            ],
307        );
308    }
309
310    #[test]
311    fn test_opcode_eq() {
312        test(
313            OpcodeBinaryOp::Eq,
314            &[
315                (&[], None),
316                (&[U256::from(123)], None),
317                (&[U256::from(0), U256::from(0)], Some(&[U256::ONE])),
318                (&[U256::from(123), U256::from(123)], Some(&[U256::ONE])),
319                (&[U256::from(123), U256::from(122)], Some(&[U256::ZERO])),
320                (&[U256::MAX, U256::MAX], Some(&[U256::ONE])),
321                (&[U256::MAX, U256::MAX - U256::ONE], Some(&[U256::ZERO])),
322            ],
323        );
324    }
325
326    #[test]
327    fn test_opcode_is_zero() {
328        test(
329            OpcodeUnaryOp::IsZero,
330            &[
331                (&[], None),
332                (&[U256::from(0)], Some(&[U256::ONE])),
333                (&[U256::from(123)], Some(&[U256::ZERO])),
334                (&[U256::MAX], Some(&[U256::ZERO])),
335                (&[U256::MAX - U256::ONE], Some(&[U256::ZERO])),
336            ],
337        );
338    }
339
340    #[test]
341    fn test_opcode_sdiv() {
342        test(
343            OpcodeBinaryOp::Sdiv,
344            &[
345                (&[U256::from(11), U256::from(2)], Some(&[U256::from(5)])),
346                (&[-U256::from(11), -U256::from(2)], Some(&[U256::from(5)])),
347                (&[-U256::from(11), U256::from(2)], Some(&[-U256::from(6)])),
348                (&[U256::from(11), -U256::from(2)], Some(&[-U256::from(6)])),
349                (&[U256::from(10), U256::from(2)], Some(&[U256::from(5)])),
350                (&[-U256::from(10), -U256::from(2)], Some(&[U256::from(5)])),
351                (&[U256::from(10), -U256::from(2)], Some(&[-U256::from(5)])),
352                (&[-U256::from(10), U256::from(2)], Some(&[-U256::from(5)])),
353            ],
354        );
355    }
356    #[test]
357    fn test_opcode_smod() {
358        test(
359            OpcodeBinaryOp::Smod,
360            &[
361                (&[U256::from(11), U256::from(3)], Some(&[U256::from(2)])),
362                (&[-U256::from(11), -U256::from(3)], Some(&[-U256::from(2)])),
363                (&[-U256::from(11), U256::from(3)], Some(&[U256::from(1)])),
364                (&[U256::from(11), -U256::from(3)], Some(&[-U256::from(1)])),
365                (&[U256::from(10), U256::from(3)], Some(&[U256::from(1)])),
366                (&[-U256::from(10), -U256::from(3)], Some(&[-U256::from(1)])),
367                (&[-U256::from(10), U256::from(3)], Some(&[U256::from(2)])),
368                (&[U256::from(10), -U256::from(3)], Some(&[-U256::from(2)])),
369                (&[U256::from(123), U256::from(100)], Some(&[U256::from(23)])),
370                (
371                    &[-U256::from(123), -U256::from(100)],
372                    Some(&[-U256::from(23)]),
373                ),
374                (
375                    &[-U256::from(123), U256::from(100)],
376                    Some(&[U256::from(77)]),
377                ),
378                (
379                    &[U256::from(123), -U256::from(100)],
380                    Some(&[-U256::from(77)]),
381                ),
382            ],
383        );
384    }
385    #[test]
386    fn test_sign_extend() {
387        test(
388            OpcodeBinaryOp::SignExtend,
389            &[
390                (&[U256::from(0), U256::from(0xff)], Some(&[U256::MAX])),
391                (
392                    &[U256::from(0), U256::from(0x7f)],
393                    Some(&[U256::from(0x7f)]),
394                ),
395                (&[U256::from(0), -U256::from(1)], Some(&[-U256::from(1)])),
396                (
397                    &[U256::from(1), U256::from(0x1234)],
398                    Some(&[U256::from(0x1234)]),
399                ),
400                (
401                    &[U256::from(1), U256::from(0x8234)],
402                    Some(&[-U256::from(32204)]),
403                ),
404                (
405                    &[U256::from(2), U256::from(0x8234)],
406                    Some(&[U256::from(0x8234)]),
407                ),
408                (
409                    &[U256::from(31), U256::from(0x8234)],
410                    Some(&[U256::from(0x8234)]),
411                ),
412                (&[U256::from(32), U256::from(0x8234)], None),
413                (&[U256::MAX, U256::from(0x8234)], None),
414                (&[U256::from(31), U256::MAX], Some(&[U256::MAX])),
415            ],
416        );
417    }
418}