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::Account,
275 solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo},
276 solana_pubkey::Pubkey,
277 solana_runtime::{
278 bank_forks::BankForks,
279 genesis_utils::{create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs},
280 },
281 solana_signer::Signer,
282 solana_stake_program::stake_state,
283 solana_vote::vote_transaction,
284 solana_vote_program::vote_state::{
285 self, process_slot_vote_unchecked, TowerSync, VoteStateVersions, MAX_LOCKOUT_HISTORY,
286 },
287 };
288
289 fn new_bank_from_parent_with_bank_forks(
290 bank_forks: &RwLock<BankForks>,
291 parent: Arc<Bank>,
292 collector_id: &Pubkey,
293 slot: Slot,
294 ) -> Arc<Bank> {
295 let bank = Bank::new_from_parent(parent, collector_id, slot);
296 bank_forks
297 .write()
298 .unwrap()
299 .insert(bank)
300 .clone_without_scheduler()
301 }
302
303 #[test]
304 fn test_get_highest_super_majority_root() {
305 assert_eq!(get_highest_super_majority_root(vec![], 10), 0);
306 let rooted_stake = vec![(0, 5), (1, 5)];
307 assert_eq!(get_highest_super_majority_root(rooted_stake, 10), 0);
308 let rooted_stake = vec![(1, 5), (0, 10), (2, 5), (1, 4)];
309 assert_eq!(get_highest_super_majority_root(rooted_stake, 10), 1);
310 }
311
312 #[test]
313 fn test_aggregate_commitment_for_vote_account_1() {
314 let ancestors = vec![3, 4, 5, 7, 9, 11];
315 let mut commitment = HashMap::new();
316 let mut rooted_stake = vec![];
317 let lamports = 5;
318 let mut vote_state = TowerVoteState::default();
319
320 let root = *ancestors.last().unwrap();
321 vote_state.root_slot = Some(root);
322 AggregateCommitmentService::aggregate_commitment_for_vote_account(
323 &mut commitment,
324 &mut rooted_stake,
325 &vote_state,
326 &ancestors,
327 lamports,
328 );
329
330 for a in ancestors {
331 let mut expected = BlockCommitment::default();
332 expected.increase_rooted_stake(lamports);
333 assert_eq!(*commitment.get(&a).unwrap(), expected);
334 }
335 assert_eq!(rooted_stake[0], (root, lamports));
336 }
337
338 #[test]
339 fn test_aggregate_commitment_for_vote_account_2() {
340 let ancestors = vec![3, 4, 5, 7, 9, 11];
341 let mut commitment = HashMap::new();
342 let mut rooted_stake = vec![];
343 let lamports = 5;
344 let mut vote_state = TowerVoteState::default();
345
346 let root = ancestors[2];
347 vote_state.root_slot = Some(root);
348 vote_state.process_next_vote_slot(*ancestors.last().unwrap());
349 AggregateCommitmentService::aggregate_commitment_for_vote_account(
350 &mut commitment,
351 &mut rooted_stake,
352 &vote_state,
353 &ancestors,
354 lamports,
355 );
356
357 for a in ancestors {
358 let mut expected = BlockCommitment::default();
359 if a <= root {
360 expected.increase_rooted_stake(lamports);
361 } else {
362 expected.increase_confirmation_stake(1, lamports);
363 }
364 assert_eq!(*commitment.get(&a).unwrap(), expected);
365 }
366 assert_eq!(rooted_stake[0], (root, lamports));
367 }
368
369 #[test]
370 fn test_aggregate_commitment_for_vote_account_3() {
371 let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
372 let mut commitment = HashMap::new();
373 let mut rooted_stake = vec![];
374 let lamports = 5;
375 let mut vote_state = TowerVoteState::default();
376
377 let root = ancestors[2];
378 vote_state.root_slot = Some(root);
379 assert!(ancestors[4] + 2 >= ancestors[6]);
380 vote_state.process_next_vote_slot(ancestors[4]);
381 vote_state.process_next_vote_slot(ancestors[6]);
382 AggregateCommitmentService::aggregate_commitment_for_vote_account(
383 &mut commitment,
384 &mut rooted_stake,
385 &vote_state,
386 &ancestors,
387 lamports,
388 );
389
390 for (i, a) in ancestors.iter().enumerate() {
391 if *a <= root {
392 let mut expected = BlockCommitment::default();
393 expected.increase_rooted_stake(lamports);
394 assert_eq!(*commitment.get(a).unwrap(), expected);
395 } else if i <= 4 {
396 let mut expected = BlockCommitment::default();
397 expected.increase_confirmation_stake(2, lamports);
398 assert_eq!(*commitment.get(a).unwrap(), expected);
399 } else if i <= 6 {
400 let mut expected = BlockCommitment::default();
401 expected.increase_confirmation_stake(1, lamports);
402 assert_eq!(*commitment.get(a).unwrap(), expected);
403 }
404 }
405 assert_eq!(rooted_stake[0], (root, lamports));
406 }
407
408 fn do_test_aggregate_commitment_validity(with_node_vote_state: bool) {
409 let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
410 let GenesisConfigInfo {
411 mut genesis_config, ..
412 } = create_genesis_config(10_000);
413
414 let rooted_stake_amount = 40;
415
416 let sk1 = solana_pubkey::new_rand();
417 let pk1 = solana_pubkey::new_rand();
418 let mut vote_account1 =
419 vote_state::create_account(&pk1, &solana_pubkey::new_rand(), 0, 100);
420 let stake_account1 =
421 stake_state::create_account(&sk1, &pk1, &vote_account1, &genesis_config.rent, 100);
422 let sk2 = solana_pubkey::new_rand();
423 let pk2 = solana_pubkey::new_rand();
424 let mut vote_account2 = vote_state::create_account(&pk2, &solana_pubkey::new_rand(), 0, 50);
425 let stake_account2 =
426 stake_state::create_account(&sk2, &pk2, &vote_account2, &genesis_config.rent, 50);
427 let sk3 = solana_pubkey::new_rand();
428 let pk3 = solana_pubkey::new_rand();
429 let mut vote_account3 = vote_state::create_account(&pk3, &solana_pubkey::new_rand(), 0, 1);
430 let stake_account3 = stake_state::create_account(
431 &sk3,
432 &pk3,
433 &vote_account3,
434 &genesis_config.rent,
435 rooted_stake_amount,
436 );
437 let sk4 = solana_pubkey::new_rand();
438 let pk4 = solana_pubkey::new_rand();
439 let mut vote_account4 = vote_state::create_account(&pk4, &solana_pubkey::new_rand(), 0, 1);
440 let stake_account4 = stake_state::create_account(
441 &sk4,
442 &pk4,
443 &vote_account4,
444 &genesis_config.rent,
445 rooted_stake_amount,
446 );
447
448 genesis_config.accounts.extend(
449 vec![
450 (pk1, vote_account1.clone()),
451 (sk1, stake_account1),
452 (pk2, vote_account2.clone()),
453 (sk2, stake_account2),
454 (pk3, vote_account3.clone()),
455 (sk3, stake_account3),
456 (pk4, vote_account4.clone()),
457 (sk4, stake_account4),
458 ]
459 .into_iter()
460 .map(|(key, account)| (key, Account::from(account))),
461 );
462
463 let bank = Arc::new(Bank::new_for_tests(&genesis_config));
465
466 let mut vote_state1 = vote_state::from(&vote_account1).unwrap();
467 process_slot_vote_unchecked(&mut vote_state1, 3);
468 process_slot_vote_unchecked(&mut vote_state1, 5);
469 if !with_node_vote_state {
470 let versioned = VoteStateVersions::new_v3(vote_state1.clone());
471 vote_state::to(&versioned, &mut vote_account1).unwrap();
472 bank.store_account(&pk1, &vote_account1);
473 }
474
475 let mut vote_state2 = vote_state::from(&vote_account2).unwrap();
476 process_slot_vote_unchecked(&mut vote_state2, 9);
477 process_slot_vote_unchecked(&mut vote_state2, 10);
478 let versioned = VoteStateVersions::new_v3(vote_state2);
479 vote_state::to(&versioned, &mut vote_account2).unwrap();
480 bank.store_account(&pk2, &vote_account2);
481
482 let mut vote_state3 = vote_state::from(&vote_account3).unwrap();
483 vote_state3.root_slot = Some(1);
484 let versioned = VoteStateVersions::new_v3(vote_state3);
485 vote_state::to(&versioned, &mut vote_account3).unwrap();
486 bank.store_account(&pk3, &vote_account3);
487
488 let mut vote_state4 = vote_state::from(&vote_account4).unwrap();
489 vote_state4.root_slot = Some(2);
490 let versioned = VoteStateVersions::new_v3(vote_state4);
491 vote_state::to(&versioned, &mut vote_account4).unwrap();
492 bank.store_account(&pk4, &vote_account4);
493
494 let node_vote_pubkey = if with_node_vote_state {
495 pk1
496 } else {
497 solana_pubkey::new_rand()
499 };
500
501 let (commitment, rooted_stake) = AggregateCommitmentService::aggregate_commitment(
502 &ancestors,
503 &bank,
504 &(node_vote_pubkey, TowerVoteState::from(vote_state1)),
505 );
506
507 for a in ancestors {
508 if a <= 3 {
509 let mut expected = BlockCommitment::default();
510 expected.increase_confirmation_stake(2, 150);
511 assert_eq!(*commitment.get(&a).unwrap(), expected);
512 } else if a <= 5 {
513 let mut expected = BlockCommitment::default();
514 expected.increase_confirmation_stake(1, 100);
515 expected.increase_confirmation_stake(2, 50);
516 assert_eq!(*commitment.get(&a).unwrap(), expected);
517 } else if a <= 9 {
518 let mut expected = BlockCommitment::default();
519 expected.increase_confirmation_stake(2, 50);
520 assert_eq!(*commitment.get(&a).unwrap(), expected);
521 } else if a <= 10 {
522 let mut expected = BlockCommitment::default();
523 expected.increase_confirmation_stake(1, 50);
524 assert_eq!(*commitment.get(&a).unwrap(), expected);
525 } else {
526 assert!(!commitment.contains_key(&a));
527 }
528 }
529 assert_eq!(rooted_stake.len(), 2);
530 assert_eq!(get_highest_super_majority_root(rooted_stake, 100), 1)
531 }
532
533 #[test]
534 fn test_aggregate_commitment_validity_with_node_vote_state() {
535 do_test_aggregate_commitment_validity(true)
536 }
537
538 #[test]
539 fn test_aggregate_commitment_validity_without_node_vote_state() {
540 do_test_aggregate_commitment_validity(false);
541 }
542
543 #[test]
544 fn test_highest_super_majority_root_advance() {
545 fn get_vote_state(vote_pubkey: Pubkey, bank: &Bank) -> TowerVoteState {
546 let vote_account = bank.get_vote_account(&vote_pubkey).unwrap();
547 TowerVoteState::from(vote_account.vote_state_view())
548 }
549
550 let block_commitment_cache = RwLock::new(BlockCommitmentCache::new_for_tests());
551
552 let validator_vote_keypairs = ValidatorVoteKeypairs::new_rand();
553 let validator_keypairs = vec![&validator_vote_keypairs];
554 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config_with_vote_accounts(
555 1_000_000_000,
556 &validator_keypairs,
557 vec![100; 1],
558 );
559
560 let (_bank0, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
561
562 for x in 0..33 {
565 let previous_bank = bank_forks.read().unwrap().get(x).unwrap();
566 let bank = new_bank_from_parent_with_bank_forks(
567 bank_forks.as_ref(),
568 previous_bank.clone(),
569 &Pubkey::default(),
570 x + 1,
571 );
572 let tower_sync = TowerSync::new_from_slot(x, previous_bank.hash());
573 let vote = vote_transaction::new_tower_sync_transaction(
574 tower_sync,
575 previous_bank.last_blockhash(),
576 &validator_vote_keypairs.node_keypair,
577 &validator_vote_keypairs.vote_keypair,
578 &validator_vote_keypairs.vote_keypair,
579 None,
580 );
581 bank.process_transaction(&vote).unwrap();
582 }
583
584 let working_bank = bank_forks.read().unwrap().working_bank();
585 let vote_pubkey = validator_vote_keypairs.vote_keypair.pubkey();
586 let root = get_vote_state(vote_pubkey, &working_bank)
587 .root_slot
588 .unwrap();
589 for x in 0..root {
590 bank_forks.write().unwrap().set_root(x, None, None).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(root, None, Some(highest_super_majority_root))
634 .unwrap();
635 let highest_super_majority_root_bank =
636 bank_forks.read().unwrap().get(highest_super_majority_root);
637 assert!(highest_super_majority_root_bank.is_some());
638
639 let bank33 = bank_forks.read().unwrap().get(33).unwrap();
642 let _bank35 = new_bank_from_parent_with_bank_forks(
643 bank_forks.as_ref(),
644 bank33,
645 &Pubkey::default(),
646 35,
647 );
648
649 let working_bank = bank_forks.read().unwrap().working_bank();
650 let ancestors = working_bank.status_cache_ancestors();
651 let _ = AggregateCommitmentService::update_commitment_cache(
652 &block_commitment_cache,
653 CommitmentAggregationData {
654 bank: working_bank,
655 root: 1,
656 total_stake: 100,
657 node_vote_state: (vote_pubkey, vote_state),
658 },
659 ancestors,
660 );
661 let highest_super_majority_root = block_commitment_cache
662 .read()
663 .unwrap()
664 .highest_super_majority_root();
665 let highest_super_majority_root_bank =
666 bank_forks.read().unwrap().get(highest_super_majority_root);
667 assert!(highest_super_majority_root_bank.is_some());
668
669 for x in 35..=37 {
672 let previous_bank = bank_forks.read().unwrap().get(x).unwrap();
673 let bank = new_bank_from_parent_with_bank_forks(
674 bank_forks.as_ref(),
675 previous_bank.clone(),
676 &Pubkey::default(),
677 x + 1,
678 );
679 let lowest_slot = x - MAX_LOCKOUT_HISTORY as u64;
681 let slots: Vec<_> = (lowest_slot..(x + 1)).filter(|s| *s != 34).collect();
682 let tower_sync =
683 TowerSync::new_from_slots(slots, previous_bank.hash(), Some(lowest_slot - 1));
684 let vote = vote_transaction::new_tower_sync_transaction(
685 tower_sync,
686 previous_bank.last_blockhash(),
687 &validator_vote_keypairs.node_keypair,
688 &validator_vote_keypairs.vote_keypair,
689 &validator_vote_keypairs.vote_keypair,
690 None,
691 );
692 bank.process_transaction(&vote).unwrap();
693 }
694
695 let working_bank = bank_forks.read().unwrap().working_bank();
696 let vote_state =
697 get_vote_state(validator_vote_keypairs.vote_keypair.pubkey(), &working_bank);
698 let root = vote_state.root_slot.unwrap();
699 let ancestors = working_bank.status_cache_ancestors();
700 let _ = AggregateCommitmentService::update_commitment_cache(
701 &block_commitment_cache,
702 CommitmentAggregationData {
703 bank: working_bank,
704 root: 0,
705 total_stake: 100,
706 node_vote_state: (vote_pubkey, vote_state),
707 },
708 ancestors,
709 );
710 let highest_super_majority_root = block_commitment_cache
711 .read()
712 .unwrap()
713 .highest_super_majority_root();
714 bank_forks
715 .write()
716 .unwrap()
717 .set_root(root, None, Some(highest_super_majority_root))
718 .unwrap();
719 let highest_super_majority_root_bank =
720 bank_forks.read().unwrap().get(highest_super_majority_root);
721 assert!(highest_super_majority_root_bank.is_some());
722 }
723}