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