solana_ledger/
rooted_slot_iterator.rs1use {
2 crate::{blockstore::*, blockstore_meta::SlotMeta},
3 log::*,
4 solana_clock::Slot,
5};
6
7pub struct RootedSlotIterator<'a> {
8 next_slots: Vec<Slot>,
9 prev_root: Slot,
10 blockstore: &'a Blockstore,
11}
12
13impl<'a> RootedSlotIterator<'a> {
14 pub fn new(start_slot: Slot, blockstore: &'a Blockstore) -> Result<Self> {
15 if blockstore.is_root(start_slot) {
16 Ok(Self {
17 next_slots: vec![start_slot],
18 prev_root: start_slot,
19 blockstore,
20 })
21 } else {
22 Err(BlockstoreError::SlotNotRooted)
23 }
24 }
25}
26impl Iterator for RootedSlotIterator<'_> {
27 type Item = (Slot, Option<SlotMeta>);
28
29 fn next(&mut self) -> Option<Self::Item> {
30 let (rooted_slot, slot_skipped) = self
33 .next_slots
34 .iter()
35 .find(|x| self.blockstore.is_root(**x))
36 .map(|x| (Some(*x), false))
37 .unwrap_or_else(|| {
38 let mut iter = self
39 .blockstore
40 .rooted_slot_iterator(
41 self.prev_root,
45 )
46 .expect("Database failure, couldn't fetch rooted slots iterator");
47 iter.next();
48 (iter.next(), true)
49 });
50
51 let slot_meta = rooted_slot
52 .map(|r| {
53 self.blockstore
54 .meta(r)
55 .expect("Database failure, couldn't fetch SlotMeta")
56 })
57 .unwrap_or(None);
58
59 if let Some(ref slot_meta) = slot_meta {
60 self.next_slots.clone_from(&slot_meta.next_slots);
61 }
62
63 if slot_meta.is_none() && slot_skipped {
64 warn!("Rooted SlotMeta was deleted in between checking is_root and fetch");
65 }
66
67 rooted_slot.map(|r| {
68 self.prev_root = r;
69 if slot_skipped {
70 (r, None)
71 } else {
72 (r, slot_meta)
73 }
74 })
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use {
81 super::*, crate::blockstore_processor::fill_blockstore_slot_with_ticks, solana_hash::Hash,
82 };
83
84 #[test]
85 fn test_rooted_slot_iterator() {
86 let ledger_path = get_tmp_ledger_path_auto_delete!();
87 let blockstore = Blockstore::open(ledger_path.path()).unwrap();
88 blockstore.set_roots(std::iter::once(&0)).unwrap();
89 let ticks_per_slot = 5;
90 let last_entry_hash = Hash::default();
107 let fork_point = 1;
108 let mut fork_hash = Hash::default();
109 for slot in 0..=3 {
110 let parent = {
111 if slot == 0 {
112 0
113 } else {
114 slot - 1
115 }
116 };
117 let last_entry_hash = fill_blockstore_slot_with_ticks(
118 &blockstore,
119 ticks_per_slot,
120 slot,
121 parent,
122 last_entry_hash,
123 );
124
125 if slot == fork_point {
126 fork_hash = last_entry_hash;
127 }
128 }
129
130 let _ =
132 fill_blockstore_slot_with_ticks(&blockstore, ticks_per_slot, 4, fork_point, fork_hash);
133
134 blockstore.set_roots([1, 2, 3].iter()).unwrap();
136
137 assert!(RootedSlotIterator::new(4, &blockstore).is_err());
139
140 let result: Vec<_> = RootedSlotIterator::new(3, &blockstore)
142 .unwrap()
143 .map(|(slot, _)| slot)
144 .collect();
145 let expected = vec![3];
146 assert_eq!(result, expected);
147
148 let result: Vec<_> = RootedSlotIterator::new(0, &blockstore)
149 .unwrap()
150 .map(|(slot, _)| slot)
151 .collect();
152 let expected = vec![0, 1, 2, 3];
153 assert_eq!(result, expected);
154 }
155
156 #[test]
157 fn test_skipping_rooted_slot_iterator() {
158 let ledger_path = get_tmp_ledger_path_auto_delete!();
159 let blockstore = Blockstore::open(ledger_path.path()).unwrap();
160 let ticks_per_slot = 5;
161 for slot in 0..=3 {
180 let parent = {
181 if slot == 0 {
182 0
183 } else {
184 slot - 1
185 }
186 };
187 fill_blockstore_slot_with_ticks(
188 &blockstore,
189 ticks_per_slot,
190 slot,
191 parent,
192 Hash::default(),
193 );
194 }
195
196 blockstore.set_roots([0, 1, 2, 3].iter()).unwrap();
198
199 blockstore.set_roots(std::iter::once(&10)).unwrap();
202 let result: Vec<_> = RootedSlotIterator::new(3, &blockstore)
205 .unwrap()
206 .map(|(slot, meta)| (slot, meta.is_some()))
207 .collect();
208 let expected = vec![(3, true), (10, false)];
209 assert_eq!(result, expected);
210
211 fill_blockstore_slot_with_ticks(&blockstore, ticks_per_slot, 11, 10, Hash::default());
213
214 blockstore.set_roots(std::iter::once(&11)).unwrap();
216
217 let result: Vec<_> = RootedSlotIterator::new(0, &blockstore)
218 .unwrap()
219 .map(|(slot, meta)| (slot, meta.is_some()))
220 .collect();
221 let expected = vec![
222 (0, true),
223 (1, true),
224 (2, true),
225 (3, true),
226 (10, false),
227 (11, true),
228 ];
229 assert_eq!(result, expected);
230 }
231}