use super::*;
pub struct RootedSlotIterator<'a> {
next_slots: Vec<u64>,
blocktree: &'a super::Blocktree,
}
impl<'a> RootedSlotIterator<'a> {
pub fn new(start_slot: u64, blocktree: &'a super::Blocktree) -> Result<Self> {
if blocktree.is_root(start_slot) {
Ok(Self {
next_slots: vec![start_slot],
blocktree,
})
} else {
Err(Error::BlocktreeError(BlocktreeError::SlotNotRooted))
}
}
}
impl<'a> Iterator for RootedSlotIterator<'a> {
type Item = (u64, super::SlotMeta);
fn next(&mut self) -> Option<Self::Item> {
let rooted_slot = self
.next_slots
.iter()
.find(|x| self.blocktree.is_root(**x))
.cloned();
rooted_slot.map(|rooted_slot| {
let slot_meta = self
.blocktree
.meta(rooted_slot)
.expect("Database failure, couldnt fetch SlotMeta")
.expect("SlotMeta in iterator didn't exist");
self.next_slots = slot_meta.next_slots.clone();
(rooted_slot, slot_meta)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::blocktree_processor::tests::fill_blocktree_slot_with_ticks;
#[test]
fn test_rooted_slot_iterator() {
let blocktree_path = get_tmp_ledger_path("test_rooted_slot_iterator");
let blocktree = Blocktree::open(&blocktree_path).unwrap();
blocktree.set_roots(&[0]).unwrap();
let ticks_per_slot = 5;
let last_entry_hash = Hash::default();
let fork_point = 1;
let mut fork_hash = Hash::default();
for slot in 0..=3 {
let parent = {
if slot == 0 {
0
} else {
slot - 1
}
};
let last_entry_hash = fill_blocktree_slot_with_ticks(
&blocktree,
ticks_per_slot,
slot,
parent,
last_entry_hash,
);
if slot == fork_point {
fork_hash = last_entry_hash;
}
}
let _ =
fill_blocktree_slot_with_ticks(&blocktree, ticks_per_slot, 4, fork_point, fork_hash);
blocktree.set_roots(&[1, 2, 3]).unwrap();
assert!(RootedSlotIterator::new(4, &blocktree).is_err());
let result: Vec<_> = RootedSlotIterator::new(3, &blocktree)
.unwrap()
.into_iter()
.map(|(slot, _)| slot)
.collect();
let expected = vec![3];
assert_eq!(result, expected);
let result: Vec<_> = RootedSlotIterator::new(0, &blocktree)
.unwrap()
.into_iter()
.map(|(slot, _)| slot)
.collect();
let expected = vec![0, 1, 2, 3];
assert_eq!(result, expected);
drop(blocktree);
Blocktree::destroy(&blocktree_path).expect("Expected successful database destruction");
}
}