1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
/// Byte representation of an opcode
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[repr(u8)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum OpcodeRepr {
    /// RESERV00
    RESERV00 = 0x00,
    /// RESERV01
    RESERV01 = 0x01,
    /// RESERV02
    RESERV02 = 0x02,
    /// RESERV03
    RESERV03 = 0x03,
    /// RESERV04
    RESERV04 = 0x04,
    /// RESERV05
    RESERV05 = 0x05,
    /// RESERV06
    RESERV06 = 0x06,
    /// RESERV07
    RESERV07 = 0x07,
    /// RESERV08
    RESERV08 = 0x08,
    /// RESERV09
    RESERV09 = 0x09,
    /// RESERV0A
    RESERV0A = 0x0a,
    /// RESERV0B
    RESERV0B = 0x0b,
    /// RESERV0C
    RESERV0C = 0x0c,
    /// RESERV0D
    RESERV0D = 0x0d,
    /// RESERV0E
    RESERV0E = 0x0e,
    /// RESERV0F
    RESERV0F = 0x0f,

    // Classes 0x1_-0x4_ - No immediate value
    /// ADD
    ADD = 0x10,
    /// AND
    AND = 0x11,
    /// DIV
    DIV = 0x12,
    /// EQ
    EQ = 0x13,
    /// EXP
    EXP = 0x14,
    /// GT
    GT = 0x15,
    /// LT
    LT = 0x16,
    /// MLOG
    MLOG = 0x17,
    /// MROO
    MROO = 0x18,
    /// MOD
    MOD = 0x19,
    /// MOVE
    MOVE = 0x1a,
    /// MUL
    MUL = 0x1b,
    /// NOT
    NOT = 0x1c,
    /// OR
    OR = 0x1d,
    /// SLL
    SLL = 0x1e,
    /// SRL
    SRL = 0x1f,
    /// SUB
    SUB = 0x20,
    /// XOR
    XOR = 0x21,
    /// RESERV22
    RESERV22 = 0x22,
    /// RESERV23
    RESERV23 = 0x23,
    /// RET
    RET = 0x24,
    /// RETD
    RETD = 0x25,
    /// ALOC
    ALOC = 0x26,
    /// MCL
    MCL = 0x27,
    /// MCP
    MCP = 0x28,
    /// MEQ
    MEQ = 0x29,
    /// BHSH
    BHSH = 0x2a,
    /// BHEI
    BHEI = 0x2b,
    /// BURN
    BURN = 0x2c,
    /// CALL
    CALL = 0x2d,
    /// CCP
    CCP = 0x2e,
    /// CROO
    CROO = 0x2f,
    /// CSIZ
    CSIZ = 0x30,
    /// CB
    CB = 0x31,
    /// LDC
    LDC = 0x32,
    /// LOG
    LOG = 0x33,
    /// LOGD
    LOGD = 0x34,
    /// MINT
    MINT = 0x35,
    /// RVRT
    RVRT = 0x36,
    /// SCWQ
    SCWQ = 0x37,
    /// SRW
    SRW = 0x38,
    /// SRWQ
    SRWQ = 0x39,
    /// SWW
    SWW = 0x3a,
    /// SWWQ
    SWWQ = 0x3b,
    /// TR
    TR = 0x3c,
    /// TRO
    TRO = 0x3d,
    /// ECR
    ECR = 0x3e,
    /// K256
    K256 = 0x3f,
    /// S256
    S256 = 0x40,
    /// TIME
    TIME = 0x41,
    /// RESERV42
    RESERV42 = 0x42,
    /// RESERV43
    RESERV43 = 0x43,
    /// RESERV44
    RESERV44 = 0x44,
    /// RESERV45
    RESERV45 = 0x45,
    /// RESERV46
    RESERV46 = 0x46,
    /// NOOP
    NOOP = 0x47,
    /// FLAG
    FLAG = 0x48,
    /// BAL
    BAL = 0x49,
    /// JMP
    JMP = 0x4a,
    /// JNE
    JNE = 0x4b,
    /// SMO
    SMO = 0x4c,
    /// RESERV4D
    RESERV4D = 0x4d,
    /// RESERV4E
    RESERV4E = 0x4e,
    /// RESERV4F
    RESERV4F = 0x4f,

    // Classes 0x5_-0x6_ - Immediate 12 bits
    /// ADDI
    ADDI = 0x50,
    /// ANDI
    ANDI = 0x51,
    /// DIVI
    DIVI = 0x52,
    /// EXPI
    EXPI = 0x53,
    /// MODI
    MODI = 0x54,
    /// MULI
    MULI = 0x55,
    /// ORI
    ORI = 0x56,
    /// SLLI
    SLLI = 0x57,
    /// SRLI
    SRLI = 0x58,
    /// SUBI
    SUBI = 0x59,
    /// XORI
    XORI = 0x5a,
    /// JNEI
    JNEI = 0x5b,
    /// LB
    LB = 0x5c,
    /// LW
    LW = 0x5d,
    /// SB
    SB = 0x5e,
    /// SW
    SW = 0x5f,
    /// MCPI
    MCPI = 0x60,
    /// GTF
    GTF = 0x61,
    /// RESERV62
    RESERV62 = 0x62,
    /// RESERV63
    RESERV63 = 0x63,
    /// RESERV64
    RESERV64 = 0x64,
    /// RESERV65
    RESERV65 = 0x65,
    /// RESERV66
    RESERV66 = 0x66,
    /// RESERV67
    RESERV67 = 0x67,
    /// RESERV68
    RESERV68 = 0x68,
    /// RESERV69
    RESERV69 = 0x69,
    /// RESERV6A
    RESERV6A = 0x6a,
    /// RESERV6B
    RESERV6B = 0x6b,
    /// RESERV6C
    RESERV6C = 0x6c,
    /// RESERV6D
    RESERV6D = 0x6d,
    /// RESERV6E
    RESERV6E = 0x6e,
    /// RESERV6F
    RESERV6F = 0x6f,

    // Classes 0x7_-0x8_ - Immediate 18 bits
    /// MCLI
    MCLI = 0x70,
    /// GM
    GM = 0x71,
    /// MOVI
    MOVI = 0x72,
    /// JNZI
    JNZI = 0x73,
    /// RESERV74
    RESERV74 = 0x74,
    /// RESERV75
    RESERV75 = 0x75,
    /// RESERV76
    RESERV76 = 0x76,
    /// RESERV77
    RESERV77 = 0x77,
    /// RESERV78
    RESERV78 = 0x78,
    /// RESERV79
    RESERV79 = 0x79,
    /// RESERV7A
    RESERV7A = 0x7a,
    /// RESERV7B
    RESERV7B = 0x7b,
    /// RESERV7C
    RESERV7C = 0x7c,
    /// RESERV7D
    RESERV7D = 0x7d,
    /// RESERV7E
    RESERV7E = 0x7e,
    /// RESERV7F
    RESERV7F = 0x7f,
    /// RESERV80
    RESERV80 = 0x80,
    /// RESERV81
    RESERV81 = 0x81,
    /// RESERV82
    RESERV82 = 0x82,
    /// RESERV83
    RESERV83 = 0x83,
    /// RESERV84
    RESERV84 = 0x84,
    /// RESERV85
    RESERV85 = 0x85,
    /// RESERV86
    RESERV86 = 0x86,
    /// RESERV87
    RESERV87 = 0x87,
    /// RESERV88
    RESERV88 = 0x88,
    /// RESERV89
    RESERV89 = 0x89,
    /// RESERV8A
    RESERV8A = 0x8a,
    /// RESERV8B
    RESERV8B = 0x8b,
    /// RESERV8C
    RESERV8C = 0x8c,
    /// RESERV8D
    RESERV8D = 0x8d,
    /// RESERV8E
    RESERV8E = 0x8e,
    /// RESERV8F
    RESERV8F = 0x8f,

    // Classes 0x9_-0xa_ - Immediate 24 bits
    /// JI
    JI = 0x90,
    /// CFEI
    CFEI = 0x91,
    /// CFSI
    CFSI = 0x92,
    /// RESERV93
    RESERV93 = 0x93,
    /// RESERV94
    RESERV94 = 0x94,
    /// RESERV95
    RESERV95 = 0x95,
    /// RESERV96
    RESERV96 = 0x96,
    /// RESERV97
    RESERV97 = 0x97,
    /// RESERV98
    RESERV98 = 0x98,
    /// RESERV99
    RESERV99 = 0x99,
    /// RESERV9A
    RESERV9A = 0x9a,
    /// RESERV9B
    RESERV9B = 0x9b,
    /// RESERV9C
    RESERV9C = 0x9c,
    /// RESERV9D
    RESERV9D = 0x9d,
    /// RESERV9E
    RESERV9E = 0x9e,
    /// RESERV9F
    RESERV9F = 0x9f,
    /// RESERVA0
    RESERVA0 = 0xa0,
    /// RESERVA1
    RESERVA1 = 0xa1,
    /// RESERVA2
    RESERVA2 = 0xa2,
    /// RESERVA3
    RESERVA3 = 0xa3,
    /// RESERVA4
    RESERVA4 = 0xa4,
    /// RESERVA5
    RESERVA5 = 0xa5,
    /// RESERVA6
    RESERVA6 = 0xa6,
    /// RESERVA7
    RESERVA7 = 0xa7,
    /// RESERVA8
    RESERVA8 = 0xa8,
    /// RESERVA9
    RESERVA9 = 0xa9,
    /// RESERVAA
    RESERVAA = 0xaa,
    /// RESERVAB
    RESERVAB = 0xab,
    /// RESERVAC
    RESERVAC = 0xac,
    /// RESERVAD
    RESERVAD = 0xad,
    /// RESERVAE
    RESERVAE = 0xae,
    /// RESERVAF
    RESERVAF = 0xaf,

    /// RESERVB0
    RESERVB0 = 0xb0,
    /// RESERVB1
    RESERVB1 = 0xb1,
    /// RESERVB2
    RESERVB2 = 0xb2,
    /// RESERVB3
    RESERVB3 = 0xb3,
    /// RESERVB4
    RESERVB4 = 0xb4,
    /// RESERVB5
    RESERVB5 = 0xb5,
    /// RESERVB6
    RESERVB6 = 0xb6,
    /// RESERVB7
    RESERVB7 = 0xb7,
    /// RESERVB8
    RESERVB8 = 0xb8,
    /// RESERVB9
    RESERVB9 = 0xb9,
    /// RESERVBA
    RESERVBA = 0xba,
    /// RESERVBB
    RESERVBB = 0xbb,
    /// RESERVBC
    RESERVBC = 0xbc,
    /// RESERVBD
    RESERVBD = 0xbd,
    /// RESERVBE
    RESERVBE = 0xbe,
    /// RESERVBF
    RESERVBF = 0xbf,

    /// RESERVC0
    RESERVC0 = 0xc0,
    /// RESERVC1
    RESERVC1 = 0xc1,
    /// RESERVC2
    RESERVC2 = 0xc2,
    /// RESERVC3
    RESERVC3 = 0xc3,
    /// RESERVC4
    RESERVC4 = 0xc4,
    /// RESERVC5
    RESERVC5 = 0xc5,
    /// RESERVC6
    RESERVC6 = 0xc6,
    /// RESERVC7
    RESERVC7 = 0xc7,
    /// RESERVC8
    RESERVC8 = 0xc8,
    /// RESERVC9
    RESERVC9 = 0xc9,
    /// RESERVCA
    RESERVCA = 0xca,
    /// RESERVCB
    RESERVCB = 0xcb,
    /// RESERVCC
    RESERVCC = 0xcc,
    /// RESERVCD
    RESERVCD = 0xcd,
    /// RESERVCE
    RESERVCE = 0xce,
    /// RESERVCF
    RESERVCF = 0xcf,

    /// RESERVD0
    RESERVD0 = 0xd0,
    /// RESERVD1
    RESERVD1 = 0xd1,
    /// RESERVD2
    RESERVD2 = 0xd2,
    /// RESERVD3
    RESERVD3 = 0xd3,
    /// RESERVD4
    RESERVD4 = 0xd4,
    /// RESERVD5
    RESERVD5 = 0xd5,
    /// RESERVD6
    RESERVD6 = 0xd6,
    /// RESERVD7
    RESERVD7 = 0xd7,
    /// RESERVD8
    RESERVD8 = 0xd8,
    /// RESERVD9
    RESERVD9 = 0xd9,
    /// RESERVDA
    RESERVDA = 0xda,
    /// RESERVDB
    RESERVDB = 0xdb,
    /// RESERVDC
    RESERVDC = 0xdc,
    /// RESERVDD
    RESERVDD = 0xdd,
    /// RESERVDE
    RESERVDE = 0xde,
    /// RESERVDF
    RESERVDF = 0xdf,

    /// RESERVE0
    RESERVE0 = 0xe0,
    /// RESERVE1
    RESERVE1 = 0xe1,
    /// RESERVE2
    RESERVE2 = 0xe2,
    /// RESERVE3
    RESERVE3 = 0xe3,
    /// RESERVE4
    RESERVE4 = 0xe4,
    /// RESERVE5
    RESERVE5 = 0xe5,
    /// RESERVE6
    RESERVE6 = 0xe6,
    /// RESERVE7
    RESERVE7 = 0xe7,
    /// RESERVE8
    RESERVE8 = 0xe8,
    /// RESERVE9
    RESERVE9 = 0xe9,
    /// RESERVEA
    RESERVEA = 0xea,
    /// RESERVEB
    RESERVEB = 0xeb,
    /// RESERVEC
    RESERVEC = 0xec,
    /// RESERVED
    RESERVED = 0xed,
    /// RESERVEE
    RESERVEE = 0xee,
    /// RESERVEF
    RESERVEF = 0xef,

    /// RESERVF0
    RESERVF0 = 0xf0,
    /// RESERVF1
    RESERVF1 = 0xf1,
    /// RESERVF2
    RESERVF2 = 0xf2,
    /// RESERVF3
    RESERVF3 = 0xf3,
    /// RESERVF4
    RESERVF4 = 0xf4,
    /// RESERVF5
    RESERVF5 = 0xf5,
    /// RESERVF6
    RESERVF6 = 0xf6,
    /// RESERVF7
    RESERVF7 = 0xf7,
    /// RESERVF8
    RESERVF8 = 0xf8,
    /// RESERVF9
    RESERVF9 = 0xf9,
    /// RESERVFA
    RESERVFA = 0xfa,
    /// RESERVFB
    RESERVFB = 0xfb,
    /// RESERVFC
    RESERVFC = 0xfc,
    /// RESERVFD
    RESERVFD = 0xfd,
    /// RESERVFE
    RESERVFE = 0xfe,
    /// RESERVFF
    RESERVFF = 0xff,
}

impl OpcodeRepr {
    /// Check if the opcode representation is allowed for predicates
    ///
    /// <https://github.com/FuelLabs/fuel-specs/blob/master/specs/vm/main.md#predicate-verification>
    /// <https://github.com/FuelLabs/fuel-specs/blob/master/specs/vm/opcodes.md#contract-opcodes>
    #[allow(clippy::match_like_matches_macro)]
    // Not following clippy conventions because rustfmt formats macros into bloated code
    pub const fn is_predicate_allowed(&self) -> bool {
        // TODO Update `OpcodeRepr` to separate contract opcodes
        // https://github.com/FuelLabs/fuel-asm/issues/68

        use OpcodeRepr::*;

        match self {
            ADD | AND | DIV | EQ | EXP | GT | LT | MLOG | MROO | MOD | MOVE | MUL | NOT | OR
            | SLL | SRL | SUB | XOR | RET | ALOC | MCL | MCP | MEQ | ECR | K256 | S256 | NOOP
            | FLAG | ADDI | ANDI | DIVI | EXPI | MODI | MULI | ORI | SLLI | SRLI | SUBI | XORI
            | JNEI | LB | LW | SB | SW | MCPI | MCLI | GM | MOVI | JNZI | JI | JMP | JNE | CFEI
            | CFSI | GTF => true,

            _ => false,
        }
    }
}

#[test]
#[allow(clippy::match_like_matches_macro)]
fn check_predicate_allowed() {
    use OpcodeRepr::*;

    // This exhaustive test will shield against changes in the opcodes structure
    for byte in 0..u8::MAX {
        let repr = OpcodeRepr::from_u8(byte);

        let should_allow = match repr {
            BAL | BHEI | BHSH | BURN | CALL | CB | CCP | CROO | CSIZ | LDC | LOG | LOGD | MINT
            | RETD | RVRT | SMO | SCWQ | SRW | SRWQ | SWW | SWWQ | TIME | TR | TRO => false,

            RESERV00 | RESERV01 | RESERV02 | RESERV03 | RESERV04 | RESERV05 | RESERV06
            | RESERV07 | RESERV08 | RESERV09 | RESERV0A | RESERV0B | RESERV0C | RESERV0D
            | RESERV0E | RESERV0F | RESERV22 | RESERV23 | RESERV42 | RESERV43 | RESERV44
            | RESERV45 | RESERV46 | RESERV4D | RESERV4E | RESERV4F | RESERV62 | RESERV63
            | RESERV64 | RESERV65 | RESERV66 | RESERV67 | RESERV68 | RESERV69 | RESERV6A
            | RESERV6B | RESERV6C | RESERV6D | RESERV6E | RESERV6F | RESERV74 | RESERV75
            | RESERV76 | RESERV77 | RESERV78 | RESERV79 | RESERV7A | RESERV7B | RESERV7C
            | RESERV7D | RESERV7E | RESERV7F | RESERV80 | RESERV81 | RESERV82 | RESERV83
            | RESERV84 | RESERV85 | RESERV86 | RESERV87 | RESERV88 | RESERV89 | RESERV8A
            | RESERV8B | RESERV8C | RESERV8D | RESERV8E | RESERV8F | RESERV93 | RESERV94
            | RESERV95 | RESERV96 | RESERV97 | RESERV98 | RESERV99 | RESERV9A | RESERV9B
            | RESERV9C | RESERV9D | RESERV9E | RESERV9F | RESERVA0 | RESERVA1 | RESERVA2
            | RESERVA3 | RESERVA4 | RESERVA5 | RESERVA6 | RESERVA7 | RESERVA8 | RESERVA9
            | RESERVAA | RESERVAB | RESERVAC | RESERVAD | RESERVAE | RESERVAF | RESERVB0
            | RESERVB1 | RESERVB2 | RESERVB3 | RESERVB4 | RESERVB5 | RESERVB6 | RESERVB7
            | RESERVB8 | RESERVB9 | RESERVBA | RESERVBB | RESERVBC | RESERVBD | RESERVBE
            | RESERVBF | RESERVC0 | RESERVC1 | RESERVC2 | RESERVC3 | RESERVC4 | RESERVC5
            | RESERVC6 | RESERVC7 | RESERVC8 | RESERVC9 | RESERVCA | RESERVCB | RESERVCC
            | RESERVCD | RESERVCE | RESERVCF | RESERVD0 | RESERVD1 | RESERVD2 | RESERVD3
            | RESERVD4 | RESERVD5 | RESERVD6 | RESERVD7 | RESERVD8 | RESERVD9 | RESERVDA
            | RESERVDB | RESERVDC | RESERVDD | RESERVDE | RESERVDF | RESERVE0 | RESERVE1
            | RESERVE2 | RESERVE3 | RESERVE4 | RESERVE5 | RESERVE6 | RESERVE7 | RESERVE8
            | RESERVE9 | RESERVEA | RESERVEB | RESERVEC | RESERVED | RESERVEE | RESERVEF
            | RESERVF0 | RESERVF1 | RESERVF2 | RESERVF3 | RESERVF4 | RESERVF5 | RESERVF6
            | RESERVF7 | RESERVF8 | RESERVF9 | RESERVFA | RESERVFB | RESERVFC | RESERVFD
            | RESERVFE | RESERVFF => false,

            _ => true,
        };

        assert_eq!(should_allow, repr.is_predicate_allowed());
    }
}