mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 00:42:42 +00:00
Add error handling to iterators (#1243)
* Add error handling to iterators * Review feedback * Leverage itertools::process_results() in few places
This commit is contained in:
@@ -48,7 +48,7 @@ bls = { path = "../../crypto/bls" }
|
||||
safe_arith = { path = "../../consensus/safe_arith" }
|
||||
environment = { path = "../../lighthouse/environment" }
|
||||
bus = "2.2.3"
|
||||
itertools = "0.9.0"
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ use crate::snapshot_cache::SnapshotCache;
|
||||
use crate::timeout_rw_lock::TimeoutRwLock;
|
||||
use crate::validator_pubkey_cache::ValidatorPubkeyCache;
|
||||
use crate::BeaconSnapshot;
|
||||
use itertools::process_results;
|
||||
use operation_pool::{OperationPool, PersistedOperationPool};
|
||||
use slog::{crit, debug, error, info, trace, warn, Logger};
|
||||
use slot_clock::SlotClock;
|
||||
@@ -319,12 +320,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// - Iterator returns `(Hash256, Slot)`.
|
||||
/// - As this iterator starts at the `head` of the chain (viz., the best block), the first slot
|
||||
/// returned may be earlier than the wall-clock slot.
|
||||
pub fn rev_iter_block_roots(&self) -> Result<impl Iterator<Item = (Hash256, Slot)>, Error> {
|
||||
pub fn rev_iter_block_roots(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = Result<(Hash256, Slot), Error>>, Error> {
|
||||
let head = self.head()?;
|
||||
|
||||
let iter = BlockRootsIterator::owned(self.store.clone(), head.beacon_state);
|
||||
|
||||
Ok(std::iter::once((head.beacon_block_root, head.beacon_block.slot())).chain(iter))
|
||||
Ok(
|
||||
std::iter::once(Ok((head.beacon_block_root, head.beacon_block.slot())))
|
||||
.chain(iter)
|
||||
.map(|result| result.map_err(|e| e.into())),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn forwards_iter_block_roots(
|
||||
@@ -339,7 +344,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
local_head.beacon_state,
|
||||
local_head.beacon_block_root,
|
||||
&self.spec,
|
||||
))
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Traverse backwards from `block_root` to find the block roots of its ancestors.
|
||||
@@ -354,7 +359,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn rev_iter_block_roots_from(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
) -> Result<impl Iterator<Item = (Hash256, Slot)>, Error> {
|
||||
) -> Result<impl Iterator<Item = Result<(Hash256, Slot), Error>>, Error> {
|
||||
let block = self
|
||||
.get_block(&block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(block_root))?;
|
||||
@@ -362,7 +367,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.get_state(&block.state_root(), Some(block.slot()))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(block.state_root()))?;
|
||||
let iter = BlockRootsIterator::owned(self.store.clone(), state);
|
||||
Ok(std::iter::once((block_root, block.slot())).chain(iter))
|
||||
Ok(std::iter::once(Ok((block_root, block.slot())))
|
||||
.chain(iter)
|
||||
.map(|result| result.map_err(|e| e.into())))
|
||||
}
|
||||
|
||||
/// Traverse backwards from `block_root` to find the root of the ancestor block at `slot`.
|
||||
@@ -371,10 +378,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
block_root: Hash256,
|
||||
slot: Slot,
|
||||
) -> Result<Option<Hash256>, Error> {
|
||||
Ok(self
|
||||
.rev_iter_block_roots_from(block_root)?
|
||||
.find(|(_, ancestor_slot)| *ancestor_slot == slot)
|
||||
.map(|(ancestor_block_root, _)| ancestor_block_root))
|
||||
process_results(self.rev_iter_block_roots_from(block_root)?, |mut iter| {
|
||||
iter.find(|(_, ancestor_slot)| *ancestor_slot == slot)
|
||||
.map(|(ancestor_block_root, _)| ancestor_block_root)
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterates across all `(state_root, slot)` pairs from the head of the chain (inclusive) to
|
||||
@@ -386,13 +393,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// - Iterator returns `(Hash256, Slot)`.
|
||||
/// - As this iterator starts at the `head` of the chain (viz., the best block), the first slot
|
||||
/// returned may be earlier than the wall-clock slot.
|
||||
pub fn rev_iter_state_roots(&self) -> Result<impl Iterator<Item = (Hash256, Slot)>, Error> {
|
||||
pub fn rev_iter_state_roots(
|
||||
&self,
|
||||
) -> Result<impl Iterator<Item = Result<(Hash256, Slot), Error>>, Error> {
|
||||
let head = self.head()?;
|
||||
let slot = head.beacon_state.slot;
|
||||
|
||||
let iter = StateRootsIterator::owned(self.store.clone(), head.beacon_state);
|
||||
|
||||
Ok(std::iter::once((head.beacon_state_root, slot)).chain(iter))
|
||||
let iter = std::iter::once(Ok((head.beacon_state_root, slot)))
|
||||
.chain(iter)
|
||||
.map(|result| result.map_err(Into::into));
|
||||
Ok(iter)
|
||||
}
|
||||
|
||||
/// Returns the block at the given slot, if any. Only returns blocks in the canonical chain.
|
||||
@@ -404,10 +414,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
&self,
|
||||
slot: Slot,
|
||||
) -> Result<Option<SignedBeaconBlock<T::EthSpec>>, Error> {
|
||||
let root = self
|
||||
.rev_iter_block_roots()?
|
||||
.find(|(_, this_slot)| *this_slot == slot)
|
||||
.map(|(root, _)| root);
|
||||
let root = process_results(self.rev_iter_block_roots()?, |mut iter| {
|
||||
iter.find(|(_, this_slot)| *this_slot == slot)
|
||||
.map(|(root, _)| root)
|
||||
})?;
|
||||
|
||||
if let Some(block_root) = root {
|
||||
Ok(self.store.get_item(&block_root)?)
|
||||
@@ -553,12 +563,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
Ok(state)
|
||||
}
|
||||
Ordering::Less => {
|
||||
let state_root = self
|
||||
.rev_iter_state_roots()?
|
||||
.take_while(|(_root, current_slot)| *current_slot >= slot)
|
||||
.find(|(_root, current_slot)| *current_slot == slot)
|
||||
.map(|(root, _slot)| root)
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?;
|
||||
let state_root = process_results(self.rev_iter_state_roots()?, |iter| {
|
||||
iter.take_while(|(_, current_slot)| *current_slot >= slot)
|
||||
.find(|(_, current_slot)| *current_slot == slot)
|
||||
.map(|(root, _slot)| root)
|
||||
})?
|
||||
.ok_or_else(|| Error::NoStateForSlot(slot))?;
|
||||
|
||||
Ok(self
|
||||
.get_state(&state_root, Some(slot))?
|
||||
@@ -633,10 +643,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
///
|
||||
/// Returns None if a block doesn't exist at the slot.
|
||||
pub fn root_at_slot(&self, target_slot: Slot) -> Result<Option<Hash256>, Error> {
|
||||
Ok(self
|
||||
.rev_iter_block_roots()?
|
||||
.find(|(_root, slot)| *slot == target_slot)
|
||||
.map(|(root, _slot)| root))
|
||||
process_results(self.rev_iter_block_roots()?, |mut iter| {
|
||||
iter.find(|(_, slot)| *slot == target_slot)
|
||||
.map(|(root, _)| root)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the block proposer for a given slot.
|
||||
|
||||
@@ -84,9 +84,10 @@ pub trait Migrate<E: EthSpec>: Send + Sync + 'static {
|
||||
.ok_or_else(|| BeaconStateError::MissingBeaconBlock(head_hash.into()))?
|
||||
.state_root();
|
||||
|
||||
let iterator = std::iter::once((head_hash, head_state_hash, head_slot))
|
||||
let iter = std::iter::once(Ok((head_hash, head_state_hash, head_slot)))
|
||||
.chain(RootsIterator::from_block(Arc::clone(&store), head_hash)?);
|
||||
for (block_hash, state_hash, slot) in iterator {
|
||||
for maybe_tuple in iter {
|
||||
let (block_hash, state_hash, slot) = maybe_tuple?;
|
||||
if slot < old_finalized_slot {
|
||||
// We must assume here any candidate chains include old_finalized_block_hash,
|
||||
// i.e. there aren't any forks starting at a block that is a strict ancestor of
|
||||
|
||||
@@ -392,6 +392,7 @@ fn delete_blocks_and_states() {
|
||||
.expect("faulty head state exists");
|
||||
|
||||
let states_to_delete = StateRootsIterator::new(store.clone(), &faulty_head_state)
|
||||
.map(Result::unwrap)
|
||||
.take_while(|(_, slot)| *slot > unforked_blocks)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -409,6 +410,7 @@ fn delete_blocks_and_states() {
|
||||
|
||||
// Deleting the blocks from the fork should remove them completely
|
||||
let blocks_to_delete = BlockRootsIterator::new(store.clone(), &faulty_head_state)
|
||||
.map(Result::unwrap)
|
||||
// Extra +1 here accounts for the skipped slot that started this fork
|
||||
.take_while(|(_, slot)| *slot > unforked_blocks + 1)
|
||||
.collect::<Vec<_>>();
|
||||
@@ -424,6 +426,7 @@ fn delete_blocks_and_states() {
|
||||
.chain
|
||||
.rev_iter_state_roots()
|
||||
.expect("rev iter ok")
|
||||
.map(Result::unwrap)
|
||||
.filter(|(_, slot)| *slot < split_slot);
|
||||
|
||||
for (state_root, slot) in finalized_states {
|
||||
@@ -659,11 +662,12 @@ fn check_shuffling_compatible(
|
||||
let previous_pivot_slot =
|
||||
(head_state.previous_epoch() - shuffling_lookahead).end_slot(E::slots_per_epoch());
|
||||
|
||||
for (block_root, slot) in harness
|
||||
for maybe_tuple in harness
|
||||
.chain
|
||||
.rev_iter_block_roots_from(head_block_root)
|
||||
.unwrap()
|
||||
{
|
||||
let (block_root, slot) = maybe_tuple.unwrap();
|
||||
// Shuffling is compatible targeting the current epoch,
|
||||
// iff slot is greater than or equal to the current epoch pivot block
|
||||
assert_eq!(
|
||||
@@ -1364,6 +1368,8 @@ fn check_chain_dump(harness: &TestHarness, expected_len: u64) {
|
||||
head.beacon_block_root,
|
||||
&harness.spec,
|
||||
)
|
||||
.unwrap()
|
||||
.map(Result::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Drop the block roots for skipped slots.
|
||||
@@ -1387,6 +1393,7 @@ fn check_iterators(harness: &TestHarness) {
|
||||
.rev_iter_state_roots()
|
||||
.expect("should get iter")
|
||||
.last()
|
||||
.map(Result::unwrap)
|
||||
.map(|(_, slot)| slot),
|
||||
Some(Slot::new(0))
|
||||
);
|
||||
@@ -1396,6 +1403,7 @@ fn check_iterators(harness: &TestHarness) {
|
||||
.rev_iter_block_roots()
|
||||
.expect("should get iter")
|
||||
.last()
|
||||
.map(Result::unwrap)
|
||||
.map(|(_, slot)| slot),
|
||||
Some(Slot::new(0))
|
||||
);
|
||||
|
||||
@@ -73,11 +73,13 @@ fn iterators() {
|
||||
.chain
|
||||
.rev_iter_block_roots()
|
||||
.expect("should get iter")
|
||||
.map(Result::unwrap)
|
||||
.collect();
|
||||
let state_roots: Vec<(Hash256, Slot)> = harness
|
||||
.chain
|
||||
.rev_iter_state_roots()
|
||||
.expect("should get iter")
|
||||
.map(Result::unwrap)
|
||||
.collect();
|
||||
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user