2020-06-16 01:34:04 +00:00
|
|
|
use crate::{Error, HotColdDB, ItemStore};
|
2019-06-18 15:47:21 +00:00
|
|
|
use std::borrow::Cow;
|
2019-12-06 03:29:06 +00:00
|
|
|
use std::marker::PhantomData;
|
2019-06-15 13:56:41 +00:00
|
|
|
use std::sync::Arc;
|
2019-12-06 03:29:06 +00:00
|
|
|
use types::{
|
2020-02-10 23:19:36 +00:00
|
|
|
typenum::Unsigned, BeaconState, BeaconStateError, EthSpec, Hash256, SignedBeaconBlock, Slot,
|
2019-12-06 03:29:06 +00:00
|
|
|
};
|
2019-06-15 13:56:41 +00:00
|
|
|
|
2019-07-29 02:08:52 +00:00
|
|
|
/// Implemented for types that have ancestors (e.g., blocks, states) that may be iterated over.
|
2019-08-08 02:28:10 +00:00
|
|
|
///
|
|
|
|
/// ## Note
|
|
|
|
///
|
|
|
|
/// It is assumed that all ancestors for this object are stored in the database. If this is not the
|
|
|
|
/// case, the iterator will start returning `None` prior to genesis.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub trait AncestorIter<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>, I: Iterator> {
|
2019-07-29 02:08:52 +00:00
|
|
|
/// Returns an iterator over the roots of the ancestors of `self`.
|
2020-06-16 01:34:04 +00:00
|
|
|
fn try_iter_ancestor_roots(&self, store: Arc<HotColdDB<E, Hot, Cold>>) -> Option<I>;
|
2019-07-29 02:08:52 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>>
|
|
|
|
AncestorIter<E, Hot, Cold, BlockRootsIterator<'a, E, Hot, Cold>> for SignedBeaconBlock<E>
|
2019-12-06 07:52:11 +00:00
|
|
|
{
|
2019-08-14 00:55:24 +00:00
|
|
|
/// Iterates across all available prior block roots of `self`, starting at the most recent and ending
|
2019-07-29 02:08:52 +00:00
|
|
|
/// at genesis.
|
2020-06-16 01:34:04 +00:00
|
|
|
fn try_iter_ancestor_roots(
|
|
|
|
&self,
|
|
|
|
store: Arc<HotColdDB<E, Hot, Cold>>,
|
|
|
|
) -> Option<BlockRootsIterator<'a, E, Hot, Cold>> {
|
2020-02-10 23:19:36 +00:00
|
|
|
let state = store
|
2021-07-09 06:15:32 +00:00
|
|
|
.get_state(&self.message().state_root(), Some(self.slot()))
|
2020-02-10 23:19:36 +00:00
|
|
|
.ok()??;
|
2019-07-29 02:08:52 +00:00
|
|
|
|
2019-08-14 00:55:24 +00:00
|
|
|
Some(BlockRootsIterator::owned(store, state))
|
2019-07-29 02:08:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>>
|
|
|
|
AncestorIter<E, Hot, Cold, StateRootsIterator<'a, E, Hot, Cold>> for BeaconState<E>
|
2019-12-06 07:52:11 +00:00
|
|
|
{
|
2019-08-14 00:55:24 +00:00
|
|
|
/// Iterates across all available prior state roots of `self`, starting at the most recent and ending
|
2019-08-10 07:15:15 +00:00
|
|
|
/// at genesis.
|
2020-06-16 01:34:04 +00:00
|
|
|
fn try_iter_ancestor_roots(
|
|
|
|
&self,
|
|
|
|
store: Arc<HotColdDB<E, Hot, Cold>>,
|
|
|
|
) -> Option<StateRootsIterator<'a, E, Hot, Cold>> {
|
2019-08-10 07:15:15 +00:00
|
|
|
// The `self.clone()` here is wasteful.
|
2019-08-14 00:55:24 +00:00
|
|
|
Some(StateRootsIterator::owned(store, self.clone()))
|
2019-08-10 07:15:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
pub struct StateRootsIterator<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> {
|
|
|
|
inner: RootsIterator<'a, T, Hot, Cold>,
|
2020-04-20 09:59:56 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Clone
|
|
|
|
for StateRootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-04-20 09:59:56 +00:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self {
|
|
|
|
inner: self.inner.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> StateRootsIterator<'a, T, Hot, Cold> {
|
|
|
|
pub fn new(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: &'a BeaconState<T>) -> Self {
|
2020-04-20 09:59:56 +00:00
|
|
|
Self {
|
|
|
|
inner: RootsIterator::new(store, beacon_state),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn owned(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: BeaconState<T>) -> Self {
|
2020-04-20 09:59:56 +00:00
|
|
|
Self {
|
|
|
|
inner: RootsIterator::owned(store, beacon_state),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Iterator
|
|
|
|
for StateRootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-06-09 23:55:44 +00:00
|
|
|
type Item = Result<(Hash256, Slot), Error>;
|
2020-04-20 09:59:56 +00:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.inner
|
|
|
|
.next()
|
2020-06-09 23:55:44 +00:00
|
|
|
.map(|result| result.map(|(_, state_root, slot)| (state_root, slot)))
|
2020-04-20 09:59:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Iterates backwards through block roots. If any specified slot is unable to be retrieved, the
|
|
|
|
/// iterator returns `None` indefinitely.
|
|
|
|
///
|
|
|
|
/// Uses the `block_roots` field of `BeaconState` as the source of block roots and will
|
|
|
|
/// perform a lookup on the `Store` for a prior `BeaconState` if `block_roots` has been
|
|
|
|
/// exhausted.
|
|
|
|
///
|
|
|
|
/// Returns `None` for roots prior to genesis or when there is an error reading from `Store`.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub struct BlockRootsIterator<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> {
|
|
|
|
inner: RootsIterator<'a, T, Hot, Cold>,
|
2020-04-20 09:59:56 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Clone
|
|
|
|
for BlockRootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-04-20 09:59:56 +00:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self {
|
|
|
|
inner: self.inner.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> BlockRootsIterator<'a, T, Hot, Cold> {
|
2020-04-20 09:59:56 +00:00
|
|
|
/// Create a new iterator over all block roots in the given `beacon_state` and prior states.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn new(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: &'a BeaconState<T>) -> Self {
|
2020-04-20 09:59:56 +00:00
|
|
|
Self {
|
|
|
|
inner: RootsIterator::new(store, beacon_state),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a new iterator over all block roots in the given `beacon_state` and prior states.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn owned(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: BeaconState<T>) -> Self {
|
2020-04-20 09:59:56 +00:00
|
|
|
Self {
|
|
|
|
inner: RootsIterator::owned(store, beacon_state),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Iterator
|
|
|
|
for BlockRootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-06-09 23:55:44 +00:00
|
|
|
type Item = Result<(Hash256, Slot), Error>;
|
2020-04-20 09:59:56 +00:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.inner
|
|
|
|
.next()
|
2020-06-09 23:55:44 +00:00
|
|
|
.map(|result| result.map(|(block_root, _, slot)| (block_root, slot)))
|
2020-04-20 09:59:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Iterator over state and block roots that backtracks using the vectors from a `BeaconState`.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub struct RootsIterator<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> {
|
|
|
|
store: Arc<HotColdDB<T, Hot, Cold>>,
|
2019-06-18 15:47:21 +00:00
|
|
|
beacon_state: Cow<'a, BeaconState<T>>,
|
|
|
|
slot: Slot,
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Clone
|
|
|
|
for RootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2019-11-26 23:54:46 +00:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self {
|
|
|
|
store: self.store.clone(),
|
|
|
|
beacon_state: self.beacon_state.clone(),
|
|
|
|
slot: self.slot,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> RootsIterator<'a, T, Hot, Cold> {
|
|
|
|
pub fn new(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: &'a BeaconState<T>) -> Self {
|
2019-06-18 15:47:21 +00:00
|
|
|
Self {
|
|
|
|
store,
|
2021-07-09 06:15:32 +00:00
|
|
|
slot: beacon_state.slot(),
|
2019-06-18 15:47:21 +00:00
|
|
|
beacon_state: Cow::Borrowed(beacon_state),
|
|
|
|
}
|
|
|
|
}
|
2019-06-18 16:06:23 +00:00
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn owned(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: BeaconState<T>) -> Self {
|
2019-06-18 16:06:23 +00:00
|
|
|
Self {
|
|
|
|
store,
|
2021-07-09 06:15:32 +00:00
|
|
|
slot: beacon_state.slot(),
|
2019-07-16 07:28:15 +00:00
|
|
|
beacon_state: Cow::Owned(beacon_state),
|
2019-06-18 16:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
2020-04-20 09:59:56 +00:00
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn from_block(
|
|
|
|
store: Arc<HotColdDB<T, Hot, Cold>>,
|
|
|
|
block_hash: Hash256,
|
|
|
|
) -> Result<Self, Error> {
|
2020-04-20 09:59:56 +00:00
|
|
|
let block = store
|
|
|
|
.get_block(&block_hash)?
|
|
|
|
.ok_or_else(|| BeaconStateError::MissingBeaconBlock(block_hash.into()))?;
|
|
|
|
let state = store
|
|
|
|
.get_state(&block.state_root(), Some(block.slot()))?
|
|
|
|
.ok_or_else(|| BeaconStateError::MissingBeaconState(block.state_root().into()))?;
|
|
|
|
Ok(Self::owned(store, state))
|
|
|
|
}
|
2019-06-18 15:47:21 +00:00
|
|
|
|
2020-06-09 23:55:44 +00:00
|
|
|
fn do_next(&mut self) -> Result<Option<(Hash256, Hash256, Slot)>, Error> {
|
2021-07-09 06:15:32 +00:00
|
|
|
if self.slot == 0 || self.slot > self.beacon_state.slot() {
|
2020-06-09 23:55:44 +00:00
|
|
|
return Ok(None);
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.slot -= 1;
|
|
|
|
|
2020-04-20 09:59:56 +00:00
|
|
|
match (
|
|
|
|
self.beacon_state.get_block_root(self.slot),
|
|
|
|
self.beacon_state.get_state_root(self.slot),
|
|
|
|
) {
|
2020-06-09 23:55:44 +00:00
|
|
|
(Ok(block_root), Ok(state_root)) => Ok(Some((*block_root, *state_root, self.slot))),
|
2020-04-20 09:59:56 +00:00
|
|
|
(Err(BeaconStateError::SlotOutOfBounds), Err(BeaconStateError::SlotOutOfBounds)) => {
|
2019-12-06 03:29:06 +00:00
|
|
|
// Read a `BeaconState` from the store that has access to prior historical roots.
|
|
|
|
let beacon_state =
|
|
|
|
next_historical_root_backtrack_state(&*self.store, &self.beacon_state)?;
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
self.beacon_state = Cow::Owned(beacon_state);
|
|
|
|
|
2020-06-09 23:55:44 +00:00
|
|
|
let block_root = *self.beacon_state.get_block_root(self.slot)?;
|
|
|
|
let state_root = *self.beacon_state.get_state_root(self.slot)?;
|
2019-06-18 15:47:21 +00:00
|
|
|
|
2020-06-09 23:55:44 +00:00
|
|
|
Ok(Some((block_root, state_root, self.slot)))
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
2020-06-09 23:55:44 +00:00
|
|
|
(Err(e), _) => Err(e.into()),
|
|
|
|
(Ok(_), Err(e)) => Err(e.into()),
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Iterator
|
|
|
|
for RootsIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-06-09 23:55:44 +00:00
|
|
|
/// (block_root, state_root, slot)
|
|
|
|
type Item = Result<(Hash256, Hash256, Slot), Error>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.do_next().transpose()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-06 03:29:06 +00:00
|
|
|
/// Block iterator that uses the `parent_root` of each block to backtrack.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub struct ParentRootBlockIterator<'a, E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> {
|
|
|
|
store: &'a HotColdDB<E, Hot, Cold>,
|
2019-12-06 03:29:06 +00:00
|
|
|
next_block_root: Hash256,
|
|
|
|
_phantom: PhantomData<E>,
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>>
|
|
|
|
ParentRootBlockIterator<'a, E, Hot, Cold>
|
|
|
|
{
|
|
|
|
pub fn new(store: &'a HotColdDB<E, Hot, Cold>, start_block_root: Hash256) -> Self {
|
2019-12-06 03:29:06 +00:00
|
|
|
Self {
|
|
|
|
store,
|
|
|
|
next_block_root: start_block_root,
|
|
|
|
_phantom: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-16 03:23:32 +00:00
|
|
|
fn do_next(&mut self) -> Result<Option<(Hash256, SignedBeaconBlock<E>)>, Error> {
|
2019-12-06 03:29:06 +00:00
|
|
|
// Stop once we reach the zero parent, otherwise we'll keep returning the genesis
|
|
|
|
// block forever.
|
|
|
|
if self.next_block_root.is_zero() {
|
2020-05-16 03:23:32 +00:00
|
|
|
Ok(None)
|
2019-12-06 03:29:06 +00:00
|
|
|
} else {
|
2020-01-08 02:58:01 +00:00
|
|
|
let block_root = self.next_block_root;
|
2020-05-16 03:23:32 +00:00
|
|
|
let block = self
|
|
|
|
.store
|
|
|
|
.get_block(&block_root)?
|
|
|
|
.ok_or(Error::BlockNotFound(block_root))?;
|
2021-07-09 06:15:32 +00:00
|
|
|
self.next_block_root = block.message().parent_root();
|
2020-05-16 03:23:32 +00:00
|
|
|
Ok(Some((block_root, block)))
|
2019-12-06 03:29:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> Iterator
|
|
|
|
for ParentRootBlockIterator<'a, E, Hot, Cold>
|
|
|
|
{
|
2020-05-16 03:23:32 +00:00
|
|
|
type Item = Result<(Hash256, SignedBeaconBlock<E>), Error>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
self.do_next().transpose()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 15:47:21 +00:00
|
|
|
#[derive(Clone)]
|
2020-02-10 23:19:36 +00:00
|
|
|
/// Extends `BlockRootsIterator`, returning `SignedBeaconBlock` instances, instead of their roots.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub struct BlockIterator<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> {
|
|
|
|
roots: BlockRootsIterator<'a, T, Hot, Cold>,
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> BlockIterator<'a, T, Hot, Cold> {
|
2019-06-15 13:56:41 +00:00
|
|
|
/// Create a new iterator over all blocks in the given `beacon_state` and prior states.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn new(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: &'a BeaconState<T>) -> Self {
|
2019-06-15 13:56:41 +00:00
|
|
|
Self {
|
2019-08-14 00:55:24 +00:00
|
|
|
roots: BlockRootsIterator::new(store, beacon_state),
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-18 16:06:23 +00:00
|
|
|
|
|
|
|
/// Create a new iterator over all blocks in the given `beacon_state` and prior states.
|
2020-06-16 01:34:04 +00:00
|
|
|
pub fn owned(store: Arc<HotColdDB<T, Hot, Cold>>, beacon_state: BeaconState<T>) -> Self {
|
2019-06-18 16:06:23 +00:00
|
|
|
Self {
|
2019-08-14 00:55:24 +00:00
|
|
|
roots: BlockRootsIterator::owned(store, beacon_state),
|
2019-06-18 16:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-09 23:55:44 +00:00
|
|
|
|
|
|
|
fn do_next(&mut self) -> Result<Option<SignedBeaconBlock<T>>, Error> {
|
|
|
|
if let Some(result) = self.roots.next() {
|
|
|
|
let (root, _slot) = result?;
|
|
|
|
self.roots.inner.store.get_block(&root)
|
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 01:34:04 +00:00
|
|
|
impl<'a, T: EthSpec, Hot: ItemStore<T>, Cold: ItemStore<T>> Iterator
|
|
|
|
for BlockIterator<'a, T, Hot, Cold>
|
|
|
|
{
|
2020-06-09 23:55:44 +00:00
|
|
|
type Item = Result<SignedBeaconBlock<T>, Error>;
|
2019-06-15 13:56:41 +00:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2020-06-09 23:55:44 +00:00
|
|
|
self.do_next().transpose()
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-06 03:29:06 +00:00
|
|
|
/// Fetch the next state to use whilst backtracking in `*RootsIterator`.
|
2020-06-16 01:34:04 +00:00
|
|
|
fn next_historical_root_backtrack_state<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>>(
|
|
|
|
store: &HotColdDB<E, Hot, Cold>,
|
2019-12-06 03:29:06 +00:00
|
|
|
current_state: &BeaconState<E>,
|
2020-06-09 23:55:44 +00:00
|
|
|
) -> Result<BeaconState<E>, Error> {
|
2019-12-06 03:29:06 +00:00
|
|
|
// For compatibility with the freezer database's restore points, we load a state at
|
|
|
|
// a restore point slot (thus avoiding replaying blocks). In the case where we're
|
|
|
|
// not frozen, this just means we might not jump back by the maximum amount on
|
|
|
|
// our first jump (i.e. at most 1 extra state load).
|
2021-07-09 06:15:32 +00:00
|
|
|
let new_state_slot = slot_of_prev_restore_point::<E>(current_state.slot());
|
2020-06-09 23:55:44 +00:00
|
|
|
let new_state_root = current_state.get_state_root(new_state_slot)?;
|
|
|
|
Ok(store
|
|
|
|
.get_state(new_state_root, Some(new_state_slot))?
|
|
|
|
.ok_or_else(|| BeaconStateError::MissingBeaconState((*new_state_root).into()))?)
|
2019-12-06 03:29:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute the slot of the last guaranteed restore point in the freezer database.
|
|
|
|
fn slot_of_prev_restore_point<E: EthSpec>(current_slot: Slot) -> Slot {
|
|
|
|
let slots_per_historical_root = E::SlotsPerHistoricalRoot::to_u64();
|
|
|
|
(current_slot - 1) / slots_per_historical_root * slots_per_historical_root
|
|
|
|
}
|
|
|
|
|
2019-06-15 13:56:41 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
2020-06-16 01:34:04 +00:00
|
|
|
use crate::HotColdDB;
|
2021-07-09 06:15:32 +00:00
|
|
|
use crate::StoreConfig as Config;
|
|
|
|
use beacon_chain::store::StoreConfig;
|
|
|
|
use beacon_chain::test_utils::BeaconChainHarness;
|
|
|
|
use beacon_chain::types::{ChainSpec, Keypair, MainnetEthSpec};
|
2020-06-16 01:34:04 +00:00
|
|
|
use sloggers::{null::NullLoggerBuilder, Build};
|
2019-06-15 13:56:41 +00:00
|
|
|
|
|
|
|
fn get_state<T: EthSpec>() -> BeaconState<T> {
|
2021-07-09 06:15:32 +00:00
|
|
|
let harness = BeaconChainHarness::new_with_store_config(
|
|
|
|
T::default(),
|
|
|
|
None,
|
|
|
|
vec![Keypair::random()],
|
|
|
|
StoreConfig::default(),
|
2019-06-15 13:56:41 +00:00
|
|
|
);
|
2021-07-09 06:15:32 +00:00
|
|
|
harness.advance_slot();
|
|
|
|
harness.get_current_state()
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-06-18 15:47:21 +00:00
|
|
|
fn block_root_iter() {
|
2020-06-16 01:34:04 +00:00
|
|
|
let log = NullLoggerBuilder.build().unwrap();
|
|
|
|
let store = Arc::new(
|
2021-07-09 06:15:32 +00:00
|
|
|
HotColdDB::open_ephemeral(Config::default(), ChainSpec::minimal(), log).unwrap(),
|
2020-06-16 01:34:04 +00:00
|
|
|
);
|
2019-06-15 13:56:41 +00:00
|
|
|
let slots_per_historical_root = MainnetEthSpec::slots_per_historical_root();
|
|
|
|
|
|
|
|
let mut state_a: BeaconState<MainnetEthSpec> = get_state();
|
|
|
|
let mut state_b: BeaconState<MainnetEthSpec> = get_state();
|
|
|
|
|
2021-07-09 06:15:32 +00:00
|
|
|
*state_a.slot_mut() = Slot::from(slots_per_historical_root);
|
|
|
|
*state_b.slot_mut() = Slot::from(slots_per_historical_root * 2);
|
2019-06-15 13:56:41 +00:00
|
|
|
|
2019-09-30 03:58:45 +00:00
|
|
|
let mut hashes = (0..).map(Hash256::from_low_u64_be);
|
2021-07-09 06:15:32 +00:00
|
|
|
let roots_a = state_a.block_roots_mut();
|
|
|
|
for i in 0..roots_a.len() {
|
|
|
|
roots_a[i] = hashes.next().unwrap()
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
2021-07-09 06:15:32 +00:00
|
|
|
let roots_b = state_b.block_roots_mut();
|
|
|
|
for i in 0..roots_b.len() {
|
|
|
|
roots_b[i] = hashes.next().unwrap()
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let state_a_root = hashes.next().unwrap();
|
2021-07-09 06:15:32 +00:00
|
|
|
state_b.state_roots_mut()[0] = state_a_root;
|
2020-04-06 00:53:33 +00:00
|
|
|
store.put_state(&state_a_root, &state_a).unwrap();
|
2019-06-15 13:56:41 +00:00
|
|
|
|
2020-01-21 07:38:56 +00:00
|
|
|
let iter = BlockRootsIterator::new(store, &state_b);
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
assert!(
|
2020-06-09 23:55:44 +00:00
|
|
|
iter.clone()
|
|
|
|
.any(|result| result.map(|(_root, slot)| slot == 0).unwrap()),
|
2019-06-18 15:47:21 +00:00
|
|
|
"iter should contain zero slot"
|
|
|
|
);
|
|
|
|
|
2020-06-09 23:55:44 +00:00
|
|
|
let mut collected: Vec<(Hash256, Slot)> = iter.collect::<Result<Vec<_>, _>>().unwrap();
|
2019-06-15 13:56:41 +00:00
|
|
|
collected.reverse();
|
|
|
|
|
2019-07-16 07:28:15 +00:00
|
|
|
let expected_len = 2 * MainnetEthSpec::slots_per_historical_root();
|
|
|
|
|
|
|
|
assert_eq!(collected.len(), expected_len);
|
|
|
|
|
2019-09-30 03:58:45 +00:00
|
|
|
for (i, item) in collected.iter().enumerate() {
|
|
|
|
assert_eq!(item.0, Hash256::from_low_u64_be(i as u64));
|
2019-08-05 06:27:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 15:47:21 +00:00
|
|
|
#[test]
|
|
|
|
fn state_root_iter() {
|
2020-06-16 01:34:04 +00:00
|
|
|
let log = NullLoggerBuilder.build().unwrap();
|
|
|
|
let store = Arc::new(
|
2021-07-09 06:15:32 +00:00
|
|
|
HotColdDB::open_ephemeral(Config::default(), ChainSpec::minimal(), log).unwrap(),
|
2020-06-16 01:34:04 +00:00
|
|
|
);
|
2019-06-18 15:47:21 +00:00
|
|
|
let slots_per_historical_root = MainnetEthSpec::slots_per_historical_root();
|
|
|
|
|
|
|
|
let mut state_a: BeaconState<MainnetEthSpec> = get_state();
|
|
|
|
let mut state_b: BeaconState<MainnetEthSpec> = get_state();
|
|
|
|
|
2021-07-09 06:15:32 +00:00
|
|
|
*state_a.slot_mut() = Slot::from(slots_per_historical_root);
|
|
|
|
*state_b.slot_mut() = Slot::from(slots_per_historical_root * 2);
|
2019-06-18 15:47:21 +00:00
|
|
|
|
2019-09-30 03:58:45 +00:00
|
|
|
let mut hashes = (0..).map(Hash256::from_low_u64_be);
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
for slot in 0..slots_per_historical_root {
|
|
|
|
state_a
|
|
|
|
.set_state_root(Slot::from(slot), hashes.next().unwrap())
|
2019-09-30 03:58:45 +00:00
|
|
|
.unwrap_or_else(|_| panic!("should set state_a slot {}", slot));
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
|
|
|
for slot in slots_per_historical_root..slots_per_historical_root * 2 {
|
|
|
|
state_b
|
|
|
|
.set_state_root(Slot::from(slot), hashes.next().unwrap())
|
2019-09-30 03:58:45 +00:00
|
|
|
.unwrap_or_else(|_| panic!("should set state_b slot {}", slot));
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
|
|
|
|
2019-08-06 04:41:42 +00:00
|
|
|
let state_a_root = Hash256::from_low_u64_be(slots_per_historical_root as u64);
|
|
|
|
let state_b_root = Hash256::from_low_u64_be(slots_per_historical_root as u64 * 2);
|
2019-06-18 15:47:21 +00:00
|
|
|
|
2020-04-06 00:53:33 +00:00
|
|
|
store.put_state(&state_a_root, &state_a).unwrap();
|
2021-01-28 23:31:06 +00:00
|
|
|
store.put_state(&state_b_root, &state_b).unwrap();
|
2019-06-18 15:47:21 +00:00
|
|
|
|
2020-01-21 07:38:56 +00:00
|
|
|
let iter = StateRootsIterator::new(store, &state_b);
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
assert!(
|
2020-06-09 23:55:44 +00:00
|
|
|
iter.clone()
|
|
|
|
.any(|result| result.map(|(_root, slot)| slot == 0).unwrap()),
|
2019-06-18 15:47:21 +00:00
|
|
|
"iter should contain zero slot"
|
|
|
|
);
|
|
|
|
|
2020-06-09 23:55:44 +00:00
|
|
|
let mut collected: Vec<(Hash256, Slot)> = iter.collect::<Result<Vec<_>, _>>().unwrap();
|
2019-06-18 15:47:21 +00:00
|
|
|
collected.reverse();
|
|
|
|
|
2019-07-16 07:28:15 +00:00
|
|
|
let expected_len = MainnetEthSpec::slots_per_historical_root() * 2;
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
assert_eq!(collected.len(), expected_len, "collection length incorrect");
|
|
|
|
|
2019-09-30 03:58:45 +00:00
|
|
|
for (i, item) in collected.iter().enumerate() {
|
|
|
|
let (hash, slot) = *item;
|
2019-06-18 15:47:21 +00:00
|
|
|
|
|
|
|
assert_eq!(slot, i as u64, "slot mismatch at {}: {} vs {}", i, slot, i);
|
|
|
|
|
2019-08-06 04:41:42 +00:00
|
|
|
assert_eq!(
|
|
|
|
hash,
|
|
|
|
Hash256::from_low_u64_be(i as u64),
|
|
|
|
"hash mismatch at {}",
|
|
|
|
i
|
|
|
|
);
|
2019-06-18 15:47:21 +00:00
|
|
|
}
|
|
|
|
}
|
2019-06-15 13:56:41 +00:00
|
|
|
}
|