Make RootedSlotsIterator for traversing slots on the root fork (#4361)
This commit is contained in:
parent
ead15d294e
commit
1a77486f8e
|
@ -32,9 +32,11 @@ use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
pub use self::meta::*;
|
pub use self::meta::*;
|
||||||
|
pub use self::rooted_slot_iterator::*;
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
mod meta;
|
mod meta;
|
||||||
|
mod rooted_slot_iterator;
|
||||||
|
|
||||||
macro_rules! db_imports {
|
macro_rules! db_imports {
|
||||||
{ $mod:ident, $db:ident, $db_path:expr } => {
|
{ $mod:ident, $db:ident, $db_path:expr } => {
|
||||||
|
@ -74,6 +76,7 @@ pub enum BlocktreeError {
|
||||||
RocksDb(rocksdb::Error),
|
RocksDb(rocksdb::Error),
|
||||||
#[cfg(feature = "kvstore")]
|
#[cfg(feature = "kvstore")]
|
||||||
KvsDb(kvstore::Error),
|
KvsDb(kvstore::Error),
|
||||||
|
SlotNotRooted,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ledger window
|
// ledger window
|
||||||
|
@ -182,6 +185,10 @@ impl Blocktree {
|
||||||
self.orphans_cf.get(slot)
|
self.orphans_cf.get(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rooted_slot_iterator<'a>(&'a self, slot: u64) -> Result<RootedSlotIterator<'a>> {
|
||||||
|
RootedSlotIterator::new(slot, self)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slot_meta_iterator(&self, slot: u64) -> Result<impl Iterator<Item = (u64, SlotMeta)>> {
|
pub fn slot_meta_iterator(&self, slot: u64) -> Result<impl Iterator<Item = (u64, SlotMeta)>> {
|
||||||
let meta_iter = self.db.iter::<cf::SlotMeta>(Some(slot))?;
|
let meta_iter = self.db.iter::<cf::SlotMeta>(Some(slot))?;
|
||||||
Ok(meta_iter.map(|(slot, slot_meta_bytes)| {
|
Ok(meta_iter.map(|(slot, slot_meta_bytes)| {
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
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> {
|
||||||
|
// Clone b/c passing the closure to the map below requires exclusive access to
|
||||||
|
// `self`, which is borrowed here if we don't clone.
|
||||||
|
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_root(0, 0).unwrap();
|
||||||
|
let ticks_per_slot = 5;
|
||||||
|
/*
|
||||||
|
Build a blocktree in the ledger with the following fork structure:
|
||||||
|
|
||||||
|
slot 0
|
||||||
|
|
|
||||||
|
slot 1 <-- set_root(true)
|
||||||
|
/ \
|
||||||
|
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_blocktree_slot_with_ticks(
|
||||||
|
&blocktree,
|
||||||
|
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_blocktree_slot_with_ticks(&blocktree, ticks_per_slot, 4, fork_point, fork_hash);
|
||||||
|
|
||||||
|
// Set a root
|
||||||
|
blocktree.set_root(3, 0).unwrap();
|
||||||
|
|
||||||
|
// Trying to get an iterator on a different fork will error
|
||||||
|
assert!(RootedSlotIterator::new(4, &blocktree).is_err());
|
||||||
|
|
||||||
|
// Trying to get an iterator on any slot on the root fork should succeed
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -281,7 +281,7 @@ pub fn process_blocktree(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::blocktree::create_new_tmp_ledger;
|
use crate::blocktree::create_new_tmp_ledger;
|
||||||
use crate::blocktree::tests::entries_to_blobs;
|
use crate::blocktree::tests::entries_to_blobs;
|
||||||
|
@ -295,7 +295,7 @@ mod tests {
|
||||||
use solana_sdk::system_transaction;
|
use solana_sdk::system_transaction;
|
||||||
use solana_sdk::transaction::TransactionError;
|
use solana_sdk::transaction::TransactionError;
|
||||||
|
|
||||||
fn fill_blocktree_slot_with_ticks(
|
pub fn fill_blocktree_slot_with_ticks(
|
||||||
blocktree: &Blocktree,
|
blocktree: &Blocktree,
|
||||||
ticks_per_slot: u64,
|
ticks_per_slot: u64,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
|
Loading…
Reference in New Issue