diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index d7ba67a37..920d8c320 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -1,7 +1,6 @@ use crate::checkpoint::CheckPoint; use crate::errors::{BeaconChainError as Error, BlockProductionError}; use crate::fork_choice::{Error as ForkChoiceError, ForkChoice}; -use crate::iter::{BlockIterator, BlockRootsIterator}; use crate::metrics::Metrics; use crate::persisted_beacon_chain::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY}; use lmd_ghost::LmdGhost; @@ -19,6 +18,7 @@ use state_processing::{ per_slot_processing, BlockProcessingError, }; use std::sync::Arc; +use store::iter::{BlockIterator, BlockRootsIterator, StateRootsIterator}; use store::{Error as DBError, Store}; use tree_hash::TreeHash; use types::*; @@ -203,7 +203,7 @@ impl BeaconChain { /// /// Contains duplicate headers when skip slots are encountered. pub fn rev_iter_blocks(&self, slot: Slot) -> BlockIterator { - BlockIterator::new(self.store.clone(), self.state.read().clone(), slot) + BlockIterator::owned(self.store.clone(), self.state.read().clone(), slot) } /// Iterates in reverse (highest to lowest slot) through all block roots from `slot` through to @@ -213,7 +213,15 @@ impl BeaconChain { /// /// Contains duplicate roots when skip slots are encountered. pub fn rev_iter_block_roots(&self, slot: Slot) -> BlockRootsIterator { - BlockRootsIterator::new(self.store.clone(), self.state.read().clone(), slot) + BlockRootsIterator::owned(self.store.clone(), self.state.read().clone(), slot) + } + + /// Iterates in reverse (highest to lowest slot) through all state roots from `slot` through to + /// genesis. + /// + /// Returns `None` for roots prior to genesis or when there is an error reading from `Store`. + pub fn rev_iter_state_roots(&self, slot: Slot) -> StateRootsIterator { + StateRootsIterator::owned(self.store.clone(), self.state.read().clone(), slot) } /// Returns the block at the given root, if any. diff --git a/beacon_node/beacon_chain/src/iter.rs b/beacon_node/beacon_chain/src/iter.rs deleted file mode 100644 index 1b5e382b0..000000000 --- a/beacon_node/beacon_chain/src/iter.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::sync::Arc; -use store::Store; -use types::{BeaconBlock, BeaconState, BeaconStateError, EthSpec, Hash256, Slot}; - -/// Extends `BlockRootsIterator`, returning `BeaconBlock` instances, instead of their roots. -pub struct BlockIterator { - roots: BlockRootsIterator, -} - -impl BlockIterator { - /// Create a new iterator over all blocks in the given `beacon_state` and prior states. - pub fn new(store: Arc, beacon_state: BeaconState, start_slot: Slot) -> Self { - Self { - roots: BlockRootsIterator::new(store, beacon_state, start_slot), - } - } -} - -impl Iterator for BlockIterator { - type Item = BeaconBlock; - - fn next(&mut self) -> Option { - let root = self.roots.next()?; - self.roots.store.get(&root).ok()? - } -} - -/// Iterates backwards through block roots. -/// -/// Uses the `latest_block_roots` field of `BeaconState` to as the source of block roots and will -/// perform a lookup on the `Store` for a prior `BeaconState` if `latest_block_roots` has been -/// exhausted. -/// -/// Returns `None` for roots prior to genesis or when there is an error reading from `Store`. -pub struct BlockRootsIterator { - store: Arc, - beacon_state: BeaconState, - slot: Slot, -} - -impl BlockRootsIterator { - /// Create a new iterator over all block roots in the given `beacon_state` and prior states. - pub fn new(store: Arc, beacon_state: BeaconState, start_slot: Slot) -> Self { - Self { - slot: start_slot, - beacon_state, - store, - } - } -} - -impl Iterator for BlockRootsIterator { - type Item = Hash256; - - fn next(&mut self) -> Option { - if (self.slot == 0) || (self.slot > self.beacon_state.slot) { - return None; - } - - self.slot -= 1; - - match self.beacon_state.get_block_root(self.slot) { - Ok(root) => Some(*root), - Err(BeaconStateError::SlotOutOfBounds) => { - // Read a `BeaconState` from the store that has access to prior historical root. - self.beacon_state = { - // Load the earlier state from disk. Skip forward one slot, because a state - // doesn't return it's own state root. - let new_state_root = self.beacon_state.get_state_root(self.slot + 1).ok()?; - - self.store.get(&new_state_root).ok()? - }?; - - self.beacon_state.get_block_root(self.slot).ok().cloned() - } - _ => None, - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use store::MemoryStore; - use types::{test_utils::TestingBeaconStateBuilder, Keypair, MainnetEthSpec}; - - fn get_state() -> BeaconState { - let builder = TestingBeaconStateBuilder::from_single_keypair( - 0, - &Keypair::random(), - &T::default_spec(), - ); - let (state, _keypairs) = builder.build(); - state - } - - #[test] - fn root_iter() { - let store = Arc::new(MemoryStore::open()); - let slots_per_historical_root = MainnetEthSpec::slots_per_historical_root(); - - let mut state_a: BeaconState = get_state(); - let mut state_b: BeaconState = get_state(); - - state_a.slot = Slot::from(slots_per_historical_root); - state_b.slot = Slot::from(slots_per_historical_root * 2); - - let mut hashes = (0..).into_iter().map(|i| Hash256::from(i)); - - for root in &mut state_a.latest_block_roots[..] { - *root = hashes.next().unwrap() - } - for root in &mut state_b.latest_block_roots[..] { - *root = hashes.next().unwrap() - } - - let state_a_root = hashes.next().unwrap(); - state_b.latest_state_roots[0] = state_a_root; - store.put(&state_a_root, &state_a).unwrap(); - - let iter = BlockRootsIterator::new(store.clone(), state_b.clone(), state_b.slot - 1); - let mut collected: Vec = iter.collect(); - collected.reverse(); - - let expected_len = 2 * MainnetEthSpec::slots_per_historical_root() - 1; - - assert_eq!(collected.len(), expected_len); - - for i in 0..expected_len { - assert_eq!(collected[i], Hash256::from(i as u64)); - } - } -} diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index cad8cc5e0..df1de153a 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -2,7 +2,6 @@ mod beacon_chain; mod checkpoint; mod errors; mod fork_choice; -pub mod iter; mod metrics; mod persisted_beacon_chain; pub mod test_utils; diff --git a/beacon_node/store/src/iter.rs b/beacon_node/store/src/iter.rs index 232605212..e8b9a27e9 100644 --- a/beacon_node/store/src/iter.rs +++ b/beacon_node/store/src/iter.rs @@ -11,7 +11,6 @@ pub struct StateRootsIterator<'a, T: EthSpec, U> { } impl<'a, T: EthSpec, U: Store> StateRootsIterator<'a, T, U> { - /// Create a new iterator over all blocks in the given `beacon_state` and prior states. pub fn new(store: Arc, beacon_state: &'a BeaconState, start_slot: Slot) -> Self { Self { store, @@ -19,6 +18,14 @@ impl<'a, T: EthSpec, U: Store> StateRootsIterator<'a, T, U> { slot: start_slot, } } + + pub fn owned(store: Arc, beacon_state: BeaconState, start_slot: Slot) -> Self { + Self { + slot: start_slot, + beacon_state: Cow::Owned(beacon_state), + store, + } + } } impl<'a, T: EthSpec, U: Store> Iterator for StateRootsIterator<'a, T, U> { @@ -65,6 +72,13 @@ impl<'a, T: EthSpec, U: Store> BlockIterator<'a, T, U> { roots: BlockRootsIterator::new(store, beacon_state, start_slot), } } + + /// Create a new iterator over all blocks in the given `beacon_state` and prior states. + pub fn owned(store: Arc, beacon_state: BeaconState, start_slot: Slot) -> Self { + Self { + roots: BlockRootsIterator::owned(store, beacon_state, start_slot), + } + } } impl<'a, T: EthSpec, U: Store> Iterator for BlockIterator<'a, T, U> { @@ -99,6 +113,15 @@ impl<'a, T: EthSpec, U: Store> BlockRootsIterator<'a, T, U> { store, } } + + /// Create a new iterator over all block roots in the given `beacon_state` and prior states. + pub fn owned(store: Arc, beacon_state: BeaconState, start_slot: Slot) -> Self { + Self { + slot: start_slot, + beacon_state: Cow::Owned(beacon_state), + store, + } + } } impl<'a, T: EthSpec, U: Store> Iterator for BlockRootsIterator<'a, T, U> { diff --git a/eth2/lmd_ghost/src/reduced_tree.rs b/eth2/lmd_ghost/src/reduced_tree.rs index a0fc2d96e..9a869c1eb 100644 --- a/eth2/lmd_ghost/src/reduced_tree.rs +++ b/eth2/lmd_ghost/src/reduced_tree.rs @@ -496,7 +496,7 @@ where let block = self.get_block(child)?; let state = self.get_state(block.state_root)?; - Ok(BlockRootsIterator::new( + Ok(BlockRootsIterator::owned( self.store.clone(), state, block.slot,