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