14
14
} ,
15
15
solana_vote_program:: vote_instruction:: VoteInstruction ,
16
16
std:: {
17
+ cmp,
17
18
collections:: HashMap ,
18
19
ops:: DerefMut ,
19
20
sync:: {
@@ -166,12 +167,13 @@ impl LatestUnprocessedVotes {
166
167
pub ( crate ) fn insert_batch (
167
168
& self ,
168
169
votes : impl Iterator < Item = LatestValidatorVotePacket > ,
170
+ should_replenish_taken_votes : bool ,
169
171
) -> VoteBatchInsertionMetrics {
170
172
let mut num_dropped_gossip = 0 ;
171
173
let mut num_dropped_tpu = 0 ;
172
174
173
175
for vote in votes {
174
- if let Some ( vote) = self . update_latest_vote ( vote) {
176
+ if let Some ( vote) = self . update_latest_vote ( vote, should_replenish_taken_votes ) {
175
177
match vote. vote_source {
176
178
VoteSource :: Gossip => num_dropped_gossip += 1 ,
177
179
VoteSource :: Tpu => num_dropped_tpu += 1 ,
@@ -199,26 +201,41 @@ impl LatestUnprocessedVotes {
199
201
pub fn update_latest_vote (
200
202
& self ,
201
203
vote : LatestValidatorVotePacket ,
204
+ should_replenish_taken_votes : bool ,
202
205
) -> Option < LatestValidatorVotePacket > {
203
206
let pubkey = vote. pubkey ( ) ;
204
207
let slot = vote. slot ( ) ;
205
208
let timestamp = vote. timestamp ( ) ;
206
209
210
+ // Allow votes for later slots or the same slot with later timestamp (refreshed votes)
211
+ // We directly compare as options to prioritize votes for same slot with timestamp as
212
+ // Some > None
213
+ let allow_update = |latest_vote : & LatestValidatorVotePacket | -> bool {
214
+ match slot. cmp ( & latest_vote. slot ( ) ) {
215
+ cmp:: Ordering :: Less => return false ,
216
+ cmp:: Ordering :: Greater => return true ,
217
+ cmp:: Ordering :: Equal => { }
218
+ } ;
219
+
220
+ // Slots are equal, now check timestamp
221
+ match timestamp. cmp ( & latest_vote. timestamp ( ) ) {
222
+ cmp:: Ordering :: Less => return false ,
223
+ cmp:: Ordering :: Greater => return true ,
224
+ cmp:: Ordering :: Equal => { }
225
+ } ;
226
+
227
+ // Timestamps are equal, lastly check if vote was taken previously
228
+ // and should be replenished
229
+ should_replenish_taken_votes && latest_vote. is_vote_taken ( )
230
+ } ;
231
+
207
232
let with_latest_vote = |latest_vote : & RwLock < LatestValidatorVotePacket > ,
208
233
vote : LatestValidatorVotePacket |
209
234
-> Option < LatestValidatorVotePacket > {
210
- let ( latest_slot, latest_timestamp) = latest_vote
211
- . read ( )
212
- . map ( |vote| ( vote. slot ( ) , vote. timestamp ( ) ) )
213
- . unwrap ( ) ;
214
- // Allow votes for later slots or the same slot with later timestamp (refreshed votes)
215
- // We directly compare as options to prioritize votes for same slot with timestamp as
216
- // Some > None
217
- if slot > latest_slot || ( ( slot == latest_slot) && ( timestamp > latest_timestamp) ) {
235
+ let should_try_update = allow_update ( & latest_vote. read ( ) . unwrap ( ) ) ;
236
+ if should_try_update {
218
237
let mut latest_vote = latest_vote. write ( ) . unwrap ( ) ;
219
- let latest_slot = latest_vote. slot ( ) ;
220
- let latest_timestamp = latest_vote. timestamp ( ) ;
221
- if slot > latest_slot || ( ( slot == latest_slot) && ( timestamp > latest_timestamp) ) {
238
+ if allow_update ( & latest_vote) {
222
239
let old_vote = std:: mem:: replace ( latest_vote. deref_mut ( ) , vote) ;
223
240
if old_vote. is_vote_taken ( ) {
224
241
self . num_unprocessed_votes . fetch_add ( 1 , Ordering :: Relaxed ) ;
@@ -536,10 +553,10 @@ mod tests {
536
553
) ;
537
554
538
555
assert ! ( latest_unprocessed_votes
539
- . update_latest_vote( vote_a)
556
+ . update_latest_vote( vote_a, false /* should replenish */ )
540
557
. is_none( ) ) ;
541
558
assert ! ( latest_unprocessed_votes
542
- . update_latest_vote( vote_b)
559
+ . update_latest_vote( vote_b, false /* should replenish */ )
543
560
. is_none( ) ) ;
544
561
assert_eq ! ( 2 , latest_unprocessed_votes. len( ) ) ;
545
562
@@ -569,15 +586,15 @@ mod tests {
569
586
assert_eq ! (
570
587
1 ,
571
588
latest_unprocessed_votes
572
- . update_latest_vote( vote_a)
589
+ . update_latest_vote( vote_a, false /* should replenish */ )
573
590
. unwrap( )
574
591
. slot
575
592
) ;
576
593
// Drop current vote
577
594
assert_eq ! (
578
595
6 ,
579
596
latest_unprocessed_votes
580
- . update_latest_vote( vote_b)
597
+ . update_latest_vote( vote_b, false /* should replenish */ )
581
598
. unwrap( )
582
599
. slot
583
600
) ;
@@ -597,8 +614,8 @@ mod tests {
597
614
& keypair_b,
598
615
None ,
599
616
) ;
600
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
601
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
617
+ latest_unprocessed_votes. update_latest_vote ( vote_a, false /* should replenish */ ) ;
618
+ latest_unprocessed_votes. update_latest_vote ( vote_b, false /* should replenish */ ) ;
602
619
603
620
assert_eq ! ( 2 , latest_unprocessed_votes. len( ) ) ;
604
621
assert_eq ! (
@@ -627,8 +644,8 @@ mod tests {
627
644
& keypair_b,
628
645
Some ( 2 ) ,
629
646
) ;
630
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
631
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
647
+ latest_unprocessed_votes. update_latest_vote ( vote_a, false /* should replenish */ ) ;
648
+ latest_unprocessed_votes. update_latest_vote ( vote_b, false /* should replenish */ ) ;
632
649
633
650
assert_eq ! ( 2 , latest_unprocessed_votes. len( ) ) ;
634
651
assert_eq ! (
@@ -653,8 +670,8 @@ mod tests {
653
670
& keypair_b,
654
671
Some ( 6 ) ,
655
672
) ;
656
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
657
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
673
+ latest_unprocessed_votes. update_latest_vote ( vote_a, false /* should replenish */ ) ;
674
+ latest_unprocessed_votes. update_latest_vote ( vote_b, false /* should replenish */ ) ;
658
675
659
676
assert_eq ! ( 2 , latest_unprocessed_votes. len( ) ) ;
660
677
assert_eq ! (
@@ -679,8 +696,10 @@ mod tests {
679
696
& keypair_b,
680
697
Some ( 3 ) ,
681
698
) ;
682
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
683
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
699
+ latest_unprocessed_votes
700
+ . update_latest_vote ( vote_a. clone ( ) , false /* should replenish */ ) ;
701
+ latest_unprocessed_votes
702
+ . update_latest_vote ( vote_b. clone ( ) , false /* should replenish */ ) ;
684
703
685
704
assert_eq ! ( 2 , latest_unprocessed_votes. len( ) ) ;
686
705
assert_eq ! (
@@ -691,6 +710,33 @@ mod tests {
691
710
Some ( 6 ) ,
692
711
latest_unprocessed_votes. get_latest_timestamp( keypair_b. node_keypair. pubkey( ) )
693
712
) ;
713
+
714
+ // Drain all latest votes
715
+ for packet in latest_unprocessed_votes
716
+ . latest_votes_per_pubkey
717
+ . read ( )
718
+ . unwrap ( )
719
+ . values ( )
720
+ {
721
+ packet. write ( ) . unwrap ( ) . take_vote ( ) . inspect ( |_vote| {
722
+ latest_unprocessed_votes
723
+ . num_unprocessed_votes
724
+ . fetch_sub ( 1 , Ordering :: Relaxed ) ;
725
+ } ) ;
726
+ }
727
+ assert_eq ! ( 0 , latest_unprocessed_votes. len( ) ) ;
728
+
729
+ // Same votes with same timestamps should not replenish without flag
730
+ latest_unprocessed_votes
731
+ . update_latest_vote ( vote_a. clone ( ) , false /* should replenish */ ) ;
732
+ latest_unprocessed_votes
733
+ . update_latest_vote ( vote_b. clone ( ) , false /* should replenish */ ) ;
734
+ assert_eq ! ( 0 , latest_unprocessed_votes. len( ) ) ;
735
+
736
+ // Same votes with same timestamps should replenish with the flag
737
+ latest_unprocessed_votes. update_latest_vote ( vote_a, true /* should replenish */ ) ;
738
+ latest_unprocessed_votes. update_latest_vote ( vote_b, true /* should replenish */ ) ;
739
+ assert_eq ! ( 0 , latest_unprocessed_votes. len( ) ) ;
694
740
}
695
741
696
742
#[ test]
@@ -711,7 +757,7 @@ mod tests {
711
757
keypairs : & Arc < Vec < ValidatorVoteKeypairs > > ,
712
758
i : usize | {
713
759
let vote = from_slots ( vec ! [ ( i as u64 , 1 ) ] , VoteSource :: Gossip , & keypairs[ i] , None ) ;
714
- latest_unprocessed_votes. update_latest_vote ( vote) ;
760
+ latest_unprocessed_votes. update_latest_vote ( vote, false /* should replenish */ ) ;
715
761
} ;
716
762
717
763
let hdl = Builder :: new ( )
@@ -756,7 +802,8 @@ mod tests {
756
802
& keypairs[ rng. gen_range ( 0 ..10 ) ] ,
757
803
None ,
758
804
) ;
759
- latest_unprocessed_votes. update_latest_vote ( vote) ;
805
+ latest_unprocessed_votes
806
+ . update_latest_vote ( vote, false /* should replenish */ ) ;
760
807
}
761
808
} )
762
809
. unwrap ( ) ;
@@ -771,7 +818,8 @@ mod tests {
771
818
& keypairs_tpu[ rng. gen_range ( 0 ..10 ) ] ,
772
819
None ,
773
820
) ;
774
- latest_unprocessed_votes_tpu. update_latest_vote ( vote) ;
821
+ latest_unprocessed_votes_tpu
822
+ . update_latest_vote ( vote, false /* should replenish */ ) ;
775
823
if i % 214 == 0 {
776
824
// Simulate draining and processing packets
777
825
let latest_votes_per_pubkey = latest_unprocessed_votes_tpu
@@ -807,8 +855,8 @@ mod tests {
807
855
808
856
let vote_a = from_slots ( vec ! [ ( 1 , 1 ) ] , VoteSource :: Gossip , & keypair_a, None ) ;
809
857
let vote_b = from_slots ( vec ! [ ( 2 , 1 ) ] , VoteSource :: Tpu , & keypair_b, None ) ;
810
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
811
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
858
+ latest_unprocessed_votes. update_latest_vote ( vote_a, false /* should replenish */ ) ;
859
+ latest_unprocessed_votes. update_latest_vote ( vote_b, false /* should replenish */ ) ;
812
860
813
861
// Don't forward 0 stake accounts
814
862
let forwarded = latest_unprocessed_votes
@@ -902,10 +950,10 @@ mod tests {
902
950
let vote_c = from_slots ( vec ! [ ( 3 , 1 ) ] , VoteSource :: Tpu , & keypair_c, None ) ;
903
951
let vote_d = from_slots ( vec ! [ ( 4 , 1 ) ] , VoteSource :: Gossip , & keypair_d, None ) ;
904
952
905
- latest_unprocessed_votes. update_latest_vote ( vote_a) ;
906
- latest_unprocessed_votes. update_latest_vote ( vote_b) ;
907
- latest_unprocessed_votes. update_latest_vote ( vote_c) ;
908
- latest_unprocessed_votes. update_latest_vote ( vote_d) ;
953
+ latest_unprocessed_votes. update_latest_vote ( vote_a, false /* should replenish */ ) ;
954
+ latest_unprocessed_votes. update_latest_vote ( vote_b, false /* should replenish */ ) ;
955
+ latest_unprocessed_votes. update_latest_vote ( vote_c, false /* should replenish */ ) ;
956
+ latest_unprocessed_votes. update_latest_vote ( vote_d, false /* should replenish */ ) ;
909
957
assert_eq ! ( 4 , latest_unprocessed_votes. len( ) ) ;
910
958
911
959
latest_unprocessed_votes. clear_forwarded_packets ( ) ;
0 commit comments