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