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