mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-18 21:38:31 +00:00
Forwards block root iterators (#672)
* Implement forwards block root iterators * Clean up errors and docs
This commit is contained in:
committed by
Paul Hauner
parent
779873680b
commit
bd1b61a5b1
@@ -1,6 +1,7 @@
|
||||
use crate::chunked_vector::{
|
||||
store_updated_vector, BlockRoots, HistoricalRoots, RandaoMixes, StateRoots,
|
||||
};
|
||||
use crate::forwards_iter::HybridForwardsBlockRootsIterator;
|
||||
use crate::iter::{ParentRootBlockIterator, StateRootsIterator};
|
||||
use crate::{
|
||||
leveldb_store::LevelDB, DBColumn, Error, PartialBeaconState, SimpleStoreItem, Store, StoreItem,
|
||||
@@ -14,6 +15,7 @@ use state_processing::{
|
||||
SlotProcessingError,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use types::*;
|
||||
@@ -25,7 +27,7 @@ pub const SPLIT_DB_KEY: &str = "FREEZERDBSPLITFREEZERDBSPLITFREE";
|
||||
///
|
||||
/// Stores vector fields like the `block_roots` and `state_roots` separately, and only stores
|
||||
/// intermittent "restore point" states pre-finalization.
|
||||
pub struct HotColdDB {
|
||||
pub struct HotColdDB<E: EthSpec> {
|
||||
/// The slot and state root at the point where the database is split between hot and cold.
|
||||
///
|
||||
/// States with slots less than `split.slot` are in the cold DB, while states with slots
|
||||
@@ -34,15 +36,17 @@ pub struct HotColdDB {
|
||||
/// Number of slots per restore point state in the freezer database.
|
||||
slots_per_restore_point: u64,
|
||||
/// Cold database containing compact historical data.
|
||||
cold_db: LevelDB,
|
||||
pub(crate) cold_db: LevelDB<E>,
|
||||
/// Hot database containing duplicated but quick-to-access recent data.
|
||||
///
|
||||
/// The hot database also contains all blocks.
|
||||
hot_db: LevelDB,
|
||||
pub(crate) hot_db: LevelDB<E>,
|
||||
/// Chain spec.
|
||||
spec: ChainSpec,
|
||||
/// Logger.
|
||||
pub(crate) log: Logger,
|
||||
/// Mere vessel for E.
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -71,7 +75,9 @@ pub enum HotColdDbError {
|
||||
RestorePointBlockHashError(BeaconStateError),
|
||||
}
|
||||
|
||||
impl Store for HotColdDB {
|
||||
impl<E: EthSpec> Store<E> for HotColdDB<E> {
|
||||
type ForwardsBlockRootsIterator = HybridForwardsBlockRootsIterator<E>;
|
||||
|
||||
// Defer to the hot database for basic operations (including blocks for now)
|
||||
fn get_bytes(&self, column: &str, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
|
||||
self.hot_db.get_bytes(column, key)
|
||||
@@ -90,11 +96,7 @@ impl Store for HotColdDB {
|
||||
}
|
||||
|
||||
/// Store a state in the store.
|
||||
fn put_state<E: EthSpec>(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
state: &BeaconState<E>,
|
||||
) -> Result<(), Error> {
|
||||
fn put_state(&self, state_root: &Hash256, state: &BeaconState<E>) -> Result<(), Error> {
|
||||
if state.slot < self.get_split_slot() {
|
||||
self.store_archive_state(state_root, state)
|
||||
} else {
|
||||
@@ -103,7 +105,7 @@ impl Store for HotColdDB {
|
||||
}
|
||||
|
||||
/// Fetch a state from the store.
|
||||
fn get_state<E: EthSpec>(
|
||||
fn get_state(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
slot: Option<Slot>,
|
||||
@@ -129,7 +131,7 @@ impl Store for HotColdDB {
|
||||
}
|
||||
|
||||
/// Advance the split point of the store, moving new finalized states to the freezer.
|
||||
fn freeze_to_state<E: EthSpec>(
|
||||
fn freeze_to_state(
|
||||
store: Arc<Self>,
|
||||
frozen_head_root: Hash256,
|
||||
frozen_head: &BeaconState<E>,
|
||||
@@ -157,7 +159,7 @@ impl Store for HotColdDB {
|
||||
for (state_root, slot) in
|
||||
state_root_iter.take_while(|&(_, slot)| slot >= current_split_slot)
|
||||
{
|
||||
if slot % store.slots_per_restore_point == 0 {
|
||||
if slot % dbg!(store.slots_per_restore_point) == 0 {
|
||||
let state: BeaconState<E> = store
|
||||
.hot_db
|
||||
.get_state(&state_root, None)?
|
||||
@@ -195,20 +197,30 @@ impl Store for HotColdDB {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn forwards_block_roots_iterator(
|
||||
store: Arc<Self>,
|
||||
start_slot: Slot,
|
||||
end_state: BeaconState<E>,
|
||||
end_block_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Self::ForwardsBlockRootsIterator {
|
||||
HybridForwardsBlockRootsIterator::new(store, start_slot, end_state, end_block_root, spec)
|
||||
}
|
||||
}
|
||||
|
||||
impl HotColdDB {
|
||||
impl<E: EthSpec> HotColdDB<E> {
|
||||
/// Open a new or existing database, with the given paths to the hot and cold DBs.
|
||||
///
|
||||
/// The `slots_per_restore_point` parameter must be a divisor of `SLOTS_PER_HISTORICAL_ROOT`.
|
||||
pub fn open<E: EthSpec>(
|
||||
pub fn open(
|
||||
hot_path: &Path,
|
||||
cold_path: &Path,
|
||||
slots_per_restore_point: u64,
|
||||
spec: ChainSpec,
|
||||
log: Logger,
|
||||
) -> Result<Self, Error> {
|
||||
Self::verify_slots_per_restore_point::<E>(slots_per_restore_point)?;
|
||||
Self::verify_slots_per_restore_point(slots_per_restore_point)?;
|
||||
|
||||
let db = HotColdDB {
|
||||
split: RwLock::new(Split::default()),
|
||||
@@ -217,6 +229,7 @@ impl HotColdDB {
|
||||
hot_db: LevelDB::open(hot_path)?,
|
||||
spec,
|
||||
log,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
// Load the previous split slot from the database (if any). This ensures we can
|
||||
@@ -230,7 +243,7 @@ impl HotColdDB {
|
||||
/// Store a pre-finalization state in the freezer database.
|
||||
///
|
||||
/// Will return an error if the state does not lie on a restore point boundary.
|
||||
pub fn store_archive_state<E: EthSpec>(
|
||||
pub fn store_archive_state(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
state: &BeaconState<E>,
|
||||
@@ -251,6 +264,7 @@ impl HotColdDB {
|
||||
"slot" => state.slot,
|
||||
"state_root" => format!("{:?}", state_root)
|
||||
);
|
||||
println!("Creating restore point {}", state.slot);
|
||||
|
||||
// 1. Convert to PartialBeaconState and store that in the DB.
|
||||
let partial_state = PartialBeaconState::from_state_forgetful(state);
|
||||
@@ -273,7 +287,7 @@ impl HotColdDB {
|
||||
/// Load a pre-finalization state from the freezer database.
|
||||
///
|
||||
/// Will reconstruct the state if it lies between restore points.
|
||||
pub fn load_archive_state<E: EthSpec>(
|
||||
pub fn load_archive_state(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
slot: Slot,
|
||||
@@ -286,10 +300,7 @@ impl HotColdDB {
|
||||
}
|
||||
|
||||
/// Load a restore point state by its `state_root`.
|
||||
fn load_restore_point<E: EthSpec>(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
) -> Result<BeaconState<E>, Error> {
|
||||
fn load_restore_point(&self, state_root: &Hash256) -> Result<BeaconState<E>, Error> {
|
||||
let mut partial_state = PartialBeaconState::db_get(&self.cold_db, state_root)?
|
||||
.ok_or_else(|| HotColdDbError::MissingRestorePoint(*state_root))?;
|
||||
|
||||
@@ -303,7 +314,7 @@ impl HotColdDB {
|
||||
}
|
||||
|
||||
/// Load a restore point state by its `restore_point_index`.
|
||||
fn load_restore_point_by_index<E: EthSpec>(
|
||||
fn load_restore_point_by_index(
|
||||
&self,
|
||||
restore_point_index: u64,
|
||||
) -> Result<BeaconState<E>, Error> {
|
||||
@@ -312,7 +323,7 @@ impl HotColdDB {
|
||||
}
|
||||
|
||||
/// Load a state that lies between restore points.
|
||||
fn load_intermediate_state<E: EthSpec>(
|
||||
fn load_intermediate_state(
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
slot: Slot,
|
||||
@@ -330,7 +341,7 @@ impl HotColdDB {
|
||||
let high_restore_point = if high_restore_point_idx * self.slots_per_restore_point
|
||||
>= split.slot.as_u64()
|
||||
{
|
||||
self.get_state::<E>(&split.state_root, Some(split.slot))?
|
||||
self.get_state(&split.state_root, Some(split.slot))?
|
||||
.ok_or_else(|| HotColdDbError::MissingSplitState(split.state_root, split.slot))?
|
||||
} else {
|
||||
self.load_restore_point_by_index(high_restore_point_idx)?
|
||||
@@ -365,7 +376,7 @@ impl HotColdDB {
|
||||
/// Get a suitable block root for backtracking from `high_restore_point` to the state at `slot`.
|
||||
///
|
||||
/// Defaults to the block root for `slot`, which *should* be in range.
|
||||
fn get_high_restore_point_block_root<E: EthSpec>(
|
||||
fn get_high_restore_point_block_root(
|
||||
&self,
|
||||
high_restore_point: &BeaconState<E>,
|
||||
slot: Slot,
|
||||
@@ -381,7 +392,7 @@ impl HotColdDB {
|
||||
///
|
||||
/// Blocks are returned in slot-ascending order, suitable for replaying on a state with slot
|
||||
/// equal to `start_slot`, to reach a state with slot equal to `end_slot`.
|
||||
fn load_blocks_to_replay<E: EthSpec>(
|
||||
fn load_blocks_to_replay(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
end_slot: Slot,
|
||||
@@ -402,7 +413,7 @@ impl HotColdDB {
|
||||
/// Replay `blocks` on top of `state` until `target_slot` is reached.
|
||||
///
|
||||
/// Will skip slots as necessary.
|
||||
fn replay_blocks<E: EthSpec>(
|
||||
fn replay_blocks(
|
||||
&self,
|
||||
mut state: BeaconState<E>,
|
||||
blocks: Vec<BeaconBlock<E>>,
|
||||
@@ -440,6 +451,11 @@ impl HotColdDB {
|
||||
self.split.read().slot
|
||||
}
|
||||
|
||||
/// Fetch the slot of the most recently stored restore point.
|
||||
pub fn get_latest_restore_point_slot(&self) -> Slot {
|
||||
self.get_split_slot() / self.slots_per_restore_point * self.slots_per_restore_point
|
||||
}
|
||||
|
||||
/// Load the split point from disk.
|
||||
fn load_split(&self) -> Result<Option<Split>, Error> {
|
||||
let key = Hash256::from_slice(SPLIT_DB_KEY.as_bytes());
|
||||
@@ -498,9 +514,7 @@ impl HotColdDB {
|
||||
/// This ensures that we have at least one restore point within range of our state
|
||||
/// root history when iterating backwards (and allows for more frequent restore points if
|
||||
/// desired).
|
||||
fn verify_slots_per_restore_point<E: EthSpec>(
|
||||
slots_per_restore_point: u64,
|
||||
) -> Result<(), HotColdDbError> {
|
||||
fn verify_slots_per_restore_point(slots_per_restore_point: u64) -> Result<(), HotColdDbError> {
|
||||
let slots_per_historical_root = E::SlotsPerHistoricalRoot::to_u64();
|
||||
if slots_per_restore_point > 0 && slots_per_historical_root % slots_per_restore_point == 0 {
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user