Skip to main content

solana_core/
commitment_service.rs

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