Allow fork_choice and beacon_chain to compile

This commit is contained in:
Paul Hauner 2019-05-08 18:18:17 +10:00
parent 9fd8af8428
commit 51dc97ee42
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
8 changed files with 87 additions and 64 deletions

View File

@ -83,30 +83,31 @@ impl BlockProcessingOutcome {
} }
} }
pub struct BeaconChain<T: ClientDB + Sized, U: SlotClock, F: ForkChoice> { pub struct BeaconChain<T: ClientDB + Sized, U: SlotClock, F: ForkChoice, B: BeaconStateTypes> {
pub block_store: Arc<BeaconBlockStore<T>>, pub block_store: Arc<BeaconBlockStore<T>>,
pub state_store: Arc<BeaconStateStore<T>>, pub state_store: Arc<BeaconStateStore<T>>,
pub slot_clock: U, pub slot_clock: U,
pub op_pool: OperationPool, pub op_pool: OperationPool<B>,
canonical_head: RwLock<CheckPoint>, canonical_head: RwLock<CheckPoint<B>>,
finalized_head: RwLock<CheckPoint>, finalized_head: RwLock<CheckPoint<B>>,
pub state: RwLock<BeaconState>, pub state: RwLock<BeaconState<B>>,
pub spec: ChainSpec, pub spec: ChainSpec,
pub fork_choice: RwLock<F>, pub fork_choice: RwLock<F>,
} }
impl<T, U, F> BeaconChain<T, U, F> impl<T, U, F, B> BeaconChain<T, U, F, B>
where where
T: ClientDB, T: ClientDB,
U: SlotClock, U: SlotClock,
F: ForkChoice, F: ForkChoice,
B: BeaconStateTypes,
{ {
/// Instantiate a new Beacon Chain, from genesis. /// Instantiate a new Beacon Chain, from genesis.
pub fn from_genesis( pub fn from_genesis(
state_store: Arc<BeaconStateStore<T>>, state_store: Arc<BeaconStateStore<T>>,
block_store: Arc<BeaconBlockStore<T>>, block_store: Arc<BeaconBlockStore<T>>,
slot_clock: U, slot_clock: U,
mut genesis_state: BeaconState, mut genesis_state: BeaconState<B>,
genesis_block: BeaconBlock, genesis_block: BeaconBlock,
spec: ChainSpec, spec: ChainSpec,
fork_choice: F, fork_choice: F,
@ -218,7 +219,7 @@ where
// //
// If we get `SlotOutOfBounds` error, load the oldest available historic // If we get `SlotOutOfBounds` error, load the oldest available historic
// state from the DB. // state from the DB.
match state.get_block_root(slot, spec) { match state.get_block_root(slot) {
Ok(root) => { Ok(root) => {
if slot < earliest_slot { if slot < earliest_slot {
break; break;
@ -230,9 +231,9 @@ where
Err(BeaconStateError::SlotOutOfBounds) => { Err(BeaconStateError::SlotOutOfBounds) => {
// Read the earliest historic state in the current slot. // Read the earliest historic state in the current slot.
let earliest_historic_slot = let earliest_historic_slot =
state.slot - Slot::from(spec.slots_per_historical_root); state.slot - Slot::from(B::SlotsPerHistoricalRoot::to_usize());
// Load the earlier state from disk. // Load the earlier state from disk.
let new_state_root = state.get_state_root(earliest_historic_slot, spec)?; let new_state_root = state.get_state_root(earliest_historic_slot)?;
// Break if the DB is unable to load the state. // Break if the DB is unable to load the state.
state = match self.state_store.get_deserialized(&new_state_root) { state = match self.state_store.get_deserialized(&new_state_root) {
@ -270,7 +271,7 @@ where
&self, &self,
new_beacon_block: BeaconBlock, new_beacon_block: BeaconBlock,
new_beacon_block_root: Hash256, new_beacon_block_root: Hash256,
new_beacon_state: BeaconState, new_beacon_state: BeaconState<B>,
new_beacon_state_root: Hash256, new_beacon_state_root: Hash256,
) { ) {
debug!( debug!(
@ -292,7 +293,7 @@ where
/// It is important to note that the `beacon_state` returned may not match the present slot. It /// It is important to note that the `beacon_state` returned may not match the present slot. It
/// is the state as it was when the head block was received, which could be some slots prior to /// is the state as it was when the head block was received, which could be some slots prior to
/// now. /// now.
pub fn head(&self) -> RwLockReadGuard<CheckPoint> { pub fn head(&self) -> RwLockReadGuard<CheckPoint<B>> {
self.canonical_head.read() self.canonical_head.read()
} }
@ -302,7 +303,7 @@ where
/// state and calling `catchup_state` as it will not result in an old state being installed and /// state and calling `catchup_state` as it will not result in an old state being installed and
/// then having it iteratively updated -- in such a case it's possible for another thread to /// then having it iteratively updated -- in such a case it's possible for another thread to
/// find the state at an old slot. /// find the state at an old slot.
pub fn update_state(&self, mut state: BeaconState) -> Result<(), Error> { pub fn update_state(&self, mut state: BeaconState<B>) -> Result<(), Error> {
let present_slot = match self.slot_clock.present_slot() { let present_slot = match self.slot_clock.present_slot() {
Ok(Some(slot)) => slot, Ok(Some(slot)) => slot,
_ => return Err(Error::UnableToReadSlot), _ => return Err(Error::UnableToReadSlot),
@ -357,7 +358,7 @@ where
&self, &self,
new_beacon_block: BeaconBlock, new_beacon_block: BeaconBlock,
new_beacon_block_root: Hash256, new_beacon_block_root: Hash256,
new_beacon_state: BeaconState, new_beacon_state: BeaconState<B>,
new_beacon_state_root: Hash256, new_beacon_state_root: Hash256,
) { ) {
let mut finalized_head = self.finalized_head.write(); let mut finalized_head = self.finalized_head.write();
@ -371,7 +372,7 @@ where
/// Returns a read-lock guarded `CheckPoint` struct for reading the justified head (as chosen, /// Returns a read-lock guarded `CheckPoint` struct for reading the justified head (as chosen,
/// indirectly, by the fork-choice rule). /// indirectly, by the fork-choice rule).
pub fn finalized_head(&self) -> RwLockReadGuard<CheckPoint> { pub fn finalized_head(&self) -> RwLockReadGuard<CheckPoint<B>> {
self.finalized_head.read() self.finalized_head.read()
} }
@ -493,17 +494,14 @@ where
} else { } else {
// If the current head block is not from this slot, use the slot from the previous // If the current head block is not from this slot, use the slot from the previous
// epoch. // epoch.
*self.state.read().get_block_root(
current_epoch_start_slot - self.spec.slots_per_epoch,
&self.spec,
)?
}
} else {
// If we're not on the first slot of the epoch.
*self *self
.state .state
.read() .read()
.get_block_root(current_epoch_start_slot, &self.spec)? .get_block_root(current_epoch_start_slot - self.spec.slots_per_epoch)?
}
} else {
// If we're not on the first slot of the epoch.
*self.state.read().get_block_root(current_epoch_start_slot)?
}; };
Ok(AttestationData { Ok(AttestationData {
@ -667,7 +665,7 @@ where
pub fn produce_block( pub fn produce_block(
&self, &self,
randao_reveal: Signature, randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState), BlockProductionError> { ) -> Result<(BeaconBlock, BeaconState<B>), BlockProductionError> {
debug!("Producing block at slot {}...", self.state.read().slot); debug!("Producing block at slot {}...", self.state.read().slot);
let mut state = self.state.read().clone(); let mut state = self.state.read().clone();
@ -677,7 +675,7 @@ where
trace!("Finding attestations for new block..."); trace!("Finding attestations for new block...");
let previous_block_root = *state let previous_block_root = *state
.get_block_root(state.slot - 1, &self.spec) .get_block_root(state.slot - 1)
.map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?; .map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?;
let (proposer_slashings, attester_slashings) = let (proposer_slashings, attester_slashings) =
@ -762,7 +760,7 @@ where
/// ///
/// This could be a very expensive operation and should only be done in testing/analysis /// This could be a very expensive operation and should only be done in testing/analysis
/// activities. /// activities.
pub fn chain_dump(&self) -> Result<Vec<CheckPoint>, Error> { pub fn chain_dump(&self) -> Result<Vec<CheckPoint<B>>, Error> {
let mut dump = vec![]; let mut dump = vec![];
let mut last_slot = CheckPoint { let mut last_slot = CheckPoint {

View File

@ -1,22 +1,22 @@
use serde_derive::Serialize; use serde_derive::Serialize;
use types::{BeaconBlock, BeaconState, Hash256}; use types::{BeaconBlock, BeaconState, BeaconStateTypes, Hash256};
/// Represents some block and it's associated state. Generally, this will be used for tracking the /// Represents some block and it's associated state. Generally, this will be used for tracking the
/// head, justified head and finalized head. /// head, justified head and finalized head.
#[derive(Clone, Serialize, PartialEq, Debug)] #[derive(Clone, Serialize, PartialEq, Debug)]
pub struct CheckPoint { pub struct CheckPoint<B: BeaconStateTypes> {
pub beacon_block: BeaconBlock, pub beacon_block: BeaconBlock,
pub beacon_block_root: Hash256, pub beacon_block_root: Hash256,
pub beacon_state: BeaconState, pub beacon_state: BeaconState<B>,
pub beacon_state_root: Hash256, pub beacon_state_root: Hash256,
} }
impl CheckPoint { impl<B: BeaconStateTypes> CheckPoint<B> {
/// Create a new checkpoint. /// Create a new checkpoint.
pub fn new( pub fn new(
beacon_block: BeaconBlock, beacon_block: BeaconBlock,
beacon_block_root: Hash256, beacon_block_root: Hash256,
beacon_state: BeaconState, beacon_state: BeaconState<B>,
beacon_state_root: Hash256, beacon_state_root: Hash256,
) -> Self { ) -> Self {
Self { Self {
@ -32,7 +32,7 @@ impl CheckPoint {
&mut self, &mut self,
beacon_block: BeaconBlock, beacon_block: BeaconBlock,
beacon_block_root: Hash256, beacon_block_root: Hash256,
beacon_state: BeaconState, beacon_state: BeaconState<B>,
beacon_state_root: Hash256, beacon_state_root: Hash256,
) { ) {
self.beacon_block = beacon_block; self.beacon_block = beacon_block;

View File

@ -11,14 +11,21 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::test_utils::TestingBeaconStateBuilder; use types::test_utils::TestingBeaconStateBuilder;
use types::{BeaconBlock, ChainSpec, Hash256}; use types::{BeaconBlock, ChainSpec, FewValidatorsStateTypes, FoundationStateTypes, Hash256};
//TODO: Correct this for prod //TODO: Correct this for prod
//TODO: Account for historical db //TODO: Account for historical db
pub fn initialise_beacon_chain( pub fn initialise_beacon_chain(
spec: &ChainSpec, spec: &ChainSpec,
db_name: Option<&PathBuf>, db_name: Option<&PathBuf>,
) -> Arc<BeaconChain<DiskDB, SystemTimeSlotClock, BitwiseLMDGhost<DiskDB>>> { ) -> Arc<
BeaconChain<
DiskDB,
SystemTimeSlotClock,
BitwiseLMDGhost<DiskDB, FoundationStateTypes>,
FoundationStateTypes,
>,
> {
// set up the db // set up the db
let db = Arc::new(DiskDB::open( let db = Arc::new(DiskDB::open(
db_name.expect("Database directory must be included"), db_name.expect("Database directory must be included"),
@ -64,7 +71,14 @@ pub fn initialise_beacon_chain(
pub fn initialise_test_beacon_chain( pub fn initialise_test_beacon_chain(
spec: &ChainSpec, spec: &ChainSpec,
_db_name: Option<&PathBuf>, _db_name: Option<&PathBuf>,
) -> Arc<BeaconChain<MemoryDB, SystemTimeSlotClock, BitwiseLMDGhost<MemoryDB>>> { ) -> Arc<
BeaconChain<
MemoryDB,
SystemTimeSlotClock,
BitwiseLMDGhost<MemoryDB, FewValidatorsStateTypes>,
FewValidatorsStateTypes,
>,
> {
let db = Arc::new(MemoryDB::open()); let db = Arc::new(MemoryDB::open());
let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
let state_store = Arc::new(BeaconStateStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone()));

View File

@ -7,17 +7,18 @@ use fork_choice::BitwiseLMDGhost;
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use std::sync::Arc; use std::sync::Arc;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::test_utils::TestingBeaconStateBuilder;
use types::*; use types::*;
use types::{test_utils::TestingBeaconStateBuilder, BeaconStateTypes, FewValidatorsStateTypes};
type TestingBeaconChain = BeaconChain<MemoryDB, TestingSlotClock, BitwiseLMDGhost<MemoryDB>>; type TestingBeaconChain<B> =
BeaconChain<MemoryDB, TestingSlotClock, BitwiseLMDGhost<MemoryDB, FewValidatorsStateTypes>, B>;
pub struct TestingBeaconChainBuilder { pub struct TestingBeaconChainBuilder<B: BeaconStateTypes> {
state_builder: TestingBeaconStateBuilder, state_builder: TestingBeaconStateBuilder<B>,
} }
impl TestingBeaconChainBuilder { impl<B: BeaconStateTypes> TestingBeaconChainBuilder<B> {
pub fn build(self, spec: &ChainSpec) -> TestingBeaconChain { pub fn build(self, spec: &ChainSpec) -> TestingBeaconChain<B> {
let db = Arc::new(MemoryDB::open()); let db = Arc::new(MemoryDB::open());
let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
let state_store = Arc::new(BeaconStateStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone()));
@ -43,8 +44,8 @@ impl TestingBeaconChainBuilder {
} }
} }
impl From<TestingBeaconStateBuilder> for TestingBeaconChainBuilder { impl<B: BeaconStateTypes> From<TestingBeaconStateBuilder<B>> for TestingBeaconChainBuilder<B> {
fn from(state_builder: TestingBeaconStateBuilder) -> TestingBeaconChainBuilder { fn from(state_builder: TestingBeaconStateBuilder<B>) -> TestingBeaconChainBuilder<B> {
TestingBeaconChainBuilder { state_builder } TestingBeaconChainBuilder { state_builder }
} }
} }

View File

@ -9,8 +9,9 @@ use db::{
}; };
use log::{debug, trace}; use log::{debug, trace};
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight}; use types::{BeaconBlock, BeaconState, BeaconStateTypes, ChainSpec, Hash256, Slot, SlotHeight};
//TODO: Pruning - Children //TODO: Pruning - Children
//TODO: Handle Syncing //TODO: Handle Syncing
@ -33,7 +34,7 @@ fn power_of_2_below(x: u64) -> u64 {
} }
/// Stores the necessary data structures to run the optimised bitwise lmd ghost algorithm. /// Stores the necessary data structures to run the optimised bitwise lmd ghost algorithm.
pub struct BitwiseLMDGhost<T: ClientDB + Sized> { pub struct BitwiseLMDGhost<T: ClientDB + Sized, B: BeaconStateTypes> {
/// A cache of known ancestors at given heights for a specific block. /// A cache of known ancestors at given heights for a specific block.
//TODO: Consider FnvHashMap //TODO: Consider FnvHashMap
cache: HashMap<CacheKey<u64>, Hash256>, cache: HashMap<CacheKey<u64>, Hash256>,
@ -50,9 +51,10 @@ pub struct BitwiseLMDGhost<T: ClientDB + Sized> {
/// State storage access. /// State storage access.
state_store: Arc<BeaconStateStore<T>>, state_store: Arc<BeaconStateStore<T>>,
max_known_height: SlotHeight, max_known_height: SlotHeight,
_phantom: PhantomData<B>,
} }
impl<T> BitwiseLMDGhost<T> impl<T, B: BeaconStateTypes> BitwiseLMDGhost<T, B>
where where
T: ClientDB + Sized, T: ClientDB + Sized,
{ {
@ -68,6 +70,7 @@ where
max_known_height: SlotHeight::new(0), max_known_height: SlotHeight::new(0),
block_store, block_store,
state_store, state_store,
_phantom: PhantomData,
} }
} }
@ -85,7 +88,7 @@ where
// build a hashmap of block_hash to weighted votes // build a hashmap of block_hash to weighted votes
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new(); let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes // gets the current weighted votes
let current_state = self let current_state: BeaconState<B> = self
.state_store .state_store
.get_deserialized(&state_root)? .get_deserialized(&state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
@ -240,7 +243,7 @@ where
} }
} }
impl<T: ClientDB + Sized> ForkChoice for BitwiseLMDGhost<T> { impl<T: ClientDB + Sized, B: BeaconStateTypes> ForkChoice for BitwiseLMDGhost<T, B> {
fn add_block( fn add_block(
&mut self, &mut self,
block: &BeaconBlock, block: &BeaconBlock,

View File

@ -9,8 +9,9 @@ use db::{
use log::{debug, trace}; use log::{debug, trace};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Hash256, Slot, SlotHeight}; use types::{BeaconBlock, BeaconState, BeaconStateTypes, ChainSpec, Hash256, Slot, SlotHeight};
//TODO: Pruning - Children //TODO: Pruning - Children
//TODO: Handle Syncing //TODO: Handle Syncing
@ -33,7 +34,7 @@ fn power_of_2_below(x: u64) -> u64 {
} }
/// Stores the necessary data structures to run the optimised lmd ghost algorithm. /// Stores the necessary data structures to run the optimised lmd ghost algorithm.
pub struct OptimizedLMDGhost<T: ClientDB + Sized> { pub struct OptimizedLMDGhost<T: ClientDB + Sized, B: BeaconStateTypes> {
/// A cache of known ancestors at given heights for a specific block. /// A cache of known ancestors at given heights for a specific block.
//TODO: Consider FnvHashMap //TODO: Consider FnvHashMap
cache: HashMap<CacheKey<u64>, Hash256>, cache: HashMap<CacheKey<u64>, Hash256>,
@ -50,9 +51,10 @@ pub struct OptimizedLMDGhost<T: ClientDB + Sized> {
/// State storage access. /// State storage access.
state_store: Arc<BeaconStateStore<T>>, state_store: Arc<BeaconStateStore<T>>,
max_known_height: SlotHeight, max_known_height: SlotHeight,
_phantom: PhantomData<B>,
} }
impl<T> OptimizedLMDGhost<T> impl<T, B: BeaconStateTypes> OptimizedLMDGhost<T, B>
where where
T: ClientDB + Sized, T: ClientDB + Sized,
{ {
@ -68,6 +70,7 @@ where
max_known_height: SlotHeight::new(0), max_known_height: SlotHeight::new(0),
block_store, block_store,
state_store, state_store,
_phantom: PhantomData,
} }
} }
@ -85,7 +88,7 @@ where
// build a hashmap of block_hash to weighted votes // build a hashmap of block_hash to weighted votes
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new(); let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes // gets the current weighted votes
let current_state = self let current_state: BeaconState<B> = self
.state_store .state_store
.get_deserialized(&state_root)? .get_deserialized(&state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
@ -211,7 +214,7 @@ where
} }
} }
impl<T: ClientDB + Sized> ForkChoice for OptimizedLMDGhost<T> { impl<T: ClientDB + Sized, B: BeaconStateTypes> ForkChoice for OptimizedLMDGhost<T, B> {
fn add_block( fn add_block(
&mut self, &mut self,
block: &BeaconBlock, block: &BeaconBlock,

View File

@ -7,12 +7,13 @@ use db::{
}; };
use log::{debug, trace}; use log::{debug, trace};
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Hash256, Slot}; use types::{BeaconBlock, BeaconState, BeaconStateTypes, ChainSpec, Hash256, Slot};
//TODO: Pruning and syncing //TODO: Pruning and syncing
pub struct SlowLMDGhost<T: ClientDB + Sized> { pub struct SlowLMDGhost<T: ClientDB + Sized, B: BeaconStateTypes> {
/// The latest attestation targets as a map of validator index to block hash. /// The latest attestation targets as a map of validator index to block hash.
//TODO: Could this be a fixed size vec //TODO: Could this be a fixed size vec
latest_attestation_targets: HashMap<u64, Hash256>, latest_attestation_targets: HashMap<u64, Hash256>,
@ -22,9 +23,10 @@ pub struct SlowLMDGhost<T: ClientDB + Sized> {
block_store: Arc<BeaconBlockStore<T>>, block_store: Arc<BeaconBlockStore<T>>,
/// State storage access. /// State storage access.
state_store: Arc<BeaconStateStore<T>>, state_store: Arc<BeaconStateStore<T>>,
_phantom: PhantomData<B>,
} }
impl<T> SlowLMDGhost<T> impl<T, B: BeaconStateTypes> SlowLMDGhost<T, B>
where where
T: ClientDB + Sized, T: ClientDB + Sized,
{ {
@ -37,6 +39,7 @@ where
children: HashMap::new(), children: HashMap::new(),
block_store, block_store,
state_store, state_store,
_phantom: PhantomData,
} }
} }
@ -54,7 +57,7 @@ where
// build a hashmap of block_hash to weighted votes // build a hashmap of block_hash to weighted votes
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new(); let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes // gets the current weighted votes
let current_state = self let current_state: BeaconState<B> = self
.state_store .state_store
.get_deserialized(&state_root)? .get_deserialized(&state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?; .ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
@ -105,7 +108,7 @@ where
} }
} }
impl<T: ClientDB + Sized> ForkChoice for SlowLMDGhost<T> { impl<T: ClientDB + Sized, B: BeaconStateTypes> ForkChoice for SlowLMDGhost<T, B> {
/// Process when a block is added /// Process when a block is added
fn add_block( fn add_block(
&mut self, &mut self,

View File

@ -1,12 +1,13 @@
use crate::*; use crate::*;
use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192}; use fixed_len_vec::typenum::{Unsigned, U1024, U8, U8192};
use std::fmt::Debug;
pub trait BeaconStateTypes: Default { pub trait BeaconStateTypes: Default + Sync + Send + Clone + Debug + PartialEq {
type ShardCount: Unsigned + Clone + Sync + Send; type ShardCount: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send; type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send; type LatestRandaoMixesLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send; type LatestActiveIndexRootsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type LatestSlashedExitLength: Unsigned + Clone + Sync + Send; type LatestSlashedExitLength: Unsigned + Clone + Sync + Send + Debug + PartialEq;
fn spec() -> ChainSpec; fn spec() -> ChainSpec;
} }