56
56
num_enum:: { IntoPrimitive , TryFromPrimitive } ,
57
57
serde:: { Deserialize , Serialize } ,
58
58
solana_entry:: entry:: { create_ticks, Entry } ,
59
- solana_perf:: packet:: Packet ,
59
+ solana_perf:: packet:: { deserialize_from_with_limit , Packet } ,
60
60
solana_runtime:: bank:: Bank ,
61
61
solana_sdk:: {
62
62
clock:: Slot ,
@@ -317,7 +317,7 @@ impl Shred {
317
317
}
318
318
319
319
pub fn new_from_serialized_shred ( shred : Vec < u8 > ) -> Result < Self , Error > {
320
- Ok ( match Self :: shred_type_from_payload ( & shred) ? {
320
+ Ok ( match layout :: get_shred_type ( & shred) ? {
321
321
ShredType :: Code => Self :: from ( ShredCode :: from_payload ( shred) ?) ,
322
322
ShredType :: Data => Self :: from ( ShredData :: from_payload ( shred) ?) ,
323
323
} )
@@ -383,7 +383,7 @@ impl Shred {
383
383
384
384
// Possibly zero pads bytes stored in blockstore.
385
385
pub ( crate ) fn resize_stored_shred ( shred : Vec < u8 > ) -> Result < Vec < u8 > , Error > {
386
- match Self :: shred_type_from_payload ( & shred) ? {
386
+ match layout :: get_shred_type ( & shred) ? {
387
387
ShredType :: Code => ShredCode :: resize_stored_shred ( shred) ,
388
388
ShredType :: Data => ShredData :: resize_stored_shred ( shred) ,
389
389
}
@@ -441,16 +441,6 @@ impl Shred {
441
441
self . common_header ( ) . shred_type
442
442
}
443
443
444
- fn shred_type_from_payload ( shred : & [ u8 ] ) -> Result < ShredType , Error > {
445
- match shred. get ( OFFSET_OF_SHRED_TYPE ) {
446
- None => Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
447
- Some ( shred_type) => match ShredType :: try_from ( * shred_type) {
448
- Err ( _) => Err ( Error :: InvalidShredType ) ,
449
- Ok ( shred_type) => Ok ( shred_type) ,
450
- } ,
451
- }
452
- }
453
-
454
444
pub fn is_data ( & self ) -> bool {
455
445
self . shred_type ( ) == ShredType :: Data
456
446
}
@@ -488,25 +478,6 @@ impl Shred {
488
478
}
489
479
}
490
480
491
- // Get slot from a shred packet with partial deserialize
492
- pub fn get_slot_from_packet ( p : & Packet ) -> Option < Slot > {
493
- let slot_start = OFFSET_OF_SHRED_SLOT ;
494
- let slot_end = slot_start + SIZE_OF_SHRED_SLOT ;
495
- p. deserialize_slice ( slot_start..slot_end) . ok ( )
496
- }
497
-
498
- pub ( crate ) fn reference_tick_from_data ( data : & [ u8 ] ) -> Result < u8 , Error > {
499
- const SHRED_FLAGS_OFFSET : usize = SIZE_OF_COMMON_SHRED_HEADER + std:: mem:: size_of :: < u16 > ( ) ;
500
- if Self :: shred_type_from_payload ( data) ? != ShredType :: Data {
501
- return Err ( Error :: InvalidShredType ) ;
502
- }
503
- let flags = match data. get ( SHRED_FLAGS_OFFSET ) {
504
- None => return Err ( Error :: InvalidPayloadSize ( data. len ( ) ) ) ,
505
- Some ( flags) => flags,
506
- } ;
507
- Ok ( flags & ShredFlags :: SHRED_TICK_REFERENCE_MASK . bits ( ) )
508
- }
509
-
510
481
pub fn verify ( & self , pubkey : & Pubkey ) -> bool {
511
482
let message = self . signed_payload ( ) ;
512
483
self . signature ( ) . verify ( pubkey. as_ref ( ) , message)
@@ -535,6 +506,73 @@ impl Shred {
535
506
}
536
507
}
537
508
509
+ // Helper methods to extract pieces of the shred from the payload
510
+ // without deserializing the entire payload.
511
+ pub mod layout {
512
+ use { super :: * , std:: ops:: Range } ;
513
+
514
+ fn get_shred_size ( packet : & Packet ) -> usize {
515
+ if packet. meta . repair ( ) {
516
+ packet. meta . size . saturating_sub ( SIZE_OF_NONCE )
517
+ } else {
518
+ packet. meta . size
519
+ }
520
+ }
521
+
522
+ pub fn get_shred ( packet : & Packet ) -> & [ u8 ] {
523
+ & packet. data ( ) [ ..get_shred_size ( packet) ]
524
+ }
525
+
526
+ pub ( crate ) fn get_signature ( shred : & [ u8 ] ) -> Option < Signature > {
527
+ Some ( Signature :: new ( shred. get ( ..SIZE_OF_SIGNATURE ) ?) )
528
+ }
529
+
530
+ pub ( crate ) const fn get_signature_range ( ) -> Range < usize > {
531
+ 0 ..SIZE_OF_SIGNATURE
532
+ }
533
+
534
+ pub ( super ) fn get_shred_type ( shred : & [ u8 ] ) -> Result < ShredType , Error > {
535
+ match shred. get ( OFFSET_OF_SHRED_TYPE ) {
536
+ None => Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
537
+ Some ( shred_type) => match ShredType :: try_from ( * shred_type) {
538
+ Err ( _) => Err ( Error :: InvalidShredType ) ,
539
+ Ok ( shred_type) => Ok ( shred_type) ,
540
+ } ,
541
+ }
542
+ }
543
+
544
+ pub fn get_slot ( shred : & [ u8 ] ) -> Option < Slot > {
545
+ deserialize_from_with_limit ( shred. get ( OFFSET_OF_SHRED_SLOT ..) ?) . ok ( )
546
+ }
547
+
548
+ pub ( super ) fn get_index ( shred : & [ u8 ] ) -> Option < u32 > {
549
+ deserialize_from_with_limit ( shred. get ( OFFSET_OF_SHRED_INDEX ..) ?) . ok ( )
550
+ }
551
+
552
+ // Returns chunk of the payload which is signed.
553
+ pub ( crate ) fn get_signed_message ( shred : & [ u8 ] ) -> Option < & [ u8 ] > {
554
+ shred. get ( SIZE_OF_SIGNATURE ..)
555
+ }
556
+
557
+ // Returns slice range of the packet payload which is signed.
558
+ pub ( crate ) fn get_signed_message_range ( packet : & Packet ) -> Range < usize > {
559
+ SIZE_OF_SIGNATURE ..get_shred_size ( packet)
560
+ }
561
+
562
+ pub ( crate ) fn get_reference_tick ( shred : & [ u8 ] ) -> Result < u8 , Error > {
563
+ const SIZE_OF_PARENT_OFFSET : usize = std:: mem:: size_of :: < u16 > ( ) ;
564
+ const OFFSET_OF_SHRED_FLAGS : usize = SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_PARENT_OFFSET ;
565
+ if get_shred_type ( shred) ? != ShredType :: Data {
566
+ return Err ( Error :: InvalidShredType ) ;
567
+ }
568
+ let flags = match shred. get ( OFFSET_OF_SHRED_FLAGS ) {
569
+ None => return Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
570
+ Some ( flags) => flags,
571
+ } ;
572
+ Ok ( flags & ShredFlags :: SHRED_TICK_REFERENCE_MASK . bits ( ) )
573
+ }
574
+ }
575
+
538
576
impl From < ShredCode > for Shred {
539
577
fn from ( shred : ShredCode ) -> Self {
540
578
Self :: ShredCode ( shred)
@@ -549,50 +587,39 @@ impl From<ShredData> for Shred {
549
587
550
588
// Get slot, index, and type from a packet with partial deserialize
551
589
pub fn get_shred_slot_index_type (
552
- p : & Packet ,
590
+ packet : & Packet ,
553
591
stats : & mut ShredFetchStats ,
554
592
) -> Option < ( Slot , u32 , ShredType ) > {
555
- let index_start = OFFSET_OF_SHRED_INDEX ;
556
- let index_end = index_start + SIZE_OF_SHRED_INDEX ;
557
- let slot_start = OFFSET_OF_SHRED_SLOT ;
558
- let slot_end = slot_start + SIZE_OF_SHRED_SLOT ;
559
-
560
- debug_assert ! ( index_end > slot_end) ;
561
- debug_assert ! ( index_end > OFFSET_OF_SHRED_TYPE ) ;
562
-
563
- if index_end > p. meta . size {
593
+ let shred = layout:: get_shred ( packet) ;
594
+ if OFFSET_OF_SHRED_INDEX + SIZE_OF_SHRED_INDEX > shred. len ( ) {
564
595
stats. index_overrun += 1 ;
565
596
return None ;
566
597
}
567
-
568
- let index = match p. deserialize_slice ( index_start..index_end) {
569
- Ok ( x) => x,
570
- Err ( _e) => {
571
- stats. index_bad_deserialize += 1 ;
598
+ let shred_type = match layout:: get_shred_type ( shred) {
599
+ Ok ( shred_type) => shred_type,
600
+ Err ( _) => {
601
+ stats. bad_shred_type += 1 ;
572
602
return None ;
573
603
}
574
604
} ;
575
-
576
- if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
577
- stats. index_out_of_bounds += 1 ;
578
- return None ;
579
- }
580
-
581
- let slot = match p. deserialize_slice ( slot_start..slot_end) {
582
- Ok ( x) => x,
583
- Err ( _e) => {
605
+ let slot = match layout:: get_slot ( shred) {
606
+ Some ( slot) => slot,
607
+ None => {
584
608
stats. slot_bad_deserialize += 1 ;
585
609
return None ;
586
610
}
587
611
} ;
588
-
589
- let shred_type = match ShredType :: try_from ( p . data ( ) [ OFFSET_OF_SHRED_TYPE ] ) {
590
- Err ( _ ) => {
591
- stats. bad_shred_type += 1 ;
612
+ let index = match layout :: get_index ( shred ) {
613
+ Some ( index ) => index ,
614
+ None => {
615
+ stats. index_bad_deserialize += 1 ;
592
616
return None ;
593
617
}
594
- Ok ( shred_type) => shred_type,
595
618
} ;
619
+ if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
620
+ stats. index_out_of_bounds += 1 ;
621
+ return None ;
622
+ }
596
623
Some ( ( slot, index, shred_type) )
597
624
}
598
625
@@ -924,9 +951,9 @@ mod tests {
924
951
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
925
952
assert_eq ! (
926
953
shred. reference_tick( ) ,
927
- Shred :: reference_tick_from_data ( packet. data( ) ) . unwrap( )
954
+ layout :: get_reference_tick ( packet. data( ) ) . unwrap( )
928
955
) ;
929
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
956
+ assert_eq ! ( layout :: get_slot ( packet. data ( ) ) , Some ( shred. slot( ) ) ) ;
930
957
assert_eq ! (
931
958
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
932
959
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -965,9 +992,9 @@ mod tests {
965
992
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
966
993
assert_eq ! (
967
994
shred. reference_tick( ) ,
968
- Shred :: reference_tick_from_data ( packet. data( ) ) . unwrap( )
995
+ layout :: get_reference_tick ( packet. data( ) ) . unwrap( )
969
996
) ;
970
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
997
+ assert_eq ! ( layout :: get_slot ( packet. data ( ) ) , Some ( shred. slot( ) ) ) ;
971
998
assert_eq ! (
972
999
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
973
1000
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -1011,7 +1038,7 @@ mod tests {
1011
1038
packet. meta . size = payload. len ( ) ;
1012
1039
assert_eq ! ( shred. bytes_to_store( ) , payload) ;
1013
1040
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
1014
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
1041
+ assert_eq ! ( layout :: get_slot ( packet. data ( ) ) , Some ( shred. slot( ) ) ) ;
1015
1042
assert_eq ! (
1016
1043
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
1017
1044
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -1050,7 +1077,7 @@ mod tests {
1050
1077
assert_eq ! ( shred. last_in_slot( ) , is_last_in_slot) ;
1051
1078
assert_eq ! ( shred. reference_tick( ) , reference_tick. min( 63u8 ) ) ;
1052
1079
assert_eq ! (
1053
- Shred :: reference_tick_from_data ( shred. payload( ) ) . unwrap( ) ,
1080
+ layout :: get_reference_tick ( shred. payload( ) ) . unwrap( ) ,
1054
1081
reference_tick. min( 63u8 ) ,
1055
1082
) ;
1056
1083
}
0 commit comments