solana_runtime/
bank_forks.rs

1//! The `bank_forks` module implements BankForks a DAG of checkpointed Banks
2
3use {
4    crate::{
5        bank::{bank_hash_details, Bank, SquashTiming},
6        bank_hash_cache::DumpedSlotSubscription,
7        installed_scheduler_pool::{
8            BankWithScheduler, InstalledSchedulerPoolArc, SchedulingContext,
9        },
10        snapshot_controller::SnapshotController,
11    },
12    arc_swap::ArcSwap,
13    log::*,
14    solana_clock::{BankId, Slot},
15    solana_hash::Hash,
16    solana_measure::measure::Measure,
17    solana_program_runtime::loaded_programs::{BlockRelation, ForkGraph},
18    solana_unified_scheduler_logic::SchedulingMode,
19    std::{
20        collections::{hash_map::Entry, HashMap, HashSet},
21        ops::Index,
22        sync::{
23            atomic::{AtomicBool, AtomicU64, Ordering},
24            Arc, RwLock,
25        },
26        time::Instant,
27    },
28    thiserror::Error,
29};
30
31pub const MAX_ROOT_DISTANCE_FOR_VOTE_ONLY: Slot = 400;
32pub type AtomicSlot = AtomicU64;
33#[derive(Clone)]
34pub struct ReadOnlyAtomicSlot {
35    slot: Arc<AtomicSlot>,
36}
37
38impl ReadOnlyAtomicSlot {
39    pub fn get(&self) -> Slot {
40        // The expectation is that an instance `ReadOnlyAtomicSlot` is on a different thread than
41        // BankForks *and* this instance is being accessed *without* locking BankForks first.
42        // Thus, to ensure atomic ordering correctness, we must use Acquire-Release semantics.
43        self.slot.load(Ordering::Acquire)
44    }
45}
46
47#[derive(Clone)]
48pub struct SharableBank(Arc<ArcSwap<Bank>>);
49
50impl SharableBank {
51    pub fn load(&self) -> Arc<Bank> {
52        self.0.load_full()
53    }
54
55    fn store(&self, bank: Arc<Bank>) {
56        self.0.store(bank);
57    }
58}
59
60#[derive(Error, Debug)]
61pub enum SetRootError {}
62
63#[derive(Debug, Default, Copy, Clone)]
64struct SetRootMetrics {
65    timings: SetRootTimings,
66    total_parent_banks: i64,
67    tx_count: i64,
68    dropped_banks_len: i64,
69    accounts_data_len: i64,
70}
71
72#[derive(Debug, Default, Copy, Clone)]
73struct SetRootTimings {
74    total_squash_time: SquashTiming,
75    total_snapshot_ms: i64,
76    prune_non_rooted_ms: i64,
77    drop_parent_banks_ms: i64,
78    prune_slots_ms: i64,
79    prune_remove_ms: i64,
80}
81
82pub struct BankForks {
83    banks: HashMap<Slot, BankWithScheduler>,
84    descendants: HashMap<Slot, HashSet<Slot>>,
85    root: Arc<AtomicSlot>,
86    root_bank: SharableBank,
87    in_vote_only_mode: Arc<AtomicBool>,
88    highest_slot_at_startup: Slot,
89    scheduler_pool: Option<InstalledSchedulerPoolArc>,
90    dumped_slot_subscribers: Vec<DumpedSlotSubscription>,
91}
92
93impl Index<u64> for BankForks {
94    type Output = Arc<Bank>;
95    fn index(&self, bank_slot: Slot) -> &Self::Output {
96        &self.banks[&bank_slot]
97    }
98}
99
100impl BankForks {
101    pub fn new_rw_arc(root_bank: Bank) -> Arc<RwLock<Self>> {
102        let root_bank = Arc::new(root_bank);
103        let root_slot = root_bank.slot();
104
105        let mut banks = HashMap::new();
106        banks.insert(
107            root_slot,
108            BankWithScheduler::new_without_scheduler(root_bank.clone()),
109        );
110
111        let parents = root_bank.parents();
112        for parent in parents {
113            if banks
114                .insert(
115                    parent.slot(),
116                    BankWithScheduler::new_without_scheduler(parent.clone()),
117                )
118                .is_some()
119            {
120                // All ancestors have already been inserted by another fork
121                break;
122            }
123        }
124
125        let mut descendants = HashMap::<_, HashSet<_>>::new();
126        descendants.entry(root_slot).or_default();
127        for parent in root_bank.proper_ancestors() {
128            descendants.entry(parent).or_default().insert(root_slot);
129        }
130
131        let bank_forks = Arc::new(RwLock::new(Self {
132            root: Arc::new(AtomicSlot::new(root_slot)),
133            root_bank: SharableBank(Arc::new(ArcSwap::from(Arc::clone(&root_bank)))),
134            banks,
135            descendants,
136            in_vote_only_mode: Arc::new(AtomicBool::new(false)),
137            highest_slot_at_startup: 0,
138            scheduler_pool: None,
139            dumped_slot_subscribers: vec![],
140        }));
141
142        root_bank.set_fork_graph_in_program_cache(Arc::downgrade(&bank_forks));
143        bank_forks
144    }
145
146    pub fn banks(&self) -> &HashMap<Slot, BankWithScheduler> {
147        &self.banks
148    }
149
150    pub fn get_vote_only_mode_signal(&self) -> Arc<AtomicBool> {
151        self.in_vote_only_mode.clone()
152    }
153
154    pub fn len(&self) -> usize {
155        self.banks.len()
156    }
157
158    pub fn is_empty(&self) -> bool {
159        self.banks.is_empty()
160    }
161
162    /// Create a map of bank slot id to the set of ancestors for the bank slot.
163    pub fn ancestors(&self) -> HashMap<Slot, HashSet<Slot>> {
164        let root = self.root();
165        self.banks
166            .iter()
167            .map(|(slot, bank)| {
168                let ancestors = bank.proper_ancestors().filter(|k| *k >= root);
169                (*slot, ancestors.collect())
170            })
171            .collect()
172    }
173
174    /// Create a map of bank slot id to the set of all of its descendants
175    pub fn descendants(&self) -> HashMap<Slot, HashSet<Slot>> {
176        self.descendants.clone()
177    }
178
179    pub fn frozen_banks(&self) -> impl Iterator<Item = (Slot, Arc<Bank>)> + '_ {
180        self.banks
181            .iter()
182            .filter(|(_, b)| b.is_frozen())
183            .map(|(&k, b)| (k, b.clone_without_scheduler()))
184    }
185
186    pub fn active_bank_slots(&self) -> Vec<Slot> {
187        self.banks
188            .iter()
189            .filter(|(_, v)| !v.is_frozen())
190            .map(|(k, _v)| *k)
191            .collect()
192    }
193
194    pub fn get_with_scheduler(&self, bank_slot: Slot) -> Option<BankWithScheduler> {
195        self.banks.get(&bank_slot).map(|b| b.clone_with_scheduler())
196    }
197
198    pub fn get(&self, bank_slot: Slot) -> Option<Arc<Bank>> {
199        self.get_with_scheduler(bank_slot)
200            .map(|b| b.clone_without_scheduler())
201    }
202
203    pub fn get_with_checked_hash(
204        &self,
205        (bank_slot, expected_hash): (Slot, Hash),
206    ) -> Option<Arc<Bank>> {
207        let maybe_bank = self.get(bank_slot);
208        if let Some(bank) = &maybe_bank {
209            assert_eq!(bank.hash(), expected_hash);
210        }
211        maybe_bank
212    }
213
214    pub fn bank_hash(&self, slot: Slot) -> Option<Hash> {
215        self.get(slot).map(|bank| bank.hash())
216    }
217
218    pub fn sharable_root_bank(&self) -> SharableBank {
219        self.root_bank.clone()
220    }
221
222    pub fn root_bank(&self) -> Arc<Bank> {
223        self.root_bank.load()
224    }
225
226    pub fn install_scheduler_pool(&mut self, pool: InstalledSchedulerPoolArc) {
227        info!("Installed new scheduler_pool into bank_forks: {pool:?}");
228        assert!(
229            self.scheduler_pool.replace(pool).is_none(),
230            "Reinstalling scheduler pool isn't supported"
231        );
232    }
233
234    pub fn insert(&mut self, bank: Bank) -> BankWithScheduler {
235        self.insert_with_scheduling_mode(SchedulingMode::BlockVerification, bank)
236    }
237
238    pub fn insert_with_scheduling_mode(
239        &mut self,
240        mode: SchedulingMode,
241        mut bank: Bank,
242    ) -> BankWithScheduler {
243        if self.root.load(Ordering::Relaxed) < self.highest_slot_at_startup {
244            bank.set_check_program_modification_slot(true);
245        }
246
247        let bank = Arc::new(bank);
248        let bank = if let Some(scheduler_pool) = &self.scheduler_pool {
249            Self::install_scheduler_into_bank(scheduler_pool, mode, bank)
250        } else {
251            BankWithScheduler::new_without_scheduler(bank)
252        };
253        let prev = self.banks.insert(bank.slot(), bank.clone_with_scheduler());
254        assert!(prev.is_none());
255        let slot = bank.slot();
256        self.descendants.entry(slot).or_default();
257        for parent in bank.proper_ancestors() {
258            self.descendants.entry(parent).or_default().insert(slot);
259        }
260        bank
261    }
262
263    fn install_scheduler_into_bank(
264        scheduler_pool: &InstalledSchedulerPoolArc,
265        mode: SchedulingMode,
266        bank: Arc<Bank>,
267    ) -> BankWithScheduler {
268        let context = SchedulingContext::new_with_mode(mode, bank.clone());
269        let scheduler = scheduler_pool.take_scheduler(context);
270        let bank_with_scheduler = BankWithScheduler::new(bank, Some(scheduler));
271        // Skip registering for block production. Both the tvu main loop in the replay stage
272        // and PohRecorder don't support _concurrent block production_ at all. It's strongly
273        // assumed that block is produced in singleton way and it's actually desired, while
274        // ignoring the opportunity cost of (hopefully rare!) fork switching...
275        if matches!(mode, SchedulingMode::BlockVerification) {
276            scheduler_pool.register_timeout_listener(bank_with_scheduler.create_timeout_listener());
277        }
278        bank_with_scheduler
279    }
280
281    pub fn insert_from_ledger(&mut self, bank: Bank) -> BankWithScheduler {
282        self.highest_slot_at_startup = std::cmp::max(self.highest_slot_at_startup, bank.slot());
283        self.insert(bank)
284    }
285
286    pub fn remove(&mut self, slot: Slot) -> Option<BankWithScheduler> {
287        let bank = self.banks.remove(&slot)?;
288        for parent in bank.proper_ancestors() {
289            let Entry::Occupied(mut entry) = self.descendants.entry(parent) else {
290                panic!("this should not happen!");
291            };
292            entry.get_mut().remove(&slot);
293            if entry.get().is_empty() && !self.banks.contains_key(&parent) {
294                entry.remove_entry();
295            }
296        }
297        let Entry::Occupied(entry) = self.descendants.entry(slot) else {
298            panic!("this should not happen!");
299        };
300        if entry.get().is_empty() {
301            entry.remove_entry();
302        }
303        Some(bank)
304    }
305
306    pub fn highest_slot(&self) -> Slot {
307        self.banks.values().map(|bank| bank.slot()).max().unwrap()
308    }
309
310    pub fn working_bank(&self) -> Arc<Bank> {
311        self[self.highest_slot()].clone()
312    }
313
314    pub fn working_bank_with_scheduler(&self) -> BankWithScheduler {
315        self.banks[&self.highest_slot()].clone_with_scheduler()
316    }
317
318    /// Register to be notified when a bank has been dumped (due to duplicate block handling)
319    /// from bank_forks.
320    pub fn register_dumped_slot_subscriber(&mut self, notifier: DumpedSlotSubscription) {
321        self.dumped_slot_subscribers.push(notifier);
322    }
323
324    /// Clears associated banks from BankForks and notifies subscribers that a dump has occured.
325    pub fn dump_slots<'a, I>(&mut self, slots: I) -> (Vec<(Slot, BankId)>, Vec<BankWithScheduler>)
326    where
327        I: Iterator<Item = &'a Slot>,
328    {
329        // Notify subscribers. It is fine that the lock is immediately released, since the bank_forks
330        // lock is held until the end of this function, so subscribers will not be able to interact
331        // with bank_forks anyway.
332        for subscriber in &self.dumped_slot_subscribers {
333            let mut lock = subscriber.lock().unwrap();
334            *lock = true;
335        }
336
337        slots
338            .map(|slot| {
339                // Clear the banks from BankForks
340                let bank = self
341                    .remove(*slot)
342                    .expect("BankForks should not have been purged yet");
343                bank_hash_details::write_bank_hash_details_file(&bank)
344                    .map_err(|err| {
345                        warn!("Unable to write bank hash details file: {err}");
346                    })
347                    .ok();
348                ((*slot, bank.bank_id()), bank)
349            })
350            .unzip()
351    }
352
353    fn do_set_root_return_metrics(
354        &mut self,
355        root: Slot,
356        snapshot_controller: Option<&SnapshotController>,
357        highest_super_majority_root: Option<Slot>,
358    ) -> Result<(Vec<BankWithScheduler>, SetRootMetrics), SetRootError> {
359        let old_epoch = self.root_bank.load().epoch();
360
361        let root_bank = &self
362            .get(root)
363            .expect("root bank didn't exist in bank_forks");
364
365        // To support `RootBankCache` (via `ReadOnlyAtomicSlot`) accessing `root` *without* locking
366        // BankForks first *and* from a different thread, this store *must* be at least Release to
367        // ensure atomic ordering correctness.
368        self.root.store(root, Ordering::Release);
369        self.root_bank.store(Arc::clone(root_bank));
370
371        let new_epoch = root_bank.epoch();
372        if old_epoch != new_epoch {
373            info!(
374                "Root entering epoch: {new_epoch}, next_epoch_start_slot: {}, epoch_stakes: {:#?}",
375                root_bank
376                    .epoch_schedule()
377                    .get_first_slot_in_epoch(new_epoch + 1),
378                root_bank
379                    .epoch_stakes(new_epoch)
380                    .unwrap()
381                    .node_id_to_vote_accounts()
382            );
383            // Now we have rooted a bank in a new epoch, there are no needs to
384            // keep the epoch rewards cache for current epoch any longer.
385            info!(
386                "Clearing epoch rewards cache for epoch {old_epoch} after setting root to slot \
387                 {root}"
388            );
389            root_bank.clear_epoch_rewards_cache();
390        }
391        let root_tx_count = root_bank
392            .parents()
393            .last()
394            .map(|bank| bank.transaction_count())
395            .unwrap_or(0);
396        // Calculate the accounts hash at a fixed interval
397        let mut banks = vec![root_bank];
398        let parents = root_bank.parents();
399        banks.extend(parents.iter());
400        let total_parent_banks = banks.len();
401        let (is_root_bank_squashed, mut squash_timing, total_snapshot_ms) =
402            if let Some(snapshot_controller) = snapshot_controller {
403                snapshot_controller.handle_new_roots(root, &banks)?
404            } else {
405                (false, SquashTiming::default(), 0)
406            };
407
408        if !is_root_bank_squashed {
409            squash_timing += root_bank.squash();
410        }
411        let new_tx_count = root_bank.transaction_count();
412        let accounts_data_len = root_bank.load_accounts_data_size() as i64;
413        let mut prune_time = Measure::start("set_root::prune");
414        let (removed_banks, prune_slots_ms, prune_remove_ms) =
415            self.prune_non_rooted(root, highest_super_majority_root);
416        prune_time.stop();
417        let dropped_banks_len = removed_banks.len();
418
419        let mut drop_parent_banks_time = Measure::start("set_root::drop_banks");
420        drop(parents);
421        drop_parent_banks_time.stop();
422
423        Ok((
424            removed_banks,
425            SetRootMetrics {
426                timings: SetRootTimings {
427                    total_squash_time: squash_timing,
428                    total_snapshot_ms: total_snapshot_ms as i64,
429                    prune_non_rooted_ms: prune_time.as_ms() as i64,
430                    drop_parent_banks_ms: drop_parent_banks_time.as_ms() as i64,
431                    prune_slots_ms: prune_slots_ms as i64,
432                    prune_remove_ms: prune_remove_ms as i64,
433                },
434                total_parent_banks: total_parent_banks as i64,
435                tx_count: (new_tx_count - root_tx_count) as i64,
436                dropped_banks_len: dropped_banks_len as i64,
437                accounts_data_len,
438            },
439        ))
440    }
441
442    pub fn prune_program_cache(&self, root: Slot) {
443        if let Some(root_bank) = self.banks.get(&root) {
444            root_bank.prune_program_cache(root, root_bank.epoch());
445        }
446    }
447
448    pub fn set_root(
449        &mut self,
450        root: Slot,
451        snapshot_controller: Option<&SnapshotController>,
452        highest_super_majority_root: Option<Slot>,
453    ) -> Result<Vec<BankWithScheduler>, SetRootError> {
454        let program_cache_prune_start = Instant::now();
455        let set_root_start = Instant::now();
456        let (removed_banks, set_root_metrics) = self.do_set_root_return_metrics(
457            root,
458            snapshot_controller,
459            highest_super_majority_root,
460        )?;
461        datapoint_info!(
462            "bank-forks_set_root",
463            (
464                "elapsed_ms",
465                set_root_start.elapsed().as_millis() as usize,
466                i64
467            ),
468            ("slot", root, i64),
469            (
470                "total_parent_banks",
471                set_root_metrics.total_parent_banks,
472                i64
473            ),
474            ("total_banks", self.banks.len(), i64),
475            (
476                "total_squash_cache_ms",
477                set_root_metrics.timings.total_squash_time.squash_cache_ms,
478                i64
479            ),
480            (
481                "total_squash_accounts_ms",
482                set_root_metrics
483                    .timings
484                    .total_squash_time
485                    .squash_accounts_ms,
486                i64
487            ),
488            (
489                "total_squash_accounts_index_ms",
490                set_root_metrics
491                    .timings
492                    .total_squash_time
493                    .squash_accounts_index_ms,
494                i64
495            ),
496            (
497                "total_squash_accounts_cache_ms",
498                set_root_metrics
499                    .timings
500                    .total_squash_time
501                    .squash_accounts_cache_ms,
502                i64
503            ),
504            (
505                "total_squash_accounts_store_ms",
506                set_root_metrics
507                    .timings
508                    .total_squash_time
509                    .squash_accounts_store_ms,
510                i64
511            ),
512            (
513                "total_snapshot_ms",
514                set_root_metrics.timings.total_snapshot_ms,
515                i64
516            ),
517            ("tx_count", set_root_metrics.tx_count, i64),
518            (
519                "prune_non_rooted_ms",
520                set_root_metrics.timings.prune_non_rooted_ms,
521                i64
522            ),
523            (
524                "drop_parent_banks_ms",
525                set_root_metrics.timings.drop_parent_banks_ms,
526                i64
527            ),
528            (
529                "prune_slots_ms",
530                set_root_metrics.timings.prune_slots_ms,
531                i64
532            ),
533            (
534                "prune_remove_ms",
535                set_root_metrics.timings.prune_remove_ms,
536                i64
537            ),
538            (
539                "program_cache_prune_ms",
540                program_cache_prune_start.elapsed().as_millis() as i64,
541                i64
542            ),
543            ("dropped_banks_len", set_root_metrics.dropped_banks_len, i64),
544            ("accounts_data_len", set_root_metrics.accounts_data_len, i64),
545        );
546        Ok(removed_banks)
547    }
548
549    pub fn root(&self) -> Slot {
550        self.root.load(Ordering::Relaxed)
551    }
552
553    /// Gets a read-only wrapper to an atomic slot holding the root slot.
554    pub fn get_atomic_root(&self) -> ReadOnlyAtomicSlot {
555        ReadOnlyAtomicSlot {
556            slot: self.root.clone(),
557        }
558    }
559
560    /// After setting a new root, prune the banks that are no longer on rooted paths
561    ///
562    /// Given the following banks and slots...
563    ///
564    /// ```text
565    /// slot 6                   * (G)
566    ///                         /
567    /// slot 5        (F)  *   /
568    ///                    |  /
569    /// slot 4    (E) *    | /
570    ///               |    |/
571    /// slot 3        |    * (D) <-- root, from set_root()
572    ///               |    |
573    /// slot 2    (C) *    |
574    ///                \   |
575    /// slot 1          \  * (B)
576    ///                  \ |
577    /// slot 0             * (A)  <-- highest confirmed root [1]
578    /// ```
579    ///
580    /// ...where (D) is set as root, clean up (C) and (E), since they are not rooted.
581    ///
582    /// (A) is kept because it is greater-than-or-equal-to the highest confirmed root, and (D) is
583    ///     one of its descendants
584    /// (B) is kept for the same reason as (A)
585    /// (C) is pruned since it is a lower slot than (D), but (D) is _not_ one of its descendants
586    /// (D) is kept since it is the root
587    /// (E) is pruned since it is not a descendant of (D)
588    /// (F) is kept since it is a descendant of (D)
589    /// (G) is kept for the same reason as (F)
590    ///
591    /// and in table form...
592    ///
593    /// ```text
594    ///       |          |  is root a  | is a descendant ||
595    ///  slot | is root? | descendant? |    of root?     || keep?
596    /// ------+----------+-------------+-----------------++-------
597    ///   (A) |     N    |      Y      |        N        ||   Y
598    ///   (B) |     N    |      Y      |        N        ||   Y
599    ///   (C) |     N    |      N      |        N        ||   N
600    ///   (D) |     Y    |      N      |        N        ||   Y
601    ///   (E) |     N    |      N      |        N        ||   N
602    ///   (F) |     N    |      N      |        Y        ||   Y
603    ///   (G) |     N    |      N      |        Y        ||   Y
604    /// ```
605    ///
606    /// [1] RPC has the concept of commitment level, which is based on the highest confirmed root,
607    /// i.e. the cluster-confirmed root.  This commitment is stronger than the local node's root.
608    /// So (A) and (B) are kept to facilitate RPC at different commitment levels.  Everything below
609    /// the highest confirmed root can be pruned.
610    fn prune_non_rooted(
611        &mut self,
612        root: Slot,
613        highest_super_majority_root: Option<Slot>,
614    ) -> (Vec<BankWithScheduler>, u64, u64) {
615        // We want to collect timing separately, and the 2nd collect requires
616        // a unique borrow to self which is already borrowed by self.banks
617        let mut prune_slots_time = Measure::start("prune_slots");
618        let highest_super_majority_root = highest_super_majority_root.unwrap_or(root);
619        let prune_slots: Vec<_> = self
620            .banks
621            .keys()
622            .copied()
623            .filter(|slot| {
624                let keep = *slot == root
625                    || self.descendants[&root].contains(slot)
626                    || (*slot < root
627                        && *slot >= highest_super_majority_root
628                        && self.descendants[slot].contains(&root));
629                !keep
630            })
631            .collect();
632        prune_slots_time.stop();
633
634        let mut prune_remove_time = Measure::start("prune_slots");
635        let removed_banks = prune_slots
636            .into_iter()
637            .filter_map(|slot| self.remove(slot))
638            .collect();
639        prune_remove_time.stop();
640
641        (
642            removed_banks,
643            prune_slots_time.as_ms(),
644            prune_remove_time.as_ms(),
645        )
646    }
647}
648
649impl ForkGraph for BankForks {
650    fn relationship(&self, a: Slot, b: Slot) -> BlockRelation {
651        let known_slot_range = self.root()..=self.highest_slot();
652        if known_slot_range.contains(&a) && known_slot_range.contains(&b) {
653            {
654                (a == b)
655                    .then_some(BlockRelation::Equal)
656                    .or_else(|| {
657                        self.banks.get(&b).and_then(|bank| {
658                            bank.ancestors
659                                .contains_key(&a)
660                                .then_some(BlockRelation::Ancestor)
661                        })
662                    })
663                    .or_else(|| {
664                        self.descendants.get(&b).and_then(|slots| {
665                            slots.contains(&a).then_some(BlockRelation::Descendant)
666                        })
667                    })
668                    .unwrap_or(BlockRelation::Unrelated)
669            }
670        } else {
671            BlockRelation::Unknown
672        }
673    }
674}
675
676impl Drop for BankForks {
677    fn drop(&mut self) {
678        info!("BankForks::drop(): started...");
679        self.banks.clear();
680
681        if let Some(scheduler_pool) = self.scheduler_pool.take() {
682            scheduler_pool.uninstalled_from_bank_forks();
683        }
684        info!("BankForks::drop(): ...finished");
685    }
686}
687
688#[cfg(test)]
689mod tests {
690    use {
691        super::*,
692        crate::{
693            bank::test_utils::update_vote_account_timestamp,
694            genesis_utils::{
695                create_genesis_config, create_genesis_config_with_leader, GenesisConfigInfo,
696            },
697        },
698        assert_matches::assert_matches,
699        solana_clock::UnixTimestamp,
700        solana_epoch_schedule::EpochSchedule,
701        solana_keypair::Keypair,
702        solana_pubkey::Pubkey,
703        solana_signer::Signer,
704        solana_vote_program::vote_state::BlockTimestamp,
705    };
706
707    #[test]
708    fn test_bank_forks_new_rw_arc_memory_leak() {
709        for _ in 0..1000 {
710            let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
711            BankForks::new_rw_arc(Bank::new_for_tests(&genesis_config));
712        }
713    }
714
715    #[test]
716    fn test_bank_forks_new() {
717        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
718        let bank = Bank::new_for_tests(&genesis_config);
719        let bank_forks = BankForks::new_rw_arc(bank);
720        let mut bank_forks = bank_forks.write().unwrap();
721        let child_bank = Bank::new_from_parent(bank_forks[0].clone(), &Pubkey::default(), 1);
722        child_bank.register_default_tick_for_test();
723        bank_forks.insert(child_bank);
724        assert_eq!(bank_forks[1u64].tick_height(), 1);
725        assert_eq!(bank_forks.working_bank().tick_height(), 1);
726    }
727
728    #[test]
729    fn test_bank_forks_descendants() {
730        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
731        let bank = Bank::new_for_tests(&genesis_config);
732        let bank_forks = BankForks::new_rw_arc(bank);
733        let mut bank_forks = bank_forks.write().unwrap();
734        let bank0 = bank_forks[0].clone();
735        let bank = Bank::new_from_parent(bank0.clone(), &Pubkey::default(), 1);
736        bank_forks.insert(bank);
737        let bank = Bank::new_from_parent(bank0, &Pubkey::default(), 2);
738        bank_forks.insert(bank);
739        let descendants = bank_forks.descendants();
740        let children: HashSet<u64> = [1u64, 2u64].iter().copied().collect();
741        assert_eq!(children, *descendants.get(&0).unwrap());
742        assert!(descendants[&1].is_empty());
743        assert!(descendants[&2].is_empty());
744    }
745
746    #[test]
747    fn test_bank_forks_ancestors() {
748        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
749        let bank = Bank::new_for_tests(&genesis_config);
750        let bank_forks = BankForks::new_rw_arc(bank);
751        let mut bank_forks = bank_forks.write().unwrap();
752        let bank0 = bank_forks[0].clone();
753        let bank = Bank::new_from_parent(bank0.clone(), &Pubkey::default(), 1);
754        bank_forks.insert(bank);
755        let bank = Bank::new_from_parent(bank0, &Pubkey::default(), 2);
756        bank_forks.insert(bank);
757        let ancestors = bank_forks.ancestors();
758        assert!(ancestors[&0].is_empty());
759        let parents: Vec<u64> = ancestors[&1].iter().cloned().collect();
760        assert_eq!(parents, vec![0]);
761        let parents: Vec<u64> = ancestors[&2].iter().cloned().collect();
762        assert_eq!(parents, vec![0]);
763    }
764
765    #[test]
766    fn test_bank_forks_frozen_banks() {
767        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
768        let bank = Bank::new_for_tests(&genesis_config);
769        let bank_forks = BankForks::new_rw_arc(bank);
770        let mut bank_forks = bank_forks.write().unwrap();
771        let bank0 = bank_forks[0].clone();
772        let child_bank = Bank::new_from_parent(bank0, &Pubkey::default(), 1);
773        bank_forks.insert(child_bank);
774
775        let frozen_slots: HashSet<Slot> = bank_forks
776            .frozen_banks()
777            .map(|(slot, _bank)| slot)
778            .collect();
779        assert!(frozen_slots.contains(&0));
780        assert!(!frozen_slots.contains(&1));
781    }
782
783    #[test]
784    fn test_bank_forks_active_banks() {
785        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
786        let bank = Bank::new_for_tests(&genesis_config);
787        let bank_forks = BankForks::new_rw_arc(bank);
788        let mut bank_forks = bank_forks.write().unwrap();
789        let bank0 = bank_forks[0].clone();
790        let child_bank = Bank::new_from_parent(bank0, &Pubkey::default(), 1);
791        bank_forks.insert(child_bank);
792        assert_eq!(bank_forks.active_bank_slots(), vec![1]);
793    }
794
795    #[test]
796    fn test_bank_forks_different_set_root() {
797        solana_logger::setup();
798        let leader_keypair = Keypair::new();
799        let GenesisConfigInfo {
800            mut genesis_config,
801            voting_keypair,
802            ..
803        } = create_genesis_config_with_leader(10_000, &leader_keypair.pubkey(), 1_000);
804        let slots_in_epoch = 32;
805        genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
806
807        let bank0 = Bank::new_for_tests(&genesis_config);
808        let bank_forks0 = BankForks::new_rw_arc(bank0);
809        let mut bank_forks0 = bank_forks0.write().unwrap();
810        bank_forks0.set_root(0, None, None).unwrap();
811
812        let bank1 = Bank::new_for_tests(&genesis_config);
813        let bank_forks1 = BankForks::new_rw_arc(bank1);
814        let mut bank_forks1 = bank_forks1.write().unwrap();
815
816        let additional_timestamp_secs = 2;
817
818        let num_slots = slots_in_epoch + 1; // Advance past first epoch boundary
819        for slot in 1..num_slots {
820            // Just after the epoch boundary, timestamp a vote that will shift
821            // Clock::unix_timestamp from Bank::unix_timestamp_from_genesis()
822            let update_timestamp_case = slot == slots_in_epoch;
823
824            let child1 =
825                Bank::new_from_parent(bank_forks0[slot - 1].clone(), &Pubkey::default(), slot);
826            let child2 =
827                Bank::new_from_parent(bank_forks1[slot - 1].clone(), &Pubkey::default(), slot);
828
829            if update_timestamp_case {
830                for child in &[&child1, &child2] {
831                    let recent_timestamp: UnixTimestamp = child.unix_timestamp_from_genesis();
832                    update_vote_account_timestamp(
833                        BlockTimestamp {
834                            slot: child.slot(),
835                            timestamp: recent_timestamp + additional_timestamp_secs,
836                        },
837                        child,
838                        &voting_keypair.pubkey(),
839                    );
840                }
841            }
842
843            // Set root in bank_forks0 to truncate the ancestor history
844            bank_forks0.insert(child1);
845            bank_forks0.set_root(slot, None, None).unwrap();
846
847            // Don't set root in bank_forks1 to keep the ancestor history
848            bank_forks1.insert(child2);
849        }
850        let child1 = &bank_forks0.working_bank();
851        let child2 = &bank_forks1.working_bank();
852
853        child1.freeze();
854        child2.freeze();
855
856        info!("child0.ancestors: {:?}", child1.ancestors);
857        info!("child1.ancestors: {:?}", child2.ancestors);
858        assert_eq!(child1.hash(), child2.hash());
859    }
860
861    fn make_hash_map(data: Vec<(Slot, Vec<Slot>)>) -> HashMap<Slot, HashSet<Slot>> {
862        data.into_iter()
863            .map(|(k, v)| (k, v.into_iter().collect()))
864            .collect()
865    }
866
867    fn extend_bank_forks(bank_forks: Arc<RwLock<BankForks>>, parent_child_pairs: &[(Slot, Slot)]) {
868        for (parent, child) in parent_child_pairs.iter() {
869            let parent: Arc<Bank> = bank_forks.read().unwrap().banks[parent].clone();
870            bank_forks.write().unwrap().insert(Bank::new_from_parent(
871                parent,
872                &Pubkey::default(),
873                *child,
874            ));
875        }
876    }
877
878    #[test]
879    fn test_bank_forks_with_set_root() {
880        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
881        let bank = Bank::new_for_tests(&genesis_config);
882        let bank_forks = BankForks::new_rw_arc(bank);
883
884        let parent_child_pairs = vec![(0, 1), (1, 2), (0, 3), (3, 4)];
885        extend_bank_forks(bank_forks.clone(), &parent_child_pairs);
886
887        assert_eq!(
888            bank_forks.read().unwrap().ancestors(),
889            make_hash_map(vec![
890                (0, vec![]),
891                (1, vec![0]),
892                (2, vec![0, 1]),
893                (3, vec![0]),
894                (4, vec![0, 3]),
895            ])
896        );
897        assert_eq!(
898            bank_forks.read().unwrap().descendants(),
899            make_hash_map(vec![
900                (0, vec![1, 2, 3, 4]),
901                (1, vec![2]),
902                (2, vec![]),
903                (3, vec![4]),
904                (4, vec![]),
905            ])
906        );
907        bank_forks
908            .write()
909            .unwrap()
910            .set_root(
911                2,    // root
912                None, // snapshot_controller
913                None, // highest confirmed root
914            )
915            .unwrap();
916        bank_forks.read().unwrap().get(2).unwrap().squash();
917        assert_eq!(
918            bank_forks.read().unwrap().ancestors(),
919            make_hash_map(vec![(2, vec![]),])
920        );
921        assert_eq!(
922            bank_forks.read().unwrap().descendants(),
923            make_hash_map(vec![(0, vec![2]), (1, vec![2]), (2, vec![]),])
924        );
925
926        let parent_child_pairs = vec![(2, 5), (5, 6)];
927        extend_bank_forks(bank_forks.clone(), &parent_child_pairs);
928        assert_eq!(
929            bank_forks.read().unwrap().ancestors(),
930            make_hash_map(vec![(2, vec![]), (5, vec![2]), (6, vec![2, 5])])
931        );
932        assert_eq!(
933            bank_forks.read().unwrap().descendants(),
934            make_hash_map(vec![
935                (0, vec![2]),
936                (1, vec![2]),
937                (2, vec![5, 6]),
938                (5, vec![6]),
939                (6, vec![])
940            ])
941        );
942    }
943
944    #[test]
945    fn test_bank_forks_with_highest_super_majority_root() {
946        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
947        let bank = Bank::new_for_tests(&genesis_config);
948        assert_eq!(bank.slot(), 0);
949        let bank_forks = BankForks::new_rw_arc(bank);
950
951        let parent_child_pairs = vec![(0, 1), (1, 2), (0, 3), (3, 4)];
952        extend_bank_forks(bank_forks.clone(), &parent_child_pairs);
953
954        assert_eq!(
955            bank_forks.read().unwrap().ancestors(),
956            make_hash_map(vec![
957                (0, vec![]),
958                (1, vec![0]),
959                (2, vec![0, 1]),
960                (3, vec![0]),
961                (4, vec![0, 3]),
962            ])
963        );
964        assert_eq!(
965            bank_forks.read().unwrap().descendants(),
966            make_hash_map(vec![
967                (0, vec![1, 2, 3, 4]),
968                (1, vec![2]),
969                (2, vec![]),
970                (3, vec![4]),
971                (4, vec![]),
972            ])
973        );
974        bank_forks
975            .write()
976            .unwrap()
977            .set_root(
978                2,
979                None,    // snapshot_controller
980                Some(1), // highest confirmed root
981            )
982            .unwrap();
983        bank_forks.read().unwrap().get(2).unwrap().squash();
984        assert_eq!(
985            bank_forks.read().unwrap().ancestors(),
986            make_hash_map(vec![(1, vec![]), (2, vec![]),])
987        );
988        assert_eq!(
989            bank_forks.read().unwrap().descendants(),
990            make_hash_map(vec![(0, vec![1, 2]), (1, vec![2]), (2, vec![]),])
991        );
992
993        let parent_child_pairs = vec![(2, 5), (5, 6)];
994        extend_bank_forks(bank_forks.clone(), &parent_child_pairs);
995        assert_eq!(
996            bank_forks.read().unwrap().ancestors(),
997            make_hash_map(vec![
998                (1, vec![]),
999                (2, vec![]),
1000                (5, vec![2]),
1001                (6, vec![2, 5])
1002            ])
1003        );
1004        assert_eq!(
1005            bank_forks.read().unwrap().descendants(),
1006            make_hash_map(vec![
1007                (0, vec![1, 2]),
1008                (1, vec![2]),
1009                (2, vec![5, 6]),
1010                (5, vec![6]),
1011                (6, vec![])
1012            ])
1013        );
1014    }
1015
1016    #[test]
1017    fn test_fork_graph() {
1018        let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
1019        let bank = Bank::new_for_tests(&genesis_config);
1020        let bank_forks = BankForks::new_rw_arc(bank);
1021
1022        let parent_child_pairs = vec![
1023            (0, 1),
1024            (1, 3),
1025            (3, 8),
1026            (0, 2),
1027            (2, 4),
1028            (4, 5),
1029            (5, 10),
1030            (4, 6),
1031            (6, 12),
1032        ];
1033        extend_bank_forks(bank_forks.clone(), &parent_child_pairs);
1034
1035        // Fork graph created for the test
1036        //                   0
1037        //                 /   \
1038        //                1     2
1039        //                |     |
1040        //                3     4
1041        //                |     | \
1042        //                8     5  6
1043        //                      |   |
1044        //                      10  12
1045        let mut bank_forks = bank_forks.write().unwrap();
1046        assert_matches!(bank_forks.relationship(0, 3), BlockRelation::Ancestor);
1047        assert_matches!(bank_forks.relationship(0, 10), BlockRelation::Ancestor);
1048        assert_matches!(bank_forks.relationship(0, 12), BlockRelation::Ancestor);
1049        assert_matches!(bank_forks.relationship(1, 3), BlockRelation::Ancestor);
1050        assert_matches!(bank_forks.relationship(2, 10), BlockRelation::Ancestor);
1051        assert_matches!(bank_forks.relationship(2, 12), BlockRelation::Ancestor);
1052        assert_matches!(bank_forks.relationship(4, 10), BlockRelation::Ancestor);
1053        assert_matches!(bank_forks.relationship(4, 12), BlockRelation::Ancestor);
1054        assert_matches!(bank_forks.relationship(6, 10), BlockRelation::Unrelated);
1055        assert_matches!(bank_forks.relationship(5, 12), BlockRelation::Unrelated);
1056        assert_matches!(bank_forks.relationship(6, 12), BlockRelation::Ancestor);
1057
1058        assert_matches!(bank_forks.relationship(6, 2), BlockRelation::Descendant);
1059        assert_matches!(bank_forks.relationship(10, 2), BlockRelation::Descendant);
1060        assert_matches!(bank_forks.relationship(8, 3), BlockRelation::Descendant);
1061        assert_matches!(bank_forks.relationship(6, 3), BlockRelation::Unrelated);
1062        assert_matches!(bank_forks.relationship(12, 2), BlockRelation::Descendant);
1063        assert_matches!(bank_forks.relationship(12, 1), BlockRelation::Unrelated);
1064        assert_matches!(bank_forks.relationship(1, 2), BlockRelation::Unrelated);
1065
1066        assert_matches!(bank_forks.relationship(1, 13), BlockRelation::Unknown);
1067        assert_matches!(bank_forks.relationship(13, 2), BlockRelation::Unknown);
1068        bank_forks
1069            .set_root(
1070                2,
1071                None,    // snapshot_controller
1072                Some(1), // highest confirmed root
1073            )
1074            .unwrap();
1075        assert_matches!(bank_forks.relationship(1, 2), BlockRelation::Unknown);
1076        assert_matches!(bank_forks.relationship(2, 0), BlockRelation::Unknown);
1077    }
1078}