1use {
2 crate::consensus::{tower_vote_state::TowerVoteState, Stake},
3 crossbeam_channel::{unbounded, Receiver, RecvTimeoutError, Sender},
4 solana_clock::Slot,
5 solana_measure::measure::Measure,
6 solana_metrics::datapoint_info,
7 solana_pubkey::Pubkey,
8 solana_rpc::rpc_subscriptions::RpcSubscriptions,
9 solana_runtime::{
10 bank::Bank,
11 commitment::{BlockCommitment, BlockCommitmentCache, CommitmentSlots, VOTE_THRESHOLD_SIZE},
12 },
13 std::{
14 cmp::max,
15 collections::HashMap,
16 sync::{
17 atomic::{AtomicBool, Ordering},
18 Arc, RwLock,
19 },
20 thread::{self, Builder, JoinHandle},
21 time::Duration,
22 },
23};
24
25pub struct CommitmentAggregationData {
26 bank: Arc<Bank>,
27 root: Slot,
28 total_stake: Stake,
29 node_vote_state: (Pubkey, TowerVoteState),
32}
33
34impl CommitmentAggregationData {
35 pub fn new(
36 bank: Arc<Bank>,
37 root: Slot,
38 total_stake: Stake,
39 node_vote_state: (Pubkey, TowerVoteState),
40 ) -> Self {
41 Self {
42 bank,
43 root,
44 total_stake,
45 node_vote_state,
46 }
47 }
48}
49
50fn get_highest_super_majority_root(mut rooted_stake: Vec<(Slot, u64)>, total_stake: u64) -> Slot {
51 rooted_stake.sort_by(|a, b| a.0.cmp(&b.0).reverse());
52 let mut stake_sum = 0;
53 for (root, stake) in rooted_stake {
54 stake_sum += stake;
55 if (stake_sum as f64 / total_stake as f64) > VOTE_THRESHOLD_SIZE {
56 return root;
57 }
58 }
59 0
60}
61
62pub struct AggregateCommitmentService {
63 t_commitment: JoinHandle<()>,
64}
65
66impl AggregateCommitmentService {
67 pub fn new(
68 exit: Arc<AtomicBool>,
69 block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
70 subscriptions: Option<Arc<RpcSubscriptions>>,
71 ) -> (Sender<CommitmentAggregationData>, Self) {
72 let (sender, receiver): (
73 Sender<CommitmentAggregationData>,
74 Receiver<CommitmentAggregationData>,
75 ) = unbounded();
76 (
77 sender,
78 Self {
79 t_commitment: Builder::new()
80 .name("solAggCommitSvc".to_string())
81 .spawn(move || loop {
82 if exit.load(Ordering::Relaxed) {
83 break;
84 }
85
86 if let Err(RecvTimeoutError::Disconnected) = Self::run(
87 &receiver,
88 &block_commitment_cache,
89 subscriptions.as_deref(),
90 &exit,
91 ) {
92 break;
93 }
94 })
95 .unwrap(),
96 },
97 )
98 }
99
100 fn run(
101 receiver: &Receiver<CommitmentAggregationData>,
102 block_commitment_cache: &RwLock<BlockCommitmentCache>,
103 rpc_subscriptions: Option<&RpcSubscriptions>,
104 exit: &AtomicBool,
105 ) -> Result<(), RecvTimeoutError> {
106 loop {
107 if exit.load(Ordering::Relaxed) {
108 return Ok(());
109 }
110
111 let aggregation_data = receiver.recv_timeout(Duration::from_secs(1))?;
112 let aggregation_data = receiver.try_iter().last().unwrap_or(aggregation_data);
113
114 let ancestors = aggregation_data.bank.status_cache_ancestors();
115 if ancestors.is_empty() {
116 continue;
117 }
118
119 let mut aggregate_commitment_time = Measure::start("aggregate-commitment-ms");
120 let update_commitment_slots =
121 Self::update_commitment_cache(block_commitment_cache, aggregation_data, ancestors);
122 aggregate_commitment_time.stop();
123 datapoint_info!(
124 "block-commitment-cache",
125 (
126 "aggregate-commitment-ms",
127 aggregate_commitment_time.as_ms() as i64,
128 i64
129 ),
130 (
131 "highest-super-majority-root",
132 update_commitment_slots.highest_super_majority_root as i64,
133 i64
134 ),
135 (
136 "highest-confirmed-slot",
137 update_commitment_slots.highest_confirmed_slot as i64,
138 i64
139 ),
140 );
141
142 if let Some(rpc_subscriptions) = rpc_subscriptions {
143 rpc_subscriptions.notify_subscribers(update_commitment_slots);
147 }
148 }
149 }
150
151 fn update_commitment_cache(
152 block_commitment_cache: &RwLock<BlockCommitmentCache>,
153 aggregation_data: CommitmentAggregationData,
154 ancestors: Vec<u64>,
155 ) -> CommitmentSlots {
156 let (block_commitment, rooted_stake) = Self::aggregate_commitment(
157 &ancestors,
158 &aggregation_data.bank,
159 &aggregation_data.node_vote_state,
160 );
161
162 let highest_super_majority_root =
163 get_highest_super_majority_root(rooted_stake, aggregation_data.total_stake);
164
165 let mut new_block_commitment = BlockCommitmentCache::new(
166 block_commitment,
167 aggregation_data.total_stake,
168 CommitmentSlots {
169 slot: aggregation_data.bank.slot(),
170 root: aggregation_data.root,
171 highest_confirmed_slot: aggregation_data.root,
172 highest_super_majority_root,
173 },
174 );
175 let highest_confirmed_slot = new_block_commitment.calculate_highest_confirmed_slot();
176 new_block_commitment.set_highest_confirmed_slot(highest_confirmed_slot);
177
178 let mut w_block_commitment_cache = block_commitment_cache.write().unwrap();
179
180 let highest_super_majority_root = max(
181 new_block_commitment.highest_super_majority_root(),
182 w_block_commitment_cache.highest_super_majority_root(),
183 );
184 new_block_commitment.set_highest_super_majority_root(highest_super_majority_root);
185
186 *w_block_commitment_cache = new_block_commitment;
187 w_block_commitment_cache.commitment_slots()
188 }
189
190 pub fn aggregate_commitment(
191 ancestors: &[Slot],
192 bank: &Bank,
193 (node_vote_pubkey, node_vote_state): &(Pubkey, TowerVoteState),
194 ) -> (HashMap<Slot, BlockCommitment>, Vec<(Slot, u64)>) {
195 assert!(!ancestors.is_empty());
196
197 for a in ancestors.windows(2) {
199 assert!(a[0] < a[1]);
200 }
201
202 let mut commitment = HashMap::new();
203 let mut rooted_stake: Vec<(Slot, u64)> = Vec::new();
204 for (pubkey, (lamports, account)) in bank.vote_accounts().iter() {
205 if *lamports == 0 {
206 continue;
207 }
208 let vote_state = if pubkey == node_vote_pubkey {
209 node_vote_state.clone()
211 } else {
212 TowerVoteState::from(account.vote_state_view())
213 };
214 Self::aggregate_commitment_for_vote_account(
215 &mut commitment,
216 &mut rooted_stake,
217 &vote_state,
218 ancestors,
219 *lamports,
220 );
221 }
222
223 (commitment, rooted_stake)
224 }
225
226 fn aggregate_commitment_for_vote_account(
227 commitment: &mut HashMap<Slot, BlockCommitment>,
228 rooted_stake: &mut Vec<(Slot, u64)>,
229 vote_state: &TowerVoteState,
230 ancestors: &[Slot],
231 lamports: u64,
232 ) {
233 assert!(!ancestors.is_empty());
234 let mut ancestors_index = 0;
235 if let Some(root) = vote_state.root_slot {
236 for (i, a) in ancestors.iter().enumerate() {
237 if *a <= root {
238 commitment
239 .entry(*a)
240 .or_default()
241 .increase_rooted_stake(lamports);
242 } else {
243 ancestors_index = i;
244 break;
245 }
246 }
247 rooted_stake.push((root, lamports));
248 }
249
250 for vote in &vote_state.votes {
251 while ancestors[ancestors_index] <= vote.slot() {
252 commitment
253 .entry(ancestors[ancestors_index])
254 .or_default()
255 .increase_confirmation_stake(vote.confirmation_count() as usize, lamports);
256 ancestors_index += 1;
257
258 if ancestors_index == ancestors.len() {
259 return;
260 }
261 }
262 }
263 }
264
265 pub fn join(self) -> thread::Result<()> {
266 self.t_commitment.join()
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use {
273 super::*,
274 solana_account::{state_traits::StateMut, Account, ReadableAccount},
275 solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo},
276 solana_pubkey::Pubkey,
277 solana_runtime::{
278 genesis_utils::{create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs},
279 stake_utils,
280 },
281 solana_signer::Signer,
282 solana_vote::vote_transaction,
283 solana_vote_program::vote_state::{
284 self, process_slot_vote_unchecked, TowerSync, VoteStateV4, VoteStateVersions,
285 MAX_LOCKOUT_HISTORY,
286 },
287 };
288
289 #[test]
290 fn test_get_highest_super_majority_root() {
291 assert_eq!(get_highest_super_majority_root(vec![], 10), 0);
292 let rooted_stake = vec![(0, 5), (1, 5)];
293 assert_eq!(get_highest_super_majority_root(rooted_stake, 10), 0);
294 let rooted_stake = vec![(1, 5), (0, 10), (2, 5), (1, 4)];
295 assert_eq!(get_highest_super_majority_root(rooted_stake, 10), 1);
296 }
297
298 #[test]
299 fn test_aggregate_commitment_for_vote_account_1() {
300 let ancestors = vec![3, 4, 5, 7, 9, 11];
301 let mut commitment = HashMap::new();
302 let mut rooted_stake = vec![];
303 let lamports = 5;
304 let mut vote_state = TowerVoteState::default();
305
306 let root = *ancestors.last().unwrap();
307 vote_state.root_slot = Some(root);
308 AggregateCommitmentService::aggregate_commitment_for_vote_account(
309 &mut commitment,
310 &mut rooted_stake,
311 &vote_state,
312 &ancestors,
313 lamports,
314 );
315
316 for a in ancestors {
317 let mut expected = BlockCommitment::default();
318 expected.increase_rooted_stake(lamports);
319 assert_eq!(*commitment.get(&a).unwrap(), expected);
320 }
321 assert_eq!(rooted_stake[0], (root, lamports));
322 }
323
324 #[test]
325 fn test_aggregate_commitment_for_vote_account_2() {
326 let ancestors = vec![3, 4, 5, 7, 9, 11];
327 let mut commitment = HashMap::new();
328 let mut rooted_stake = vec![];
329 let lamports = 5;
330 let mut vote_state = TowerVoteState::default();
331
332 let root = ancestors[2];
333 vote_state.root_slot = Some(root);
334 vote_state.process_next_vote_slot(*ancestors.last().unwrap());
335 AggregateCommitmentService::aggregate_commitment_for_vote_account(
336 &mut commitment,
337 &mut rooted_stake,
338 &vote_state,
339 &ancestors,
340 lamports,
341 );
342
343 for a in ancestors {
344 let mut expected = BlockCommitment::default();
345 if a <= root {
346 expected.increase_rooted_stake(lamports);
347 } else {
348 expected.increase_confirmation_stake(1, lamports);
349 }
350 assert_eq!(*commitment.get(&a).unwrap(), expected);
351 }
352 assert_eq!(rooted_stake[0], (root, lamports));
353 }
354
355 #[test]
356 fn test_aggregate_commitment_for_vote_account_3() {
357 let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
358 let mut commitment = HashMap::new();
359 let mut rooted_stake = vec![];
360 let lamports = 5;
361 let mut vote_state = TowerVoteState::default();
362
363 let root = ancestors[2];
364 vote_state.root_slot = Some(root);
365 assert!(ancestors[4] + 2 >= ancestors[6]);
366 vote_state.process_next_vote_slot(ancestors[4]);
367 vote_state.process_next_vote_slot(ancestors[6]);
368 AggregateCommitmentService::aggregate_commitment_for_vote_account(
369 &mut commitment,
370 &mut rooted_stake,
371 &vote_state,
372 &ancestors,
373 lamports,
374 );
375
376 for (i, a) in ancestors.iter().enumerate() {
377 if *a <= root {
378 let mut expected = BlockCommitment::default();
379 expected.increase_rooted_stake(lamports);
380 assert_eq!(*commitment.get(a).unwrap(), expected);
381 } else if i <= 4 {
382 let mut expected = BlockCommitment::default();
383 expected.increase_confirmation_stake(2, lamports);
384 assert_eq!(*commitment.get(a).unwrap(), expected);
385 } else if i <= 6 {
386 let mut expected = BlockCommitment::default();
387 expected.increase_confirmation_stake(1, lamports);
388 assert_eq!(*commitment.get(a).unwrap(), expected);
389 }
390 }
391 assert_eq!(rooted_stake[0], (root, lamports));
392 }
393
394 fn do_test_aggregate_commitment_validity(with_node_vote_state: bool) {
395 let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
396 let GenesisConfigInfo {
397 mut genesis_config, ..
398 } = create_genesis_config(10_000);
399
400 let rooted_stake_amount = 40;
401
402 let sk1 = solana_pubkey::new_rand();
403 let pk1 = solana_pubkey::new_rand();
404 let mut vote_account1 = vote_state::create_v4_account_with_authorized(
405 &solana_pubkey::new_rand(),
406 &pk1,
407 &pk1,
408 None,
409 0,
410 100,
411 );
412 let stake_account1 = stake_utils::create_stake_account(
413 &sk1,
414 &pk1,
415 &vote_account1,
416 &genesis_config.rent,
417 100,
418 );
419 let sk2 = solana_pubkey::new_rand();
420 let pk2 = solana_pubkey::new_rand();
421 let mut vote_account2 = vote_state::create_v4_account_with_authorized(
422 &solana_pubkey::new_rand(),
423 &pk2,
424 &pk2,
425 None,
426 0,
427 50,
428 );
429 let stake_account2 =
430 stake_utils::create_stake_account(&sk2, &pk2, &vote_account2, &genesis_config.rent, 50);
431 let sk3 = solana_pubkey::new_rand();
432 let pk3 = solana_pubkey::new_rand();
433 let mut vote_account3 = vote_state::create_v4_account_with_authorized(
434 &solana_pubkey::new_rand(),
435 &pk3,
436 &pk3,
437 None,
438 0,
439 1,
440 );
441 let stake_account3 = stake_utils::create_stake_account(
442 &sk3,
443 &pk3,
444 &vote_account3,
445 &genesis_config.rent,
446 rooted_stake_amount,
447 );
448 let sk4 = solana_pubkey::new_rand();
449 let pk4 = solana_pubkey::new_rand();
450 let mut vote_account4 = vote_state::create_v4_account_with_authorized(
451 &solana_pubkey::new_rand(),
452 &pk4,
453 &pk4,
454 None,
455 0,
456 1,
457 );
458 let stake_account4 = stake_utils::create_stake_account(
459 &sk4,
460 &pk4,
461 &vote_account4,
462 &genesis_config.rent,
463 rooted_stake_amount,
464 );
465
466 genesis_config.accounts.extend(
467 vec![
468 (pk1, vote_account1.clone()),
469 (sk1, stake_account1),
470 (pk2, vote_account2.clone()),
471 (sk2, stake_account2),
472 (pk3, vote_account3.clone()),
473 (sk3, stake_account3),
474 (pk4, vote_account4.clone()),
475 (sk4, stake_account4),
476 ]
477 .into_iter()
478 .map(|(key, account)| (key, Account::from(account))),
479 );
480
481 let bank = Arc::new(Bank::new_for_tests(&genesis_config));
483
484 let mut vote_state1 = VoteStateV4::deserialize(vote_account1.data(), &pk1).unwrap();
485 process_slot_vote_unchecked(&mut vote_state1, 3);
486 process_slot_vote_unchecked(&mut vote_state1, 5);
487 if !with_node_vote_state {
488 let versioned = VoteStateVersions::new_v4(vote_state1.clone());
489 vote_account1.set_state(&versioned).unwrap();
490 bank.store_account(&pk1, &vote_account1);
491 }
492
493 let mut vote_state2 = VoteStateV4::deserialize(vote_account2.data(), &pk2).unwrap();
494 process_slot_vote_unchecked(&mut vote_state2, 9);
495 process_slot_vote_unchecked(&mut vote_state2, 10);
496 let versioned = VoteStateVersions::new_v4(vote_state2);
497 vote_account2.set_state(&versioned).unwrap();
498 bank.store_account(&pk2, &vote_account2);
499
500 let mut vote_state3 = VoteStateV4::deserialize(vote_account3.data(), &pk3).unwrap();
501 vote_state3.root_slot = Some(1);
502 let versioned = VoteStateVersions::new_v4(vote_state3);
503 vote_account3.set_state(&versioned).unwrap();
504 bank.store_account(&pk3, &vote_account3);
505
506 let mut vote_state4 = VoteStateV4::deserialize(vote_account4.data(), &pk4).unwrap();
507 vote_state4.root_slot = Some(2);
508 let versioned = VoteStateVersions::new_v4(vote_state4);
509 vote_account4.set_state(&versioned).unwrap();
510 bank.store_account(&pk4, &vote_account4);
511
512 let node_vote_pubkey = if with_node_vote_state {
513 pk1
514 } else {
515 solana_pubkey::new_rand()
517 };
518
519 let (commitment, rooted_stake) = AggregateCommitmentService::aggregate_commitment(
520 &ancestors,
521 &bank,
522 &(node_vote_pubkey, TowerVoteState::from(vote_state1)),
523 );
524
525 for a in ancestors {
526 if a <= 3 {
527 let mut expected = BlockCommitment::default();
528 expected.increase_confirmation_stake(2, 150);
529 assert_eq!(*commitment.get(&a).unwrap(), expected);
530 } else if a <= 5 {
531 let mut expected = BlockCommitment::default();
532 expected.increase_confirmation_stake(1, 100);
533 expected.increase_confirmation_stake(2, 50);
534 assert_eq!(*commitment.get(&a).unwrap(), expected);
535 } else if a <= 9 {
536 let mut expected = BlockCommitment::default();
537 expected.increase_confirmation_stake(2, 50);
538 assert_eq!(*commitment.get(&a).unwrap(), expected);
539 } else if a <= 10 {
540 let mut expected = BlockCommitment::default();
541 expected.increase_confirmation_stake(1, 50);
542 assert_eq!(*commitment.get(&a).unwrap(), expected);
543 } else {
544 assert!(!commitment.contains_key(&a));
545 }
546 }
547 assert_eq!(rooted_stake.len(), 2);
548 assert_eq!(get_highest_super_majority_root(rooted_stake, 100), 1)
549 }
550
551 #[test]
552 fn test_aggregate_commitment_validity_with_node_vote_state() {
553 do_test_aggregate_commitment_validity(true)
554 }
555
556 #[test]
557 fn test_aggregate_commitment_validity_without_node_vote_state() {
558 do_test_aggregate_commitment_validity(false);
559 }
560
561 #[test]
562 fn test_highest_super_majority_root_advance() {
563 fn get_vote_state(vote_pubkey: Pubkey, bank: &Bank) -> TowerVoteState {
564 let vote_account = bank.get_vote_account(&vote_pubkey).unwrap();
565 TowerVoteState::from(vote_account.vote_state_view())
566 }
567
568 let block_commitment_cache = RwLock::new(BlockCommitmentCache::new_for_tests());
569
570 let validator_vote_keypairs = ValidatorVoteKeypairs::new_rand();
571 let validator_keypairs = vec![&validator_vote_keypairs];
572 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config_with_vote_accounts(
573 1_000_000_000,
574 &validator_keypairs,
575 vec![100; 1],
576 );
577
578 let (_bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
579
580 for x in 0..33 {
583 let previous_bank = bank_forks.read().unwrap().get(x).unwrap();
584 let bank = Bank::new_from_parent_with_bank_forks(
585 bank_forks.as_ref(),
586 previous_bank.clone(),
587 &Pubkey::default(),
588 x + 1,
589 );
590 let tower_sync = TowerSync::new_from_slot(x, previous_bank.hash());
591 let vote = vote_transaction::new_tower_sync_transaction(
592 tower_sync,
593 previous_bank.last_blockhash(),
594 &validator_vote_keypairs.node_keypair,
595 &validator_vote_keypairs.vote_keypair,
596 &validator_vote_keypairs.vote_keypair,
597 None,
598 );
599 bank.process_transaction(&vote).unwrap();
600 }
601
602 let working_bank = bank_forks.read().unwrap().working_bank();
603 let vote_pubkey = validator_vote_keypairs.vote_keypair.pubkey();
604 let root = get_vote_state(vote_pubkey, &working_bank)
605 .root_slot
606 .unwrap();
607 for x in 0..root {
608 bank_forks.write().unwrap().set_root(x, None, None);
609 }
610
611 let bank33 = bank_forks.read().unwrap().get(33).unwrap();
613 let bank34 = Bank::new_from_parent_with_bank_forks(
614 bank_forks.as_ref(),
615 bank33.clone(),
616 &Pubkey::default(),
617 34,
618 );
619 let tower_sync = TowerSync::new_from_slot(33, bank33.hash());
620 let vote33 = vote_transaction::new_tower_sync_transaction(
621 tower_sync,
622 bank33.last_blockhash(),
623 &validator_vote_keypairs.node_keypair,
624 &validator_vote_keypairs.vote_keypair,
625 &validator_vote_keypairs.vote_keypair,
626 None,
627 );
628 bank34.process_transaction(&vote33).unwrap();
629
630 let working_bank = bank_forks.read().unwrap().working_bank();
631 let vote_state = get_vote_state(vote_pubkey, &working_bank);
632 let root = vote_state.root_slot.unwrap();
633 let ancestors = working_bank.status_cache_ancestors();
634 let _ = AggregateCommitmentService::update_commitment_cache(
635 &block_commitment_cache,
636 CommitmentAggregationData {
637 bank: working_bank,
638 root: 0,
639 total_stake: 100,
640 node_vote_state: (vote_pubkey, vote_state.clone()),
641 },
642 ancestors,
643 );
644 let highest_super_majority_root = block_commitment_cache
645 .read()
646 .unwrap()
647 .highest_super_majority_root();
648 bank_forks
649 .write()
650 .unwrap()
651 .set_root(root, None, Some(highest_super_majority_root));
652 let highest_super_majority_root_bank =
653 bank_forks.read().unwrap().get(highest_super_majority_root);
654 assert!(highest_super_majority_root_bank.is_some());
655
656 let bank33 = bank_forks.read().unwrap().get(33).unwrap();
659 let _bank35 = Bank::new_from_parent_with_bank_forks(
660 bank_forks.as_ref(),
661 bank33,
662 &Pubkey::default(),
663 35,
664 );
665
666 let working_bank = bank_forks.read().unwrap().working_bank();
667 let ancestors = working_bank.status_cache_ancestors();
668 let _ = AggregateCommitmentService::update_commitment_cache(
669 &block_commitment_cache,
670 CommitmentAggregationData {
671 bank: working_bank,
672 root: 1,
673 total_stake: 100,
674 node_vote_state: (vote_pubkey, vote_state),
675 },
676 ancestors,
677 );
678 let highest_super_majority_root = block_commitment_cache
679 .read()
680 .unwrap()
681 .highest_super_majority_root();
682 let highest_super_majority_root_bank =
683 bank_forks.read().unwrap().get(highest_super_majority_root);
684 assert!(highest_super_majority_root_bank.is_some());
685
686 for x in 35..=37 {
689 let previous_bank = bank_forks.read().unwrap().get(x).unwrap();
690 let bank = Bank::new_from_parent_with_bank_forks(
691 bank_forks.as_ref(),
692 previous_bank.clone(),
693 &Pubkey::default(),
694 x + 1,
695 );
696 let lowest_slot = x - MAX_LOCKOUT_HISTORY as u64;
698 let slots: Vec<_> = (lowest_slot..(x + 1)).filter(|s| *s != 34).collect();
699 let tower_sync =
700 TowerSync::new_from_slots(slots, previous_bank.hash(), Some(lowest_slot - 1));
701 let vote = vote_transaction::new_tower_sync_transaction(
702 tower_sync,
703 previous_bank.last_blockhash(),
704 &validator_vote_keypairs.node_keypair,
705 &validator_vote_keypairs.vote_keypair,
706 &validator_vote_keypairs.vote_keypair,
707 None,
708 );
709 bank.process_transaction(&vote).unwrap();
710 }
711
712 let working_bank = bank_forks.read().unwrap().working_bank();
713 let vote_state =
714 get_vote_state(validator_vote_keypairs.vote_keypair.pubkey(), &working_bank);
715 let root = vote_state.root_slot.unwrap();
716 let ancestors = working_bank.status_cache_ancestors();
717 let _ = AggregateCommitmentService::update_commitment_cache(
718 &block_commitment_cache,
719 CommitmentAggregationData {
720 bank: working_bank,
721 root: 0,
722 total_stake: 100,
723 node_vote_state: (vote_pubkey, vote_state),
724 },
725 ancestors,
726 );
727 let highest_super_majority_root = block_commitment_cache
728 .read()
729 .unwrap()
730 .highest_super_majority_root();
731 bank_forks
732 .write()
733 .unwrap()
734 .set_root(root, None, Some(highest_super_majority_root));
735 let highest_super_majority_root_bank =
736 bank_forks.read().unwrap().get(highest_super_majority_root);
737 assert!(highest_super_majority_root_bank.is_some());
738 }
739}