@@ -15,6 +15,8 @@ use std::mem::size_of;
15
15
pub const MIN_SIGNERS : usize = 1 ;
16
16
/// Maximum number of multisignature signers (max N)
17
17
pub const MAX_SIGNERS : usize = 11 ;
18
+ /// Serialized length of a u64, for unpacking
19
+ const U64_BYTES : usize = 8 ;
18
20
19
21
/// Instructions supported by the token program.
20
22
#[ repr( C ) ]
@@ -519,47 +521,19 @@ impl<'a> TokenInstruction<'a> {
519
521
10 => Self :: FreezeAccount ,
520
522
11 => Self :: ThawAccount ,
521
523
12 => {
522
- let ( amount, rest) = rest. split_at ( 8 ) ;
523
- let amount = amount
524
- . try_into ( )
525
- . ok ( )
526
- . map ( u64:: from_le_bytes)
527
- . ok_or ( InvalidInstruction ) ?;
528
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
529
-
524
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
530
525
Self :: TransferChecked { amount, decimals }
531
526
}
532
527
13 => {
533
- let ( amount, rest) = rest. split_at ( 8 ) ;
534
- let amount = amount
535
- . try_into ( )
536
- . ok ( )
537
- . map ( u64:: from_le_bytes)
538
- . ok_or ( InvalidInstruction ) ?;
539
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
540
-
528
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
541
529
Self :: ApproveChecked { amount, decimals }
542
530
}
543
531
14 => {
544
- let ( amount, rest) = rest. split_at ( 8 ) ;
545
- let amount = amount
546
- . try_into ( )
547
- . ok ( )
548
- . map ( u64:: from_le_bytes)
549
- . ok_or ( InvalidInstruction ) ?;
550
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
551
-
532
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
552
533
Self :: MintToChecked { amount, decimals }
553
534
}
554
535
15 => {
555
- let ( amount, rest) = rest. split_at ( 8 ) ;
556
- let amount = amount
557
- . try_into ( )
558
- . ok ( )
559
- . map ( u64:: from_le_bytes)
560
- . ok_or ( InvalidInstruction ) ?;
561
- let ( & decimals, _rest) = rest. split_first ( ) . ok_or ( InvalidInstruction ) ?;
562
-
536
+ let ( amount, decimals, _rest) = Self :: unpack_amount_decimals ( rest) ?;
563
537
Self :: BurnChecked { amount, decimals }
564
538
}
565
539
16 => {
@@ -588,12 +562,7 @@ impl<'a> TokenInstruction<'a> {
588
562
21 => Self :: GetAccountDataSize ,
589
563
22 => Self :: InitializeImmutableOwner ,
590
564
23 => {
591
- let ( amount, _rest) = rest. split_at ( 8 ) ;
592
- let amount = amount
593
- . try_into ( )
594
- . ok ( )
595
- . map ( u64:: from_le_bytes)
596
- . ok_or ( InvalidInstruction ) ?;
565
+ let ( amount, _rest) = Self :: unpack_u64 ( rest) ?;
597
566
Self :: AmountToUiAmount { amount }
598
567
}
599
568
24 => {
@@ -745,6 +714,21 @@ impl<'a> TokenInstruction<'a> {
745
714
COption :: None => buf. push ( 0 ) ,
746
715
}
747
716
}
717
+
718
+ fn unpack_u64 ( input : & [ u8 ] ) -> Result < ( u64 , & [ u8 ] ) , ProgramError > {
719
+ let value = input
720
+ . get ( ..U64_BYTES )
721
+ . and_then ( |slice| slice. try_into ( ) . ok ( ) )
722
+ . map ( u64:: from_le_bytes)
723
+ . ok_or ( TokenError :: InvalidInstruction ) ?;
724
+ Ok ( ( value, & input[ U64_BYTES ..] ) )
725
+ }
726
+
727
+ fn unpack_amount_decimals ( input : & [ u8 ] ) -> Result < ( u64 , u8 , & [ u8 ] ) , ProgramError > {
728
+ let ( amount, rest) = Self :: unpack_u64 ( input) ?;
729
+ let ( & decimals, rest) = rest. split_first ( ) . ok_or ( TokenError :: InvalidInstruction ) ?;
730
+ Ok ( ( amount, decimals, rest) )
731
+ }
748
732
}
749
733
750
734
/// Specifies the authority type for SetAuthority instructions
@@ -1447,7 +1431,7 @@ pub fn is_valid_signer_index(index: usize) -> bool {
1447
1431
1448
1432
#[ cfg( test) ]
1449
1433
mod test {
1450
- use super :: * ;
1434
+ use { super :: * , proptest :: prelude :: * } ;
1451
1435
1452
1436
#[ test]
1453
1437
fn test_instruction_packing ( ) {
@@ -1689,4 +1673,25 @@ mod test {
1689
1673
let unpacked = TokenInstruction :: unpack ( & expect) . unwrap ( ) ;
1690
1674
assert_eq ! ( unpacked, check) ;
1691
1675
}
1676
+
1677
+ #[ test]
1678
+ fn test_instruction_unpack_panic ( ) {
1679
+ for i in 0 ..255u8 {
1680
+ for j in 1 ..10 {
1681
+ let mut data = vec ! [ 0 ; j] ;
1682
+ data[ 0 ] = i;
1683
+ let _no_panic = TokenInstruction :: unpack ( & data) ;
1684
+ }
1685
+ }
1686
+ }
1687
+
1688
+ proptest ! {
1689
+ #![ proptest_config( ProptestConfig :: with_cases( 1024 ) ) ]
1690
+ #[ test]
1691
+ fn test_instruction_unpack_proptest(
1692
+ data in prop:: collection:: vec( any:: <u8 >( ) , 0 ..255 )
1693
+ ) {
1694
+ let _no_panic = TokenInstruction :: unpack( & data) ;
1695
+ }
1696
+ }
1692
1697
}
0 commit comments