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_sdk:: {
61
61
clock:: Slot ,
62
62
hash:: { hashv, Hash } ,
@@ -315,7 +315,7 @@ impl Shred {
315
315
}
316
316
317
317
pub fn new_from_serialized_shred ( shred : Vec < u8 > ) -> Result < Self , Error > {
318
- Ok ( match Self :: shred_type_from_payload ( & shred) ? {
318
+ Ok ( match layout :: get_shred_type ( & shred) ? {
319
319
ShredType :: Code => Self :: from ( ShredCode :: from_payload ( shred) ?) ,
320
320
ShredType :: Data => Self :: from ( ShredData :: from_payload ( shred) ?) ,
321
321
} )
@@ -381,7 +381,7 @@ impl Shred {
381
381
382
382
// Possibly zero pads bytes stored in blockstore.
383
383
pub ( crate ) fn resize_stored_shred ( shred : Vec < u8 > ) -> Result < Vec < u8 > , Error > {
384
- match Self :: shred_type_from_payload ( & shred) ? {
384
+ match layout :: get_shred_type ( & shred) ? {
385
385
ShredType :: Code => ShredCode :: resize_stored_shred ( shred) ,
386
386
ShredType :: Data => ShredData :: resize_stored_shred ( shred) ,
387
387
}
@@ -430,16 +430,6 @@ impl Shred {
430
430
self . common_header ( ) . shred_type
431
431
}
432
432
433
- fn shred_type_from_payload ( shred : & [ u8 ] ) -> Result < ShredType , Error > {
434
- match shred. get ( OFFSET_OF_SHRED_TYPE ) {
435
- None => Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
436
- Some ( shred_type) => match ShredType :: try_from ( * shred_type) {
437
- Err ( _) => Err ( Error :: InvalidShredType ) ,
438
- Ok ( shred_type) => Ok ( shred_type) ,
439
- } ,
440
- }
441
- }
442
-
443
433
pub fn is_data ( & self ) -> bool {
444
434
self . shred_type ( ) == ShredType :: Data
445
435
}
@@ -477,25 +467,6 @@ impl Shred {
477
467
}
478
468
}
479
469
480
- // Get slot from a shred packet with partial deserialize
481
- pub fn get_slot_from_packet ( p : & Packet ) -> Option < Slot > {
482
- let slot_start = OFFSET_OF_SHRED_SLOT ;
483
- let slot_end = slot_start + SIZE_OF_SHRED_SLOT ;
484
- p. deserialize_slice ( slot_start..slot_end) . ok ( )
485
- }
486
-
487
- pub ( crate ) fn reference_tick_from_data ( data : & [ u8 ] ) -> Result < u8 , Error > {
488
- const SHRED_FLAGS_OFFSET : usize = SIZE_OF_COMMON_SHRED_HEADER + std:: mem:: size_of :: < u16 > ( ) ;
489
- if Self :: shred_type_from_payload ( data) ? != ShredType :: Data {
490
- return Err ( Error :: InvalidShredType ) ;
491
- }
492
- let flags = match data. get ( SHRED_FLAGS_OFFSET ) {
493
- None => return Err ( Error :: InvalidPayloadSize ( data. len ( ) ) ) ,
494
- Some ( flags) => flags,
495
- } ;
496
- Ok ( flags & ShredFlags :: SHRED_TICK_REFERENCE_MASK . bits ( ) )
497
- }
498
-
499
470
pub fn verify ( & self , pubkey : & Pubkey ) -> bool {
500
471
let message = self . signed_payload ( ) ;
501
472
self . signature ( ) . verify ( pubkey. as_ref ( ) , message)
@@ -524,6 +495,73 @@ impl Shred {
524
495
}
525
496
}
526
497
498
+ // Helper methods to extract pieces of the shred from the payload
499
+ // without deserializing the entire payload.
500
+ pub mod layout {
501
+ use { super :: * , std:: ops:: Range } ;
502
+
503
+ fn get_shred_size ( packet : & Packet ) -> usize {
504
+ if packet. meta . repair ( ) {
505
+ packet. meta . size . saturating_sub ( SIZE_OF_NONCE )
506
+ } else {
507
+ packet. meta . size
508
+ }
509
+ }
510
+
511
+ pub fn get_shred ( packet : & Packet ) -> & [ u8 ] {
512
+ & packet. data [ ..get_shred_size ( packet) ]
513
+ }
514
+
515
+ pub ( crate ) fn get_signature ( shred : & [ u8 ] ) -> Option < Signature > {
516
+ Some ( Signature :: new ( shred. get ( ..SIZE_OF_SIGNATURE ) ?) )
517
+ }
518
+
519
+ pub ( crate ) const fn get_signature_range ( ) -> Range < usize > {
520
+ 0 ..SIZE_OF_SIGNATURE
521
+ }
522
+
523
+ pub ( super ) fn get_shred_type ( shred : & [ u8 ] ) -> Result < ShredType , Error > {
524
+ match shred. get ( OFFSET_OF_SHRED_TYPE ) {
525
+ None => Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
526
+ Some ( shred_type) => match ShredType :: try_from ( * shred_type) {
527
+ Err ( _) => Err ( Error :: InvalidShredType ) ,
528
+ Ok ( shred_type) => Ok ( shred_type) ,
529
+ } ,
530
+ }
531
+ }
532
+
533
+ pub fn get_slot ( shred : & [ u8 ] ) -> Option < Slot > {
534
+ deserialize_from_with_limit ( shred. get ( OFFSET_OF_SHRED_SLOT ..) ?) . ok ( )
535
+ }
536
+
537
+ pub ( super ) fn get_index ( shred : & [ u8 ] ) -> Option < u32 > {
538
+ deserialize_from_with_limit ( shred. get ( OFFSET_OF_SHRED_INDEX ..) ?) . ok ( )
539
+ }
540
+
541
+ // Returns chunk of the payload which is signed.
542
+ pub ( crate ) fn get_signed_message ( shred : & [ u8 ] ) -> Option < & [ u8 ] > {
543
+ shred. get ( SIZE_OF_SIGNATURE ..)
544
+ }
545
+
546
+ // Returns slice range of the packet payload which is signed.
547
+ pub ( crate ) fn get_signed_message_range ( packet : & Packet ) -> Range < usize > {
548
+ SIZE_OF_SIGNATURE ..get_shred_size ( packet)
549
+ }
550
+
551
+ pub ( crate ) fn get_reference_tick ( shred : & [ u8 ] ) -> Result < u8 , Error > {
552
+ const SIZE_OF_PARENT_OFFSET : usize = std:: mem:: size_of :: < u16 > ( ) ;
553
+ const OFFSET_OF_SHRED_FLAGS : usize = SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_PARENT_OFFSET ;
554
+ if get_shred_type ( shred) ? != ShredType :: Data {
555
+ return Err ( Error :: InvalidShredType ) ;
556
+ }
557
+ let flags = match shred. get ( OFFSET_OF_SHRED_FLAGS ) {
558
+ None => return Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ,
559
+ Some ( flags) => flags,
560
+ } ;
561
+ Ok ( flags & ShredFlags :: SHRED_TICK_REFERENCE_MASK . bits ( ) )
562
+ }
563
+ }
564
+
527
565
impl From < ShredCode > for Shred {
528
566
fn from ( shred : ShredCode ) -> Self {
529
567
Self :: ShredCode ( shred)
@@ -538,50 +576,39 @@ impl From<ShredData> for Shred {
538
576
539
577
// Get slot, index, and type from a packet with partial deserialize
540
578
pub fn get_shred_slot_index_type (
541
- p : & Packet ,
579
+ packet : & Packet ,
542
580
stats : & mut ShredFetchStats ,
543
581
) -> Option < ( Slot , u32 , ShredType ) > {
544
- let index_start = OFFSET_OF_SHRED_INDEX ;
545
- let index_end = index_start + SIZE_OF_SHRED_INDEX ;
546
- let slot_start = OFFSET_OF_SHRED_SLOT ;
547
- let slot_end = slot_start + SIZE_OF_SHRED_SLOT ;
548
-
549
- debug_assert ! ( index_end > slot_end) ;
550
- debug_assert ! ( index_end > OFFSET_OF_SHRED_TYPE ) ;
551
-
552
- if index_end > p. meta . size {
582
+ let shred = layout:: get_shred ( packet) ;
583
+ if OFFSET_OF_SHRED_INDEX + SIZE_OF_SHRED_INDEX > shred. len ( ) {
553
584
stats. index_overrun += 1 ;
554
585
return None ;
555
586
}
556
-
557
- let index = match p. deserialize_slice ( index_start..index_end) {
558
- Ok ( x) => x,
559
- Err ( _e) => {
560
- stats. index_bad_deserialize += 1 ;
587
+ let shred_type = match layout:: get_shred_type ( shred) {
588
+ Ok ( shred_type) => shred_type,
589
+ Err ( _) => {
590
+ stats. bad_shred_type += 1 ;
561
591
return None ;
562
592
}
563
593
} ;
564
-
565
- if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
566
- stats. index_out_of_bounds += 1 ;
567
- return None ;
568
- }
569
-
570
- let slot = match p. deserialize_slice ( slot_start..slot_end) {
571
- Ok ( x) => x,
572
- Err ( _e) => {
594
+ let slot = match layout:: get_slot ( shred) {
595
+ Some ( slot) => slot,
596
+ None => {
573
597
stats. slot_bad_deserialize += 1 ;
574
598
return None ;
575
599
}
576
600
} ;
577
-
578
- let shred_type = match ShredType :: try_from ( p . data [ OFFSET_OF_SHRED_TYPE ] ) {
579
- Err ( _ ) => {
580
- stats. bad_shred_type += 1 ;
601
+ let index = match layout :: get_index ( shred ) {
602
+ Some ( index ) => index ,
603
+ None => {
604
+ stats. index_bad_deserialize += 1 ;
581
605
return None ;
582
606
}
583
- Ok ( shred_type) => shred_type,
584
607
} ;
608
+ if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
609
+ stats. index_out_of_bounds += 1 ;
610
+ return None ;
611
+ }
585
612
Some ( ( slot, index, shred_type) )
586
613
}
587
614
@@ -898,9 +925,9 @@ mod tests {
898
925
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
899
926
assert_eq ! (
900
927
shred. reference_tick( ) ,
901
- Shred :: reference_tick_from_data ( & packet. data) . unwrap( )
928
+ layout :: get_reference_tick ( & packet. data) . unwrap( )
902
929
) ;
903
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
930
+ assert_eq ! ( layout :: get_slot ( & packet. data ) , Some ( shred. slot( ) ) ) ;
904
931
assert_eq ! (
905
932
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
906
933
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -939,9 +966,9 @@ mod tests {
939
966
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
940
967
assert_eq ! (
941
968
shred. reference_tick( ) ,
942
- Shred :: reference_tick_from_data ( & packet. data) . unwrap( )
969
+ layout :: get_reference_tick ( & packet. data) . unwrap( )
943
970
) ;
944
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
971
+ assert_eq ! ( layout :: get_slot ( & packet. data ) , Some ( shred. slot( ) ) ) ;
945
972
assert_eq ! (
946
973
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
947
974
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -985,7 +1012,7 @@ mod tests {
985
1012
packet. meta . size = payload. len ( ) ;
986
1013
assert_eq ! ( shred. bytes_to_store( ) , payload) ;
987
1014
assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
988
- assert_eq ! ( Shred :: get_slot_from_packet ( & packet) , Some ( shred. slot( ) ) ) ;
1015
+ assert_eq ! ( layout :: get_slot ( & packet. data ) , Some ( shred. slot( ) ) ) ;
989
1016
assert_eq ! (
990
1017
get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
991
1018
Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
@@ -1024,7 +1051,7 @@ mod tests {
1024
1051
assert_eq ! ( shred. last_in_slot( ) , is_last_in_slot) ;
1025
1052
assert_eq ! ( shred. reference_tick( ) , reference_tick. min( 63u8 ) ) ;
1026
1053
assert_eq ! (
1027
- Shred :: reference_tick_from_data ( shred. payload( ) ) . unwrap( ) ,
1054
+ layout :: get_reference_tick ( shred. payload( ) ) . unwrap( ) ,
1028
1055
reference_tick. min( 63u8 ) ,
1029
1056
) ;
1030
1057
}
0 commit comments