1
1
use {
2
2
crate :: {
3
- cluster_info:: MAX_ACCOUNTS_HASHES ,
3
+ cluster_info:: { MAX_ACCOUNTS_HASHES , MAX_CRDS_OBJECT_SIZE } ,
4
4
contact_info:: ContactInfo ,
5
5
deprecated,
6
6
duplicate_shred:: { DuplicateShred , DuplicateShredIndex , MAX_DUPLICATE_SHREDS } ,
7
- epoch_slots:: EpochSlots ,
7
+ epoch_slots:: { CompressedSlots , EpochSlots , MAX_SLOTS_PER_ENTRY } ,
8
8
legacy_contact_info:: LegacyContactInfo ,
9
9
} ,
10
10
bincode:: { serialize, serialized_size} ,
@@ -94,6 +94,7 @@ pub enum CrdsData {
94
94
DuplicateShred ( DuplicateShredIndex , DuplicateShred ) ,
95
95
SnapshotHashes ( SnapshotHashes ) ,
96
96
ContactInfo ( ContactInfo ) ,
97
+ RestartLastVotedForkSlots ( RestartLastVotedForkSlots ) ,
97
98
}
98
99
99
100
impl Sanitize for CrdsData {
@@ -132,6 +133,7 @@ impl Sanitize for CrdsData {
132
133
}
133
134
CrdsData :: SnapshotHashes ( val) => val. sanitize ( ) ,
134
135
CrdsData :: ContactInfo ( node) => node. sanitize ( ) ,
136
+ CrdsData :: RestartLastVotedForkSlots ( slots) => slots. sanitize ( ) ,
135
137
}
136
138
}
137
139
}
@@ -145,7 +147,7 @@ pub(crate) fn new_rand_timestamp<R: Rng>(rng: &mut R) -> u64 {
145
147
impl CrdsData {
146
148
/// New random CrdsData for tests and benchmarks.
147
149
fn new_rand < R : Rng > ( rng : & mut R , pubkey : Option < Pubkey > ) -> CrdsData {
148
- let kind = rng. gen_range ( 0 ..7 ) ;
150
+ let kind = rng. gen_range ( 0 ..8 ) ;
149
151
// TODO: Implement other kinds of CrdsData here.
150
152
// TODO: Assign ranges to each arm proportional to their frequency in
151
153
// the mainnet crds table.
@@ -157,6 +159,9 @@ impl CrdsData {
157
159
3 => CrdsData :: AccountsHashes ( AccountsHashes :: new_rand ( rng, pubkey) ) ,
158
160
4 => CrdsData :: Version ( Version :: new_rand ( rng, pubkey) ) ,
159
161
5 => CrdsData :: Vote ( rng. gen_range ( 0 ..MAX_VOTES ) , Vote :: new_rand ( rng, pubkey) ) ,
162
+ 6 => CrdsData :: RestartLastVotedForkSlots ( RestartLastVotedForkSlots :: new_rand (
163
+ rng, pubkey,
164
+ ) ) ,
160
165
_ => CrdsData :: EpochSlots (
161
166
rng. gen_range ( 0 ..MAX_EPOCH_SLOTS ) ,
162
167
EpochSlots :: new_rand ( rng, pubkey) ,
@@ -485,6 +490,87 @@ impl Sanitize for NodeInstance {
485
490
}
486
491
}
487
492
493
+ #[ derive( Serialize , Deserialize , Clone , Default , PartialEq , Eq , AbiExample , Debug ) ]
494
+ pub struct RestartLastVotedForkSlots {
495
+ pub from : Pubkey ,
496
+ pub wallclock : u64 ,
497
+ pub slots : Vec < CompressedSlots > ,
498
+ pub last_voted_hash : Hash ,
499
+ pub shred_version : u16 ,
500
+ }
501
+
502
+ impl Sanitize for RestartLastVotedForkSlots {
503
+ fn sanitize ( & self ) -> std:: result:: Result < ( ) , SanitizeError > {
504
+ if self . slots . is_empty ( ) {
505
+ return Err ( SanitizeError :: InvalidValue ) ;
506
+ }
507
+ self . slots . sanitize ( ) ?;
508
+ self . last_voted_hash . sanitize ( )
509
+ }
510
+ }
511
+
512
+ impl RestartLastVotedForkSlots {
513
+ pub fn new ( from : Pubkey , now : u64 , last_voted_hash : Hash , shred_version : u16 ) -> Self {
514
+ Self {
515
+ from,
516
+ wallclock : now,
517
+ slots : Vec :: new ( ) ,
518
+ last_voted_hash,
519
+ shred_version,
520
+ }
521
+ }
522
+
523
+ /// New random Version for tests and benchmarks.
524
+ pub fn new_rand < R : Rng > ( rng : & mut R , pubkey : Option < Pubkey > ) -> Self {
525
+ let pubkey = pubkey. unwrap_or_else ( solana_sdk:: pubkey:: new_rand) ;
526
+ let mut result =
527
+ RestartLastVotedForkSlots :: new ( pubkey, new_rand_timestamp ( rng) , Hash :: new_unique ( ) , 1 ) ;
528
+ let num_slots = rng. gen_range ( 2 ..20 ) ;
529
+ let mut slots = std:: iter:: repeat_with ( || 47825632 + rng. gen_range ( 0 ..512 ) )
530
+ . take ( num_slots)
531
+ . collect :: < Vec < Slot > > ( ) ;
532
+ slots. sort ( ) ;
533
+ result. fill ( & slots) ;
534
+ result
535
+ }
536
+
537
+ pub fn fill ( & mut self , slots : & [ Slot ] ) -> usize {
538
+ let slots = & slots[ slots. len ( ) . saturating_sub ( MAX_SLOTS_PER_ENTRY ) ..] ;
539
+ let mut num = 0 ;
540
+ let space = self . max_compressed_slot_size ( ) ;
541
+ if space == 0 {
542
+ return 0 ;
543
+ }
544
+ while num < slots. len ( ) {
545
+ let mut cslot = CompressedSlots :: new ( space as usize ) ;
546
+ num += cslot. add ( & slots[ num..] ) ;
547
+ self . slots . push ( cslot) ;
548
+ }
549
+ num
550
+ }
551
+
552
+ pub fn deflate ( & mut self ) {
553
+ for s in self . slots . iter_mut ( ) {
554
+ let _ = s. deflate ( ) ;
555
+ }
556
+ }
557
+
558
+ pub fn max_compressed_slot_size ( & self ) -> isize {
559
+ let len_header = serialized_size ( self ) . unwrap ( ) ;
560
+ let len_slot = serialized_size ( & CompressedSlots :: default ( ) ) . unwrap ( ) ;
561
+ MAX_CRDS_OBJECT_SIZE as isize - ( len_header + len_slot) as isize
562
+ }
563
+
564
+ pub fn to_slots ( & self , min_slot : Slot ) -> Vec < Slot > {
565
+ self . slots
566
+ . iter ( )
567
+ . filter ( |s| min_slot < s. first_slot ( ) + s. num_slots ( ) as u64 )
568
+ . filter_map ( |s| s. to_slots ( min_slot) . ok ( ) )
569
+ . flatten ( )
570
+ . collect ( )
571
+ }
572
+ }
573
+
488
574
/// Type of the replicated value
489
575
/// These are labels for values in a record that is associated with `Pubkey`
490
576
#[ derive( PartialEq , Hash , Eq , Clone , Debug ) ]
@@ -501,6 +587,7 @@ pub enum CrdsValueLabel {
501
587
DuplicateShred ( DuplicateShredIndex , Pubkey ) ,
502
588
SnapshotHashes ( Pubkey ) ,
503
589
ContactInfo ( Pubkey ) ,
590
+ RestartLastVotedForkSlots ( Pubkey ) ,
504
591
}
505
592
506
593
impl fmt:: Display for CrdsValueLabel {
@@ -524,6 +611,9 @@ impl fmt::Display for CrdsValueLabel {
524
611
write ! ( f, "SnapshotHashes({})" , self . pubkey( ) )
525
612
}
526
613
CrdsValueLabel :: ContactInfo ( _) => write ! ( f, "ContactInfo({})" , self . pubkey( ) ) ,
614
+ CrdsValueLabel :: RestartLastVotedForkSlots ( _) => {
615
+ write ! ( f, "RestartLastVotedForkSlots({})" , self . pubkey( ) )
616
+ }
527
617
}
528
618
}
529
619
}
@@ -543,6 +633,7 @@ impl CrdsValueLabel {
543
633
CrdsValueLabel :: DuplicateShred ( _, p) => * p,
544
634
CrdsValueLabel :: SnapshotHashes ( p) => * p,
545
635
CrdsValueLabel :: ContactInfo ( pubkey) => * pubkey,
636
+ CrdsValueLabel :: RestartLastVotedForkSlots ( p) => * p,
546
637
}
547
638
}
548
639
}
@@ -593,6 +684,7 @@ impl CrdsValue {
593
684
CrdsData :: DuplicateShred ( _, shred) => shred. wallclock ,
594
685
CrdsData :: SnapshotHashes ( hash) => hash. wallclock ,
595
686
CrdsData :: ContactInfo ( node) => node. wallclock ( ) ,
687
+ CrdsData :: RestartLastVotedForkSlots ( slots) => slots. wallclock ,
596
688
}
597
689
}
598
690
pub fn pubkey ( & self ) -> Pubkey {
@@ -609,6 +701,7 @@ impl CrdsValue {
609
701
CrdsData :: DuplicateShred ( _, shred) => shred. from ,
610
702
CrdsData :: SnapshotHashes ( hash) => hash. from ,
611
703
CrdsData :: ContactInfo ( node) => * node. pubkey ( ) ,
704
+ CrdsData :: RestartLastVotedForkSlots ( slots) => slots. from ,
612
705
}
613
706
}
614
707
pub fn label ( & self ) -> CrdsValueLabel {
@@ -627,6 +720,9 @@ impl CrdsValue {
627
720
CrdsData :: DuplicateShred ( ix, shred) => CrdsValueLabel :: DuplicateShred ( * ix, shred. from ) ,
628
721
CrdsData :: SnapshotHashes ( _) => CrdsValueLabel :: SnapshotHashes ( self . pubkey ( ) ) ,
629
722
CrdsData :: ContactInfo ( node) => CrdsValueLabel :: ContactInfo ( * node. pubkey ( ) ) ,
723
+ CrdsData :: RestartLastVotedForkSlots ( _) => {
724
+ CrdsValueLabel :: RestartLastVotedForkSlots ( self . pubkey ( ) )
725
+ }
630
726
}
631
727
}
632
728
pub fn contact_info ( & self ) -> Option < & LegacyContactInfo > {
@@ -1073,4 +1169,58 @@ mod test {
1073
1169
assert ! ( node. should_force_push( & pubkey) ) ;
1074
1170
assert ! ( !node. should_force_push( & Pubkey :: new_unique( ) ) ) ;
1075
1171
}
1172
+
1173
+ #[ test]
1174
+ fn test_restart_last_voted_fork_slots ( ) {
1175
+ let keypair = Keypair :: new ( ) ;
1176
+ let slot = 53 ;
1177
+ let slot_parent = slot - 5 ;
1178
+ let shred_version = 21 ;
1179
+ let mut slots = RestartLastVotedForkSlots :: new (
1180
+ keypair. pubkey ( ) ,
1181
+ timestamp ( ) ,
1182
+ Hash :: default ( ) ,
1183
+ shred_version,
1184
+ ) ;
1185
+ let original_slots_vec = [ slot_parent, slot] ;
1186
+ slots. fill ( & original_slots_vec) ;
1187
+ let value =
1188
+ CrdsValue :: new_signed ( CrdsData :: RestartLastVotedForkSlots ( slots. clone ( ) ) , & keypair) ;
1189
+ assert_eq ! ( value. sanitize( ) , Ok ( ( ) ) ) ;
1190
+ let label = value. label ( ) ;
1191
+ assert_eq ! (
1192
+ label,
1193
+ CrdsValueLabel :: RestartLastVotedForkSlots ( keypair. pubkey( ) )
1194
+ ) ;
1195
+ assert_eq ! ( label. pubkey( ) , keypair. pubkey( ) ) ;
1196
+ assert_eq ! ( value. wallclock( ) , slots. wallclock) ;
1197
+ let retrived_slots = slots. to_slots ( 0 ) ;
1198
+ assert_eq ! ( retrived_slots. len( ) , 2 ) ;
1199
+ assert_eq ! ( retrived_slots[ 0 ] , slot_parent) ;
1200
+ assert_eq ! ( retrived_slots[ 1 ] , slot) ;
1201
+
1202
+ let empty_slots = RestartLastVotedForkSlots :: new (
1203
+ keypair. pubkey ( ) ,
1204
+ timestamp ( ) ,
1205
+ Hash :: default ( ) ,
1206
+ shred_version,
1207
+ ) ;
1208
+ let bad_value =
1209
+ CrdsValue :: new_signed ( CrdsData :: RestartLastVotedForkSlots ( empty_slots) , & keypair) ;
1210
+ assert_eq ! ( bad_value. sanitize( ) , Err ( SanitizeError :: InvalidValue ) ) ;
1211
+
1212
+ let last_slot: Slot = ( MAX_SLOTS_PER_ENTRY + 10 ) . try_into ( ) . unwrap ( ) ;
1213
+ let mut large_slots = RestartLastVotedForkSlots :: new (
1214
+ keypair. pubkey ( ) ,
1215
+ timestamp ( ) ,
1216
+ Hash :: default ( ) ,
1217
+ shred_version,
1218
+ ) ;
1219
+ let large_slots_vec: Vec < Slot > = ( 0 ..last_slot + 1 ) . collect ( ) ;
1220
+ large_slots. fill ( & large_slots_vec) ;
1221
+ let retrived_slots = large_slots. to_slots ( 0 ) ;
1222
+ assert_eq ! ( retrived_slots. len( ) , MAX_SLOTS_PER_ENTRY ) ;
1223
+ assert_eq ! ( retrived_slots. first( ) , Some ( & 11 ) ) ;
1224
+ assert_eq ! ( retrived_slots. last( ) , Some ( & last_slot) ) ;
1225
+ }
1076
1226
}
0 commit comments