solana_runtime/
bank_hash_cache.rs1use {
11 crate::{bank::Bank, bank_forks::BankForks, root_bank_cache::RootBankCache},
12 solana_sdk::{clock::Slot, hash::Hash},
13 std::{
14 collections::BTreeMap,
15 sync::{Arc, Mutex, MutexGuard, RwLock},
16 },
17};
18
19pub type DumpedSlotSubscription = Arc<Mutex<bool>>;
21
22pub struct BankHashCache {
23 hashes: BTreeMap<Slot, Hash>,
24 bank_forks: Arc<RwLock<BankForks>>,
25 root_bank_cache: RootBankCache,
26 last_root: Slot,
27 dumped_slot_subscription: DumpedSlotSubscription,
28}
29
30impl BankHashCache {
31 pub fn new(bank_forks: Arc<RwLock<BankForks>>) -> Self {
32 let root_bank_cache = RootBankCache::new(bank_forks.clone());
33 let dumped_slot_subscription = DumpedSlotSubscription::default();
34 bank_forks
35 .write()
36 .unwrap()
37 .register_dumped_slot_subscriber(dumped_slot_subscription.clone());
38 Self {
39 hashes: BTreeMap::default(),
40 bank_forks,
41 root_bank_cache,
42 last_root: 0,
43 dumped_slot_subscription,
44 }
45 }
46
47 pub fn dumped_slot_subscription(&self) -> DumpedSlotSubscription {
48 self.dumped_slot_subscription.clone()
49 }
50
51 pub fn hash(&mut self, slot: Slot, slots_dumped: &mut MutexGuard<bool>) -> Option<Hash> {
56 if **slots_dumped {
57 self.hashes.clear();
60 **slots_dumped = false;
61 }
62
63 if let Some(hash) = self.hashes.get(&slot) {
64 return Some(*hash);
65 }
66
67 let Some(hash) = self.bank_forks.read().unwrap().bank_hash(slot) else {
68 return None;
70 };
71
72 if hash == Hash::default() {
73 return None;
75 }
76
77 let prev_hash = self.hashes.insert(slot, hash);
79 debug_assert!(
80 prev_hash.is_none(),
81 "Programmer error, this indicates we have dumped and replayed \
82 a block however the cache was not invalidated"
83 );
84 Some(hash)
85 }
86
87 pub fn root(&mut self) -> Slot {
88 self.get_root_bank_and_prune_cache().slot()
89 }
90
91 pub fn get_root_bank_and_prune_cache(&mut self) -> Arc<Bank> {
93 let root_bank = self.root_bank_cache.root_bank();
94 if root_bank.slot() != self.last_root {
95 self.last_root = root_bank.slot();
96 self.hashes = self.hashes.split_off(&self.last_root);
97 }
98 root_bank
99 }
100}