use crate::chunked_iter::ChunkedVectorIter; use crate::chunked_vector::{BlockRoots, StateRoots}; use crate::errors::{Error, Result}; use crate::iter::{BlockRootsIterator, StateRootsIterator}; use crate::{HotColdDB, ItemStore}; use itertools::process_results; use std::sync::Arc; use types::{BeaconState, ChainSpec, EthSpec, Hash256, Slot}; /// Forwards block roots iterator that makes use of the `block_roots` table in the freezer DB. pub struct FrozenForwardsBlockRootsIterator, Cold: ItemStore> { inner: ChunkedVectorIter, } /// Forwards block roots iterator that reverses a backwards iterator (only good for short ranges). pub struct SimpleForwardsBlockRootsIterator { // Values from the backwards iterator (in slot descending order) values: Vec<(Hash256, Slot)>, } /// Fusion of the above two approaches to forwards iteration. Fast and efficient. pub enum HybridForwardsBlockRootsIterator, Cold: ItemStore> { PreFinalization { iter: Box>, /// Data required by the `PostFinalization` iterator when we get to it. continuation_data: Box, Hash256)>>, }, PostFinalization { iter: SimpleForwardsBlockRootsIterator, }, } impl, Cold: ItemStore> FrozenForwardsBlockRootsIterator { pub fn new( store: Arc>, start_slot: Slot, last_restore_point_slot: Slot, spec: &ChainSpec, ) -> Self { Self { inner: ChunkedVectorIter::new( store, start_slot.as_usize(), last_restore_point_slot, spec, ), } } } impl, Cold: ItemStore> Iterator for FrozenForwardsBlockRootsIterator { type Item = (Hash256, Slot); fn next(&mut self) -> Option { self.inner .next() .map(|(slot, block_hash)| (block_hash, Slot::from(slot))) } } impl SimpleForwardsBlockRootsIterator { pub fn new, Cold: ItemStore>( store: Arc>, start_slot: Slot, end_state: BeaconState, end_block_root: Hash256, ) -> Result { // Iterate backwards from the end state, stopping at the start slot. let values = process_results( std::iter::once(Ok((end_block_root, end_state.slot()))) .chain(BlockRootsIterator::owned(store, end_state)), |iter| { iter.take_while(|(_, slot)| *slot >= start_slot) .collect::>() }, )?; Ok(Self { values }) } } impl Iterator for SimpleForwardsBlockRootsIterator { type Item = Result<(Hash256, Slot)>; fn next(&mut self) -> Option { // Pop from the end of the vector to get the block roots in slot-ascending order. Ok(self.values.pop()).transpose() } } impl, Cold: ItemStore> HybridForwardsBlockRootsIterator { pub fn new( store: Arc>, start_slot: Slot, end_state: BeaconState, end_block_root: Hash256, spec: &ChainSpec, ) -> Result { use HybridForwardsBlockRootsIterator::*; let latest_restore_point_slot = store.get_latest_restore_point_slot(); let result = if start_slot < latest_restore_point_slot { PreFinalization { iter: Box::new(FrozenForwardsBlockRootsIterator::new( store, start_slot, latest_restore_point_slot, spec, )), continuation_data: Box::new(Some((end_state, end_block_root))), } } else { PostFinalization { iter: SimpleForwardsBlockRootsIterator::new( store, start_slot, end_state, end_block_root, )?, } }; Ok(result) } fn do_next(&mut self) -> Result> { use HybridForwardsBlockRootsIterator::*; match self { PreFinalization { iter, continuation_data, } => { match iter.next() { Some(x) => Ok(Some(x)), // Once the pre-finalization iterator is consumed, transition // to a post-finalization iterator beginning from the last slot // of the pre iterator. None => { let (end_state, end_block_root) = continuation_data.take().ok_or(Error::NoContinuationData)?; *self = PostFinalization { iter: SimpleForwardsBlockRootsIterator::new( iter.inner.store.clone(), Slot::from(iter.inner.end_vindex), end_state, end_block_root, )?, }; self.do_next() } } } PostFinalization { iter } => iter.next().transpose(), } } } impl, Cold: ItemStore> Iterator for HybridForwardsBlockRootsIterator { type Item = Result<(Hash256, Slot)>; fn next(&mut self) -> Option { self.do_next().transpose() } } /// Forwards state roots iterator that makes use of the `state_roots` table in the freezer DB. pub struct FrozenForwardsStateRootsIterator, Cold: ItemStore> { inner: ChunkedVectorIter, } /// Forwards state roots iterator that reverses a backwards iterator (only good for short ranges). pub struct SimpleForwardsStateRootsIterator { // Values from the backwards iterator (in slot descending order) values: Vec<(Hash256, Slot)>, } /// Fusion of the above two approaches to forwards iteration. Fast and efficient. pub enum HybridForwardsStateRootsIterator, Cold: ItemStore> { PreFinalization { iter: Box>, /// Data required by the `PostFinalization` iterator when we get to it. continuation_data: Box, Hash256)>>, }, PostFinalization { iter: SimpleForwardsStateRootsIterator, }, } impl, Cold: ItemStore> FrozenForwardsStateRootsIterator { pub fn new( store: Arc>, start_slot: Slot, last_restore_point_slot: Slot, spec: &ChainSpec, ) -> Self { Self { inner: ChunkedVectorIter::new( store, start_slot.as_usize(), last_restore_point_slot, spec, ), } } } impl, Cold: ItemStore> Iterator for FrozenForwardsStateRootsIterator { type Item = (Hash256, Slot); fn next(&mut self) -> Option { self.inner .next() .map(|(slot, state_hash)| (state_hash, Slot::from(slot))) } } impl SimpleForwardsStateRootsIterator { pub fn new, Cold: ItemStore>( store: Arc>, start_slot: Slot, end_state: BeaconState, end_state_root: Hash256, ) -> Result { // Iterate backwards from the end state, stopping at the start slot. let values = process_results( std::iter::once(Ok((end_state_root, end_state.slot()))) .chain(StateRootsIterator::owned(store, end_state)), |iter| { iter.take_while(|(_, slot)| *slot >= start_slot) .collect::>() }, )?; Ok(Self { values }) } } impl Iterator for SimpleForwardsStateRootsIterator { type Item = Result<(Hash256, Slot)>; fn next(&mut self) -> Option { // Pop from the end of the vector to get the state roots in slot-ascending order. Ok(self.values.pop()).transpose() } } impl, Cold: ItemStore> HybridForwardsStateRootsIterator { pub fn new( store: Arc>, start_slot: Slot, end_state: BeaconState, end_state_root: Hash256, spec: &ChainSpec, ) -> Result { use HybridForwardsStateRootsIterator::*; let latest_restore_point_slot = store.get_latest_restore_point_slot(); let result = if start_slot < latest_restore_point_slot { PreFinalization { iter: Box::new(FrozenForwardsStateRootsIterator::new( store, start_slot, latest_restore_point_slot, spec, )), continuation_data: Box::new(Some((end_state, end_state_root))), } } else { PostFinalization { iter: SimpleForwardsStateRootsIterator::new( store, start_slot, end_state, end_state_root, )?, } }; Ok(result) } fn do_next(&mut self) -> Result> { use HybridForwardsStateRootsIterator::*; match self { PreFinalization { iter, continuation_data, } => { match iter.next() { Some(x) => Ok(Some(x)), // Once the pre-finalization iterator is consumed, transition // to a post-finalization iterator beginning from the last slot // of the pre iterator. None => { let (end_state, end_state_root) = continuation_data.take().ok_or(Error::NoContinuationData)?; *self = PostFinalization { iter: SimpleForwardsStateRootsIterator::new( iter.inner.store.clone(), Slot::from(iter.inner.end_vindex), end_state, end_state_root, )?, }; self.do_next() } } } PostFinalization { iter } => iter.next().transpose(), } } } impl, Cold: ItemStore> Iterator for HybridForwardsStateRootsIterator { type Item = Result<(Hash256, Slot)>; fn next(&mut self) -> Option { self.do_next().transpose() } }