@@ -12,6 +12,7 @@ pub mod genesis_utils;
 | 
			
		||||
pub mod leader_schedule;
 | 
			
		||||
pub mod leader_schedule_cache;
 | 
			
		||||
pub mod leader_schedule_utils;
 | 
			
		||||
pub mod next_slots_iterator;
 | 
			
		||||
pub mod poh;
 | 
			
		||||
pub mod rooted_slot_iterator;
 | 
			
		||||
pub mod shred;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										117
									
								
								ledger/src/next_slots_iterator.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								ledger/src/next_slots_iterator.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
use crate::{blockstore::*, blockstore_meta::SlotMeta};
 | 
			
		||||
use solana_sdk::clock::Slot;
 | 
			
		||||
 | 
			
		||||
pub struct NextSlotsIterator<'a> {
 | 
			
		||||
    pending_slots: Vec<Slot>,
 | 
			
		||||
    blockstore: &'a Blockstore,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> NextSlotsIterator<'a> {
 | 
			
		||||
    pub fn new(start_slot: Slot, blockstore: &'a Blockstore) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            pending_slots: vec![start_slot],
 | 
			
		||||
            blockstore,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> Iterator for NextSlotsIterator<'a> {
 | 
			
		||||
    type Item = (Slot, SlotMeta);
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        if self.pending_slots.is_empty() {
 | 
			
		||||
            None
 | 
			
		||||
        } else {
 | 
			
		||||
            let slot = self.pending_slots.pop().unwrap();
 | 
			
		||||
            if let Some(slot_meta) = self.blockstore.meta(slot).unwrap() {
 | 
			
		||||
                self.pending_slots.extend(slot_meta.next_slots.iter());
 | 
			
		||||
                Some((slot, slot_meta))
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::blockstore_processor::fill_blockstore_slot_with_ticks;
 | 
			
		||||
    use solana_sdk::hash::Hash;
 | 
			
		||||
    use std::collections::HashSet;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_next_slots_iterator() {
 | 
			
		||||
        let blockstore_path = get_tmp_ledger_path!();
 | 
			
		||||
        let blockstore = Blockstore::open(&blockstore_path).unwrap();
 | 
			
		||||
        blockstore.set_roots(&[0]).unwrap();
 | 
			
		||||
        let ticks_per_slot = 5;
 | 
			
		||||
        /*
 | 
			
		||||
            Build a blockstore in the ledger with the following fork structure:
 | 
			
		||||
 | 
			
		||||
                 slot 0
 | 
			
		||||
                   |
 | 
			
		||||
                 slot 1  <-- set_root
 | 
			
		||||
                 /   \
 | 
			
		||||
            slot 2   |
 | 
			
		||||
               /     |
 | 
			
		||||
            slot 3   |
 | 
			
		||||
                     |
 | 
			
		||||
                   slot 4
 | 
			
		||||
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        // Fork 1, ending at slot 3
 | 
			
		||||
        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_blockstore_slot_with_ticks(
 | 
			
		||||
                &blockstore,
 | 
			
		||||
                ticks_per_slot,
 | 
			
		||||
                slot,
 | 
			
		||||
                parent,
 | 
			
		||||
                last_entry_hash,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if slot == fork_point {
 | 
			
		||||
                fork_hash = last_entry_hash;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Fork 2, ending at slot 4
 | 
			
		||||
        let _ =
 | 
			
		||||
            fill_blockstore_slot_with_ticks(&blockstore, ticks_per_slot, 4, fork_point, fork_hash);
 | 
			
		||||
 | 
			
		||||
        // Trying to get an iterator on any slot on the root fork should succeed
 | 
			
		||||
        let result: HashSet<_> = NextSlotsIterator::new(0, &blockstore)
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|(slot, _)| slot)
 | 
			
		||||
            .collect();
 | 
			
		||||
        let expected = vec![0, 1, 2, 3, 4].into_iter().collect();
 | 
			
		||||
        assert_eq!(result, expected);
 | 
			
		||||
 | 
			
		||||
        let result: HashSet<_> = NextSlotsIterator::new(2, &blockstore)
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|(slot, _)| slot)
 | 
			
		||||
            .collect();
 | 
			
		||||
        let expected = vec![2, 3].into_iter().collect();
 | 
			
		||||
        assert_eq!(result, expected);
 | 
			
		||||
 | 
			
		||||
        let result: HashSet<_> = NextSlotsIterator::new(4, &blockstore)
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(|(slot, _)| slot)
 | 
			
		||||
            .collect();
 | 
			
		||||
        let expected = vec![4].into_iter().collect();
 | 
			
		||||
        assert_eq!(result, expected);
 | 
			
		||||
 | 
			
		||||
        drop(blockstore);
 | 
			
		||||
        Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user