solana/ledger/src/ancestor_iterator.rs

186 lines
5.4 KiB
Rust
Raw Normal View History

use {
crate::blockstore::*,
solana_sdk::{clock::Slot, hash::Hash},
};
pub struct AncestorIterator<'a> {
current: Option<Slot>,
blockstore: &'a Blockstore,
}
impl<'a> AncestorIterator<'a> {
pub fn new(start_slot: Slot, blockstore: &'a Blockstore) -> Self {
let current = blockstore.meta(start_slot).unwrap().and_then(|slot_meta| {
if start_slot != 0 {
slot_meta.parent_slot
} else {
None
}
});
Self {
current,
blockstore,
}
}
Persistent tower (#10718) * Save/restore Tower * Avoid unwrap() * Rebase cleanups * Forcibly pass test * Correct reconcilation of votes after validator resume * d b g * Add more tests * fsync and fix test * Add test * Fix fmt * Debug * Fix tests... * save * Clarify error message and code cleaning around it * Move most of code out of tower save hot codepath * Proper comment for the lack of fsync on tower * Clean up * Clean up * Simpler type alias * Manage tower-restored ancestor slots without banks * Add comment * Extract long code blocks... * Add comment * Simplify returned tuple... * Tweak too aggresive log * Fix typo... * Add test * Update comment * Improve test to require non-empty stray restored slots * Measure tower save and dump all tower contents * Log adjust and add threshold related assertions * cleanup adjust * Properly lower stray restored slots priority... * Rust fmt * Fix test.... * Clarify comments a bit and add TowerError::TooNew * Further clean-up arround TowerError * Truly create ancestors by excluding last vote slot * Add comment for stray_restored_slots * Add comment for stray_restored_slots * Use BTreeSet * Consider root_slot into post-replay adjustment * Tweak logging * Add test for stray_restored_ancestors * Reorder some code * Better names for unit tests * Add frozen_abi to SavedTower * Fold long lines * Tweak stray ancestors and too old slot history * Re-adjust error conditon of too old slot history * Test normal ancestors is checked before stray ones * Fix conflict, update tests, adjust behavior a bit * Fix test * Address review comments * Last touch! * Immediately after creating cleaning pr * Revert stray slots * Revert comment... * Report error as metrics * Revert not to panic! and ignore unfixable test... * Normalize lockouts.root_slot more strictly * Add comments for panic! and more assertions * Proper initialize root without vote account * Clarify code and comments based on review feedback * Fix rebase * Further simplify based on assured tower root * Reorder code for more readability Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-18 22:03:54 -07:00
pub fn new_inclusive(start_slot: Slot, blockstore: &'a Blockstore) -> Self {
Self {
current: blockstore.meta(start_slot).unwrap().map(|_| start_slot),
blockstore,
}
}
}
impl<'a> Iterator for AncestorIterator<'a> {
type Item = Slot;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
current.map(|slot| {
if slot != 0 {
self.current = self
.blockstore
.meta(slot)
.unwrap()
.and_then(|slot_meta| slot_meta.parent_slot);
} else {
self.current = None;
}
slot
})
}
}
pub struct AncestorIteratorWithHash<'a> {
ancestor_iterator: AncestorIterator<'a>,
}
impl<'a> From<AncestorIterator<'a>> for AncestorIteratorWithHash<'a> {
fn from(ancestor_iterator: AncestorIterator<'a>) -> Self {
Self { ancestor_iterator }
}
}
impl<'a> Iterator for AncestorIteratorWithHash<'a> {
type Item = (Slot, Hash);
fn next(&mut self) -> Option<Self::Item> {
self.ancestor_iterator
.next()
.and_then(|next_ancestor_slot| {
self.ancestor_iterator
.blockstore
.get_bank_hash(next_ancestor_slot)
.map(|next_ancestor_hash| (next_ancestor_slot, next_ancestor_hash))
})
}
}
#[cfg(test)]
mod tests {
use {
super::*,
solana_sdk::hash::Hash,
std::{collections::HashMap, path::Path},
trees::tr,
};
fn setup_forks(ledger_path: &Path) -> Blockstore {
let blockstore = Blockstore::open(ledger_path).unwrap();
/*
Build fork structure:
slot 0
|
slot 1
/ \
slot 2 |
| |
slot 3 |
|
|
slot 4
*/
let tree = tr(0) / (tr(1) / (tr(2) / (tr(3))) / (tr(4)));
blockstore.add_tree(tree, true, true, 2, Hash::default());
blockstore
}
#[test]
fn test_ancestor_iterator() {
let ledger_path = get_tmp_ledger_path_auto_delete!();
let blockstore = setup_forks(ledger_path.path());
// Test correctness
assert!(AncestorIterator::new(0, &blockstore).next().is_none());
assert_eq!(
AncestorIterator::new(4, &blockstore).collect::<Vec<Slot>>(),
vec![1, 0]
);
assert_eq!(
AncestorIterator::new(3, &blockstore).collect::<Vec<Slot>>(),
vec![2, 1, 0]
);
}
Persistent tower (#10718) * Save/restore Tower * Avoid unwrap() * Rebase cleanups * Forcibly pass test * Correct reconcilation of votes after validator resume * d b g * Add more tests * fsync and fix test * Add test * Fix fmt * Debug * Fix tests... * save * Clarify error message and code cleaning around it * Move most of code out of tower save hot codepath * Proper comment for the lack of fsync on tower * Clean up * Clean up * Simpler type alias * Manage tower-restored ancestor slots without banks * Add comment * Extract long code blocks... * Add comment * Simplify returned tuple... * Tweak too aggresive log * Fix typo... * Add test * Update comment * Improve test to require non-empty stray restored slots * Measure tower save and dump all tower contents * Log adjust and add threshold related assertions * cleanup adjust * Properly lower stray restored slots priority... * Rust fmt * Fix test.... * Clarify comments a bit and add TowerError::TooNew * Further clean-up arround TowerError * Truly create ancestors by excluding last vote slot * Add comment for stray_restored_slots * Add comment for stray_restored_slots * Use BTreeSet * Consider root_slot into post-replay adjustment * Tweak logging * Add test for stray_restored_ancestors * Reorder some code * Better names for unit tests * Add frozen_abi to SavedTower * Fold long lines * Tweak stray ancestors and too old slot history * Re-adjust error conditon of too old slot history * Test normal ancestors is checked before stray ones * Fix conflict, update tests, adjust behavior a bit * Fix test * Address review comments * Last touch! * Immediately after creating cleaning pr * Revert stray slots * Revert comment... * Report error as metrics * Revert not to panic! and ignore unfixable test... * Normalize lockouts.root_slot more strictly * Add comments for panic! and more assertions * Proper initialize root without vote account * Clarify code and comments based on review feedback * Fix rebase * Further simplify based on assured tower root * Reorder code for more readability Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-18 22:03:54 -07:00
#[test]
fn test_ancestor_iterator_inclusive() {
let ledger_path = get_tmp_ledger_path_auto_delete!();
let blockstore = Blockstore::open(ledger_path.path()).unwrap();
Persistent tower (#10718) * Save/restore Tower * Avoid unwrap() * Rebase cleanups * Forcibly pass test * Correct reconcilation of votes after validator resume * d b g * Add more tests * fsync and fix test * Add test * Fix fmt * Debug * Fix tests... * save * Clarify error message and code cleaning around it * Move most of code out of tower save hot codepath * Proper comment for the lack of fsync on tower * Clean up * Clean up * Simpler type alias * Manage tower-restored ancestor slots without banks * Add comment * Extract long code blocks... * Add comment * Simplify returned tuple... * Tweak too aggresive log * Fix typo... * Add test * Update comment * Improve test to require non-empty stray restored slots * Measure tower save and dump all tower contents * Log adjust and add threshold related assertions * cleanup adjust * Properly lower stray restored slots priority... * Rust fmt * Fix test.... * Clarify comments a bit and add TowerError::TooNew * Further clean-up arround TowerError * Truly create ancestors by excluding last vote slot * Add comment for stray_restored_slots * Add comment for stray_restored_slots * Use BTreeSet * Consider root_slot into post-replay adjustment * Tweak logging * Add test for stray_restored_ancestors * Reorder some code * Better names for unit tests * Add frozen_abi to SavedTower * Fold long lines * Tweak stray ancestors and too old slot history * Re-adjust error conditon of too old slot history * Test normal ancestors is checked before stray ones * Fix conflict, update tests, adjust behavior a bit * Fix test * Address review comments * Last touch! * Immediately after creating cleaning pr * Revert stray slots * Revert comment... * Report error as metrics * Revert not to panic! and ignore unfixable test... * Normalize lockouts.root_slot more strictly * Add comments for panic! and more assertions * Proper initialize root without vote account * Clarify code and comments based on review feedback * Fix rebase * Further simplify based on assured tower root * Reorder code for more readability Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-18 22:03:54 -07:00
let (shreds, _) = make_slot_entries(0, 0, 42);
blockstore.insert_shreds(shreds, None, false).unwrap();
let (shreds, _) = make_slot_entries(1, 0, 42);
blockstore.insert_shreds(shreds, None, false).unwrap();
let (shreds, _) = make_slot_entries(2, 1, 42);
blockstore.insert_shreds(shreds, None, false).unwrap();
assert_eq!(
AncestorIterator::new(2, &blockstore).collect::<Vec<Slot>>(),
vec![1, 0]
);
// existing start_slot
assert_eq!(
AncestorIterator::new_inclusive(2, &blockstore).collect::<Vec<Slot>>(),
vec![2, 1, 0]
);
// non-existing start_slot
assert_eq!(
AncestorIterator::new_inclusive(3, &blockstore).collect::<Vec<Slot>>(),
vec![] as Vec<Slot>
);
}
#[test]
fn test_ancestor_iterator_with_hash() {
let ledger_path = get_tmp_ledger_path_auto_delete!();
let blockstore = setup_forks(ledger_path.path());
// Insert frozen hashes
let mut slot_to_bank_hash = HashMap::new();
for slot in 0..=4 {
let bank_hash = Hash::new_unique();
slot_to_bank_hash.insert(slot, bank_hash);
blockstore.insert_bank_hash(slot, bank_hash, false);
}
// Test correctness
assert!(
AncestorIteratorWithHash::from(AncestorIterator::new(0, &blockstore))
.next()
.is_none()
);
assert_eq!(
AncestorIteratorWithHash::from(AncestorIterator::new(4, &blockstore))
.collect::<Vec<(Slot, Hash)>>(),
vec![(1, slot_to_bank_hash[&1]), (0, slot_to_bank_hash[&0])]
);
assert_eq!(
AncestorIteratorWithHash::from(AncestorIterator::new(3, &blockstore))
.collect::<Vec<(Slot, Hash)>>(),
vec![
(2, slot_to_bank_hash[&2]),
(1, slot_to_bank_hash[&1]),
(0, slot_to_bank_hash[&0])
]
);
}
}