Add beacon state test builder, tidy errors

This commit is contained in:
Paul Hauner 2019-02-15 16:12:24 +11:00
parent 5031ee5505
commit ec4a658fe7
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
9 changed files with 173 additions and 104 deletions

View File

@ -1,7 +1,7 @@
use state_processing::validate_attestation_without_signature; use state_processing::validate_attestation_without_signature;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use types::{ use types::{
beacon_state::CommitteesError, AggregateSignature, Attestation, AttestationData, BeaconState, beacon_state::BeaconStateError, AggregateSignature, Attestation, AttestationData, BeaconState,
Bitfield, ChainSpec, FreeAttestation, Signature, Bitfield, ChainSpec, FreeAttestation, Signature,
}; };
@ -79,7 +79,7 @@ impl AttestationAggregator {
state: &BeaconState, state: &BeaconState,
free_attestation: &FreeAttestation, free_attestation: &FreeAttestation,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<Outcome, CommitteesError> { ) -> Result<Outcome, BeaconStateError> {
let (slot, shard, committee_index) = some_or_invalid!( let (slot, shard, committee_index) = some_or_invalid!(
state.attestation_slot_and_shard_for_validator( state.attestation_slot_and_shard_for_validator(
free_attestation.validator_index as usize, free_attestation.validator_index as usize,

View File

@ -14,7 +14,7 @@ use state_processing::{
}; };
use std::sync::Arc; use std::sync::Arc;
use types::{ use types::{
beacon_state::CommitteesError, beacon_state::BeaconStateError,
readers::{BeaconBlockReader, BeaconStateReader}, readers::{BeaconBlockReader, BeaconStateReader},
AttestationData, BeaconBlock, BeaconBlockBody, BeaconState, ChainSpec, Crosslink, Deposit, AttestationData, BeaconBlock, BeaconBlockBody, BeaconState, ChainSpec, Crosslink, Deposit,
Epoch, Eth1Data, FreeAttestation, Hash256, PublicKey, Signature, Slot, Epoch, Eth1Data, FreeAttestation, Hash256, PublicKey, Signature, Slot,
@ -24,7 +24,7 @@ use types::{
pub enum Error { pub enum Error {
InsufficientValidators, InsufficientValidators,
BadRecentBlockRoots, BadRecentBlockRoots,
CommitteesError(CommitteesError), BeaconStateError(BeaconStateError),
DBInconsistent(String), DBInconsistent(String),
DBError(String), DBError(String),
ForkChoiceError(ForkChoiceError), ForkChoiceError(ForkChoiceError),
@ -99,7 +99,7 @@ where
initial_validator_deposits, initial_validator_deposits,
latest_eth1_data, latest_eth1_data,
&spec, &spec,
); )?;
let state_root = genesis_state.canonical_root(); let state_root = genesis_state.canonical_root();
state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?; state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?;
@ -252,7 +252,7 @@ where
/// ///
/// Information is read from the present `beacon_state` shuffling, so only information from the /// Information is read from the present `beacon_state` shuffling, so only information from the
/// present and prior epoch is available. /// present and prior epoch is available.
pub fn block_proposer(&self, slot: Slot) -> Result<usize, CommitteesError> { pub fn block_proposer(&self, slot: Slot) -> Result<usize, BeaconStateError> {
let index = self let index = self
.state .state
.read() .read()
@ -273,7 +273,7 @@ where
pub fn validator_attestion_slot_and_shard( pub fn validator_attestion_slot_and_shard(
&self, &self,
validator_index: usize, validator_index: usize,
) -> Result<Option<(Slot, u64)>, CommitteesError> { ) -> Result<Option<(Slot, u64)>, BeaconStateError> {
if let Some((slot, shard, _committee)) = self if let Some((slot, shard, _committee)) = self
.state .state
.read() .read()
@ -588,8 +588,8 @@ impl From<ForkChoiceError> for Error {
} }
} }
impl From<CommitteesError> for Error { impl From<BeaconStateError> for Error {
fn from(e: CommitteesError) -> Error { fn from(e: BeaconStateError) -> Error {
Error::CommitteesError(e) Error::BeaconStateError(e)
} }
} }

View File

@ -3,7 +3,7 @@ use hashing::hash;
use log::debug; use log::debug;
use ssz::{ssz_encode, TreeHash}; use ssz::{ssz_encode, TreeHash};
use types::{ use types::{
beacon_state::{AttestationValidationError, CommitteesError}, beacon_state::{AttestationParticipantsError, BeaconStateError},
AggregatePublicKey, Attestation, BeaconBlock, BeaconState, ChainSpec, Crosslink, Epoch, Exit, AggregatePublicKey, Attestation, BeaconBlock, BeaconState, ChainSpec, Crosslink, Epoch, Exit,
Fork, Hash256, PendingAttestation, PublicKey, Signature, Fork, Hash256, PendingAttestation, PublicKey, Signature,
}; };
@ -41,10 +41,23 @@ pub enum Error {
BadCustodyReseeds, BadCustodyReseeds,
BadCustodyChallenges, BadCustodyChallenges,
BadCustodyResponses, BadCustodyResponses,
CommitteesError(CommitteesError), BeaconStateError(BeaconStateError),
SlotProcessingError(SlotProcessingError), SlotProcessingError(SlotProcessingError),
} }
#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
IncludedTooEarly,
IncludedTooLate,
WrongJustifiedSlot,
WrongJustifiedRoot,
BadLatestCrosslinkRoot,
BadSignature,
ShardBlockRootNotZero,
NoBlockRoot,
AttestationParticipantsError(AttestationParticipantsError),
}
macro_rules! ensure { macro_rules! ensure {
($condition: expr, $result: expr) => { ($condition: expr, $result: expr) => {
if !$condition { if !$condition {
@ -390,9 +403,9 @@ impl From<AttestationValidationError> for Error {
} }
} }
impl From<CommitteesError> for Error { impl From<BeaconStateError> for Error {
fn from(e: CommitteesError) -> Error { fn from(e: BeaconStateError) -> Error {
Error::CommitteesError(e) Error::BeaconStateError(e)
} }
} }
@ -401,3 +414,9 @@ impl From<SlotProcessingError> for Error {
Error::SlotProcessingError(e) Error::SlotProcessingError(e)
} }
} }
impl From<AttestationParticipantsError> for AttestationValidationError {
fn from(e: AttestationParticipantsError) -> AttestationValidationError {
AttestationValidationError::AttestationParticipantsError(e)
}
}

View File

@ -5,7 +5,7 @@ use ssz::TreeHash;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::iter::FromIterator; use std::iter::FromIterator;
use types::{ use types::{
beacon_state::{AttestationParticipantsError, CommitteesError, InclusionError}, beacon_state::{AttestationParticipantsError, BeaconStateError, InclusionError},
validator_registry::get_active_validator_indices, validator_registry::get_active_validator_indices,
BeaconState, ChainSpec, Crosslink, Epoch, Hash256, PendingAttestation, BeaconState, ChainSpec, Crosslink, Epoch, Hash256, PendingAttestation,
}; };
@ -27,7 +27,7 @@ pub enum Error {
NoBlockRoots, NoBlockRoots,
BaseRewardQuotientIsZero, BaseRewardQuotientIsZero,
NoRandaoSeed, NoRandaoSeed,
CommitteesError(CommitteesError), BeaconStateError(BeaconStateError),
AttestationParticipantsError(AttestationParticipantsError), AttestationParticipantsError(AttestationParticipantsError),
InclusionError(InclusionError), InclusionError(InclusionError),
WinningRootError(WinningRootError), WinningRootError(WinningRootError),
@ -559,9 +559,7 @@ impl EpochProcessable for BeaconState {
self.current_epoch_start_shard = (self.current_epoch_start_shard self.current_epoch_start_shard = (self.current_epoch_start_shard
+ self.get_current_epoch_committee_count(spec) as u64) + self.get_current_epoch_committee_count(spec) as u64)
% spec.shard_count; % spec.shard_count;
self.current_epoch_seed = self self.current_epoch_seed = self.generate_seed(self.current_calculation_epoch, spec)?
.generate_seed(self.current_calculation_epoch, spec)
.ok_or_else(|| Error::NoRandaoSeed)?;
} else { } else {
let epochs_since_last_registry_update = let epochs_since_last_registry_update =
current_epoch - self.validator_registry_update_epoch; current_epoch - self.validator_registry_update_epoch;
@ -569,9 +567,8 @@ impl EpochProcessable for BeaconState {
& epochs_since_last_registry_update.is_power_of_two() & epochs_since_last_registry_update.is_power_of_two()
{ {
self.current_calculation_epoch = next_epoch; self.current_calculation_epoch = next_epoch;
self.current_epoch_seed = self self.current_epoch_seed =
.generate_seed(self.current_calculation_epoch, spec) self.generate_seed(self.current_calculation_epoch, spec)?
.ok_or_else(|| Error::NoRandaoSeed)?;
} }
} }
@ -689,9 +686,9 @@ impl From<InclusionError> for Error {
} }
} }
impl From<CommitteesError> for Error { impl From<BeaconStateError> for Error {
fn from(e: CommitteesError) -> Error { fn from(e: BeaconStateError) -> Error {
Error::CommitteesError(e) Error::BeaconStateError(e)
} }
} }

View File

@ -1,9 +1,9 @@
use crate::{EpochProcessable, EpochProcessingError}; use crate::{EpochProcessable, EpochProcessingError};
use types::{beacon_state::CommitteesError, BeaconState, ChainSpec, Hash256}; use types::{beacon_state::BeaconStateError, BeaconState, ChainSpec, Hash256};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
CommitteesError(CommitteesError), BeaconStateError(BeaconStateError),
EpochProcessingError(EpochProcessingError), EpochProcessingError(EpochProcessingError),
} }
@ -49,9 +49,9 @@ fn merkle_root(_input: &[Hash256]) -> Hash256 {
Hash256::zero() Hash256::zero()
} }
impl From<CommitteesError> for Error { impl From<BeaconStateError> for Error {
fn from(e: CommitteesError) -> Error { fn from(e: BeaconStateError) -> Error {
Error::CommitteesError(e) Error::BeaconStateError(e)
} }
} }

View File

@ -19,3 +19,6 @@ serde_json = "1.0"
slog = "^2.2.3" slog = "^2.2.3"
ssz = { path = "../utils/ssz" } ssz = { path = "../utils/ssz" }
vec_shuffle = { path = "../utils/vec_shuffle" } vec_shuffle = { path = "../utils/vec_shuffle" }
[dev-dependencies]
env_logger = "0.6.0"

View File

@ -9,48 +9,31 @@ use honey_badger_split::SplitExt;
use rand::RngCore; use rand::RngCore;
use serde_derive::Serialize; use serde_derive::Serialize;
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
use std::ops::Range;
use vec_shuffle::shuffle; use vec_shuffle::shuffle;
pub enum Error {
InsufficientValidators,
BadBlockSignature,
InvalidEpoch(Slot, Range<Epoch>),
CommitteesError(CommitteesError),
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum CommitteesError { pub enum BeaconStateError {
InvalidEpoch, EpochOutOfBounds,
InsufficientNumberOfValidators, InsufficientRandaoMixes,
BadRandao, InsufficientValidators,
InsufficientBlockRoots,
InsufficientIndexRoots,
InsufficientAttestations,
InsufficientCommittees,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum InclusionError { pub enum InclusionError {
NoIncludedAttestations, /// The validator did not participate in an attestation in this period.
NoAttestationsForValidator,
AttestationParticipantsError(AttestationParticipantsError), AttestationParticipantsError(AttestationParticipantsError),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum AttestationParticipantsError { pub enum AttestationParticipantsError {
/// There is no committee for the given shard in the given epoch.
NoCommitteeForShard, NoCommitteeForShard,
NoCommittees, BeaconStateError(BeaconStateError),
BadBitfieldLength,
CommitteesError(CommitteesError),
}
#[derive(Debug, PartialEq)]
pub enum AttestationValidationError {
IncludedTooEarly,
IncludedTooLate,
WrongJustifiedSlot,
WrongJustifiedRoot,
BadLatestCrosslinkRoot,
BadSignature,
ShardBlockRootNotZero,
NoBlockRoot,
AttestationParticipantsError(AttestationParticipantsError),
} }
macro_rules! safe_add_assign { macro_rules! safe_add_assign {
@ -111,7 +94,7 @@ impl BeaconState {
initial_validator_deposits: Vec<Deposit>, initial_validator_deposits: Vec<Deposit>,
latest_eth1_data: Eth1Data, latest_eth1_data: Eth1Data,
spec: &ChainSpec, spec: &ChainSpec,
) -> BeaconState { ) -> Result<BeaconState, BeaconStateError> {
let initial_crosslink = Crosslink { let initial_crosslink = Crosslink {
epoch: spec.genesis_epoch, epoch: spec.genesis_epoch,
shard_block_root: spec.zero_hash, shard_block_root: spec.zero_hash,
@ -195,11 +178,9 @@ impl BeaconState {
)); ));
genesis_state.latest_index_roots = genesis_state.latest_index_roots =
vec![genesis_active_index_root; spec.latest_index_roots_length]; vec![genesis_active_index_root; spec.latest_index_roots_length];
genesis_state.current_epoch_seed = genesis_state genesis_state.current_epoch_seed = genesis_state.generate_seed(spec.genesis_epoch, spec)?;
.generate_seed(spec.genesis_epoch, spec)
.expect("Unable to generate seed.");
genesis_state Ok(genesis_state)
} }
/// Return the tree hash root for this `BeaconState`. /// Return the tree hash root for this `BeaconState`.
@ -322,7 +303,7 @@ impl BeaconState {
+ 1; + 1;
let latest_index_root = current_epoch + spec.entry_exit_delay; let latest_index_root = current_epoch + spec.entry_exit_delay;
if (epoch <= earliest_index_root) & (epoch >= latest_index_root) { if (epoch >= earliest_index_root) & (epoch <= latest_index_root) {
Some(self.latest_index_roots[epoch.as_usize() % spec.latest_index_roots_length]) Some(self.latest_index_roots[epoch.as_usize() % spec.latest_index_roots_length])
} else { } else {
None None
@ -332,12 +313,27 @@ impl BeaconState {
/// Generate a seed for the given ``epoch``. /// Generate a seed for the given ``epoch``.
/// ///
/// Spec v0.2.0 /// Spec v0.2.0
pub fn generate_seed(&self, epoch: Epoch, spec: &ChainSpec) -> Option<Hash256> { pub fn generate_seed(
let mut input = self.get_randao_mix(epoch, spec)?.to_vec(); &self,
input.append(&mut self.get_active_index_root(epoch, spec)?.to_vec()); epoch: Epoch,
spec: &ChainSpec,
) -> Result<Hash256, BeaconStateError> {
let mut input = self
.get_randao_mix(epoch, spec)
.ok_or_else(|| BeaconStateError::InsufficientRandaoMixes)?
.to_vec();
input.append(
&mut self
.get_active_index_root(epoch, spec)
.ok_or_else(|| BeaconStateError::InsufficientIndexRoots)?
.to_vec(),
);
// TODO: ensure `Hash256::from(u64)` == `int_to_bytes32`. // TODO: ensure `Hash256::from(u64)` == `int_to_bytes32`.
input.append(&mut Hash256::from(epoch.as_u64()).to_vec()); input.append(&mut Hash256::from(epoch.as_u64()).to_vec());
Some(Hash256::from(&hash(&input[..])[..]))
Ok(Hash256::from(&hash(&input[..])[..]))
} }
/// Return the list of ``(committee, shard)`` tuples for the ``slot``. /// Return the list of ``(committee, shard)`` tuples for the ``slot``.
@ -351,7 +347,7 @@ impl BeaconState {
slot: Slot, slot: Slot,
registry_change: bool, registry_change: bool,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<Vec<(Vec<usize>, u64)>, CommitteesError> { ) -> Result<Vec<(Vec<usize>, u64)>, BeaconStateError> {
let epoch = slot.epoch(spec.epoch_length); let epoch = slot.epoch(spec.epoch_length);
let current_epoch = self.current_epoch(spec); let current_epoch = self.current_epoch(spec);
let previous_epoch = if current_epoch == spec.genesis_epoch { let previous_epoch = if current_epoch == spec.genesis_epoch {
@ -381,9 +377,7 @@ impl BeaconState {
let epochs_since_last_registry_update = let epochs_since_last_registry_update =
current_epoch - self.validator_registry_update_epoch; current_epoch - self.validator_registry_update_epoch;
let (seed, shuffling_start_shard) = if registry_change { let (seed, shuffling_start_shard) = if registry_change {
let next_seed = self let next_seed = self.generate_seed(next_epoch, spec)?;
.generate_seed(next_epoch, spec)
.ok_or_else(|| CommitteesError::BadRandao)?;
( (
next_seed, next_seed,
(self.current_epoch_start_shard + current_committees_per_epoch) (self.current_epoch_start_shard + current_committees_per_epoch)
@ -392,9 +386,7 @@ impl BeaconState {
} else if (epochs_since_last_registry_update > 1) } else if (epochs_since_last_registry_update > 1)
& epochs_since_last_registry_update.is_power_of_two() & epochs_since_last_registry_update.is_power_of_two()
{ {
let next_seed = self let next_seed = self.generate_seed(next_epoch, spec)?;
.generate_seed(next_epoch, spec)
.ok_or_else(|| CommitteesError::BadRandao)?;
(next_seed, self.current_epoch_start_shard) (next_seed, self.current_epoch_start_shard)
} else { } else {
(self.current_epoch_seed, self.current_epoch_start_shard) (self.current_epoch_seed, self.current_epoch_start_shard)
@ -406,7 +398,7 @@ impl BeaconState {
shuffling_start_shard, shuffling_start_shard,
) )
} else { } else {
panic!("Epoch out-of-bounds.") return Err(BeaconStateError::EpochOutOfBounds);
}; };
let shuffling = self.get_shuffling(seed, shuffling_epoch, spec); let shuffling = self.get_shuffling(seed, shuffling_epoch, spec);
@ -434,7 +426,7 @@ impl BeaconState {
&self, &self,
validator_index: usize, validator_index: usize,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<Option<(Slot, u64, u64)>, CommitteesError> { ) -> Result<Option<(Slot, u64, u64)>, BeaconStateError> {
let mut result = None; let mut result = None;
for slot in self.current_epoch(spec).slot_iter(spec.epoch_length) { for slot in self.current_epoch(spec).slot_iter(spec.epoch_length) {
for (committee, shard) in self.get_crosslink_committees_at_slot(slot, false, spec)? { for (committee, shard) in self.get_crosslink_committees_at_slot(slot, false, spec)? {
@ -464,16 +456,15 @@ impl BeaconState {
&self, &self,
slot: Slot, slot: Slot,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<usize, CommitteesError> { ) -> Result<usize, BeaconStateError> {
let committees = self.get_crosslink_committees_at_slot(slot, false, spec)?; let committees = self.get_crosslink_committees_at_slot(slot, false, spec)?;
committees committees
.first() .first()
.ok_or(CommitteesError::InsufficientNumberOfValidators) .ok_or(BeaconStateError::InsufficientValidators)
.and_then(|(first_committee, _)| { .and_then(|(first_committee, _)| {
let index = (slot.as_usize()) let index = (slot.as_usize())
.checked_rem(first_committee.len()) .checked_rem(first_committee.len())
.ok_or(CommitteesError::InsufficientNumberOfValidators)?; .ok_or(BeaconStateError::InsufficientValidators)?;
// NOTE: next index will not panic as we have already returned if this is the case.
Ok(first_committee[index]) Ok(first_committee[index])
}) })
} }
@ -682,7 +673,7 @@ impl BeaconState {
&mut self, &mut self,
validator_index: usize, validator_index: usize,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), CommitteesError> { ) -> Result<(), BeaconStateError> {
self.exit_validator(validator_index, spec); self.exit_validator(validator_index, spec);
let current_epoch = self.current_epoch(spec); let current_epoch = self.current_epoch(spec);
@ -802,7 +793,7 @@ impl BeaconState {
let earliest_attestation_index = included_attestations let earliest_attestation_index = included_attestations
.iter() .iter()
.min_by_key(|i| attestations[**i].inclusion_slot) .min_by_key(|i| attestations[**i].inclusion_slot)
.ok_or_else(|| InclusionError::NoIncludedAttestations)?; .ok_or_else(|| InclusionError::NoAttestationsForValidator)?;
Ok(attestations[*earliest_attestation_index].clone()) Ok(attestations[*earliest_attestation_index].clone())
} }
@ -907,34 +898,18 @@ fn hash_tree_root<T: TreeHash>(input: Vec<T>) -> Hash256 {
Hash256::from(&input.hash_tree_root()[..]) Hash256::from(&input.hash_tree_root()[..])
} }
impl From<AttestationParticipantsError> for AttestationValidationError { impl From<BeaconStateError> for AttestationParticipantsError {
fn from(e: AttestationParticipantsError) -> AttestationValidationError { fn from(e: BeaconStateError) -> AttestationParticipantsError {
AttestationValidationError::AttestationParticipantsError(e) AttestationParticipantsError::BeaconStateError(e)
} }
} }
impl From<CommitteesError> for AttestationParticipantsError {
fn from(e: CommitteesError) -> AttestationParticipantsError {
AttestationParticipantsError::CommitteesError(e)
}
}
/*
*/
impl From<AttestationParticipantsError> for InclusionError { impl From<AttestationParticipantsError> for InclusionError {
fn from(e: AttestationParticipantsError) -> InclusionError { fn from(e: AttestationParticipantsError) -> InclusionError {
InclusionError::AttestationParticipantsError(e) InclusionError::AttestationParticipantsError(e)
} }
} }
impl From<CommitteesError> for Error {
fn from(e: CommitteesError) -> Error {
Error::CommitteesError(e)
}
}
impl Encodable for BeaconState { impl Encodable for BeaconState {
fn ssz_append(&self, s: &mut SszStream) { fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot); s.append(&self.slot);

View File

@ -0,0 +1,74 @@
use crate::{
beacon_state::BeaconStateError, BeaconState, ChainSpec, Deposit, DepositData, DepositInput,
Eth1Data, Hash256, Keypair,
};
use bls::create_proof_of_possession;
struct BeaconStateTestBuilder {
pub genesis_time: u64,
pub initial_validator_deposits: Vec<Deposit>,
pub latest_eth1_data: Eth1Data,
pub spec: ChainSpec,
pub keypairs: Vec<Keypair>,
}
impl BeaconStateTestBuilder {
pub fn with_random_validators(validator_count: usize) -> Self {
let genesis_time = 10_000_000;
let keypairs: Vec<Keypair> = (0..validator_count)
.collect::<Vec<usize>>()
.iter()
.map(|_| Keypair::random())
.collect();
let initial_validator_deposits = keypairs
.iter()
.map(|keypair| Deposit {
branch: vec![], // branch verification is not specified.
index: 0, // index verification is not specified.
deposit_data: DepositData {
amount: 32_000_000_000, // 32 ETH (in Gwei)
timestamp: genesis_time - 1,
deposit_input: DepositInput {
pubkey: keypair.pk.clone(),
withdrawal_credentials: Hash256::zero(), // Withdrawal not possible.
proof_of_possession: create_proof_of_possession(&keypair),
},
},
})
.collect();
let latest_eth1_data = Eth1Data {
deposit_root: Hash256::zero(),
block_hash: Hash256::zero(),
};
let spec = ChainSpec::foundation();
Self {
genesis_time,
initial_validator_deposits,
latest_eth1_data,
spec,
keypairs,
}
}
pub fn build(&self) -> Result<BeaconState, BeaconStateError> {
BeaconState::genesis(
self.genesis_time,
self.initial_validator_deposits.clone(),
self.latest_eth1_data.clone(),
&self.spec,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn can_produce_genesis_block() {
let builder = BeaconStateTestBuilder::with_random_validators(2);
builder.build().unwrap();
}
}

View File

@ -7,6 +7,7 @@ pub mod attester_slashing;
pub mod beacon_block; pub mod beacon_block;
pub mod beacon_block_body; pub mod beacon_block_body;
pub mod beacon_state; pub mod beacon_state;
pub mod beacon_state_tests;
pub mod casper_slashing; pub mod casper_slashing;
pub mod crosslink; pub mod crosslink;
pub mod deposit; pub mod deposit;