From 4b21252ce4777627fd50108bd2d9f75cec4bed29 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 8 Mar 2019 15:33:45 +1100 Subject: [PATCH] Refactor BeaconChain and BeaconState genesis Now it more easily supports using pre-build validator registries. --- beacon_node/beacon_chain/src/beacon_chain.rs | 19 +-- .../test_harness/src/beacon_chain_harness.rs | 16 +- eth2/types/src/beacon_state.rs | 42 ++--- eth2/types/src/beacon_state/builder.rs | 154 ++++++------------ 4 files changed, 83 insertions(+), 148 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 3d2efa8ae..b0e84e1e1 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -73,31 +73,18 @@ where F: ForkChoice, { /// Instantiate a new Beacon Chain, from genesis. - #[allow(clippy::too_many_arguments)] // Will be re-factored in the coming weeks. - pub fn genesis( + pub fn from_genesis( state_store: Arc>, block_store: Arc>, slot_clock: U, - genesis_time: u64, - latest_eth1_data: Eth1Data, - initial_validator_deposits: Vec, + mut genesis_state: BeaconState, + genesis_block: BeaconBlock, spec: ChainSpec, fork_choice: F, ) -> Result { - if initial_validator_deposits.is_empty() { - return Err(Error::InsufficientValidators); - } - - let mut genesis_state = BeaconState::genesis( - genesis_time, - initial_validator_deposits, - latest_eth1_data, - &spec, - )?; let state_root = genesis_state.canonical_root(); state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?; - let genesis_block = BeaconBlock::genesis(state_root, &spec); let block_root = genesis_block.canonical_root(); block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?; diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 8ec07a994..c41f6fa1e 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -9,11 +9,12 @@ use fork_choice::BitwiseLMDGhost; use log::debug; use rayon::prelude::*; use slot_clock::TestingSlotClock; +use ssz::TreeHash; use std::collections::HashSet; use std::iter::FromIterator; use std::path::Path; use std::sync::Arc; -use types::*; +use types::{beacon_state::BeaconStateBuilder, *}; mod generate_deposits; mod load_deposits_from_file; @@ -67,15 +68,20 @@ impl BeaconChainHarness { (keypairs, deposits) }; + let mut state_builder = BeaconStateBuilder::new(genesis_time, latest_eth1_data, &spec); + state_builder.process_initial_deposits(&initial_validator_deposits, &spec); + let genesis_state = state_builder.build(&spec).unwrap(); + let state_root = Hash256::from_slice(&genesis_state.hash_tree_root()); + let genesis_block = BeaconBlock::genesis(state_root, &spec); + // Create the Beacon Chain let beacon_chain = Arc::new( - BeaconChain::genesis( + BeaconChain::from_genesis( state_store.clone(), block_store.clone(), slot_clock, - genesis_time, - latest_eth1_data, - initial_validator_deposits, + genesis_state, + genesis_block, spec.clone(), fork_choice, ) diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 809408b32..f3d533527 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -114,18 +114,13 @@ pub struct BeaconState { impl BeaconState { /// Produce the first state of the Beacon Chain. - pub fn genesis_without_validators( - genesis_time: u64, - latest_eth1_data: Eth1Data, - spec: &ChainSpec, - ) -> Result { - debug!("Creating genesis state (without validator processing)."); + pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState { let initial_crosslink = Crosslink { epoch: spec.genesis_epoch, crosslink_data_root: spec.zero_hash, }; - Ok(BeaconState { + BeaconState { /* * Misc */ @@ -188,19 +183,15 @@ impl BeaconState { */ cache_index_offset: 0, caches: vec![EpochCache::empty(); CACHED_EPOCHS], - }) + } } /// Produce the first state of the Beacon Chain. - pub fn genesis( - genesis_time: u64, + pub fn process_initial_deposits( + &mut self, initial_validator_deposits: Vec, - latest_eth1_data: Eth1Data, spec: &ChainSpec, - ) -> Result { - let mut genesis_state = - BeaconState::genesis_without_validators(genesis_time, latest_eth1_data, spec)?; - + ) -> Result<(), Error> { debug!("Processing genesis deposits..."); let deposit_data = initial_validator_deposits @@ -208,29 +199,28 @@ impl BeaconState { .map(|deposit| &deposit.deposit_data) .collect(); - genesis_state.process_deposits(deposit_data, spec); + self.process_deposits(deposit_data, spec); trace!("Processed genesis deposits."); - for validator_index in 0..genesis_state.validator_registry.len() { - if genesis_state.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount - { - genesis_state.activate_validator(validator_index, true, spec); + for validator_index in 0..self.validator_registry.len() { + if self.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount { + self.activate_validator(validator_index, true, spec); } } - genesis_state.deposit_index = initial_validator_deposits.len() as u64; + self.deposit_index = initial_validator_deposits.len() as u64; let genesis_active_index_root = hash_tree_root(get_active_validator_indices( - &genesis_state.validator_registry, + &self.validator_registry, spec.genesis_epoch, )); - genesis_state.latest_active_index_roots = + self.latest_active_index_roots = vec![genesis_active_index_root; spec.latest_active_index_roots_length]; - genesis_state.current_shuffling_seed = - genesis_state.generate_seed(spec.genesis_epoch, spec)?; - Ok(genesis_state) + self.current_shuffling_seed = self.generate_seed(spec.genesis_epoch, spec)?; + + Ok(()) } /// Returns the `hash_tree_root` of the state. diff --git a/eth2/types/src/beacon_state/builder.rs b/eth2/types/src/beacon_state/builder.rs index 0be297db7..4bb5e2cc6 100644 --- a/eth2/types/src/beacon_state/builder.rs +++ b/eth2/types/src/beacon_state/builder.rs @@ -1,5 +1,9 @@ +use super::BeaconStateError; use crate::*; +use crate::{validator_registry::get_active_validator_indices, *}; use bls::create_proof_of_possession; +use rayon::prelude::*; +use ssz::TreeHash; /// Builds a `BeaconState` for use in testing or benchmarking. /// @@ -16,128 +20,73 @@ use bls::create_proof_of_possession; /// Step (4) produces a clone of the BeaconState and doesn't consume the `BeaconStateBuilder` to /// allow access to `self.keypairs` and `self.spec`. pub struct BeaconStateBuilder { - pub validator_count: usize, - pub state: Option, - pub genesis_time: u64, - pub latest_eth1_data: Eth1Data, - pub spec: ChainSpec, - pub keypairs: Vec, + pub state: BeaconState, } impl BeaconStateBuilder { /// Create a new builder with the given number of validators. - pub fn new(validator_count: usize) -> Self { - let genesis_time = 10_000_000; - - let latest_eth1_data = Eth1Data { - deposit_root: Hash256::zero(), - block_hash: Hash256::zero(), - }; - - let spec = ChainSpec::foundation(); - + /// + /// Spec v0.4.0 + pub fn new(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> Self { Self { - validator_count, - state: None, - genesis_time, - latest_eth1_data, - spec, - keypairs: vec![], + state: BeaconState::genesis(genesis_time, latest_eth1_data, spec), } } + /// Produce the first state of the Beacon Chain. + /// + /// Spec v0.4.0 + pub fn process_initial_deposits( + &mut self, + initial_validator_deposits: &[Deposit], + spec: &ChainSpec, + ) { + let deposit_data = initial_validator_deposits + .par_iter() + .map(|deposit| &deposit.deposit_data) + .collect(); + + self.state.process_deposits(deposit_data, spec); + + for validator_index in 0..self.state.validator_registry.len() { + if self.state.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount { + self.state.activate_validator(validator_index, true, spec); + } + } + + self.state.deposit_index = initial_validator_deposits.len() as u64; + } + /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function. /// /// Each validator is assigned a unique, randomly-generated keypair and all /// proof-of-possessions are verified during genesis. - pub fn build(&mut self) -> Result<(), BeaconStateError> { - self.keypairs = (0..self.validator_count) - .collect::>() - .iter() - .map(|_| Keypair::random()) - .collect(); + /// + /// Spec v0.4.0 + pub fn build(mut self, spec: &ChainSpec) -> Result { + let genesis_active_index_root = + get_active_validator_indices(&self.state.validator_registry, spec.genesis_epoch) + .hash_tree_root(); - let initial_validator_deposits = self - .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: self.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(); + self.state.latest_active_index_roots = vec![ + Hash256::from_slice(&genesis_active_index_root); + spec.latest_active_index_roots_length + ]; - let state = BeaconState::genesis( - self.genesis_time, - initial_validator_deposits, - self.latest_eth1_data.clone(), - &self.spec, - )?; + self.state.current_shuffling_seed = self.state.generate_seed(spec.genesis_epoch, spec)?; - self.state = Some(state); - - Ok(()) - } - - /// Builds a `BeaconState` using the `BeaconState::genesis(..)` function, without supplying any - /// validators. Instead validators are added to the state post-genesis. - /// - /// One keypair is randomly generated and all validators are assigned this same keypair. - /// Proof-of-possessions are not created (or validated). - /// - /// This function runs orders of magnitude faster than `Self::build()`, however it will be - /// erroneous for functions which use a validators public key as an identifier (e.g., - /// deposits). - pub fn build_fast(&mut self) -> Result<(), BeaconStateError> { - let common_keypair = Keypair::random(); - - let mut validator_registry = Vec::with_capacity(self.validator_count); - let mut validator_balances = Vec::with_capacity(self.validator_count); - self.keypairs = Vec::with_capacity(self.validator_count); - - for _ in 0..self.validator_count { - self.keypairs.push(common_keypair.clone()); - validator_balances.push(32_000_000_000); - validator_registry.push(Validator { - pubkey: common_keypair.pk.clone(), - withdrawal_credentials: Hash256::zero(), - activation_epoch: self.spec.genesis_epoch, - ..Validator::default() - }) - } - - let state = BeaconState { - validator_registry, - validator_balances, - ..BeaconState::genesis( - self.genesis_time, - vec![], - self.latest_eth1_data.clone(), - &self.spec, - )? - }; - - self.state = Some(state); - - Ok(()) + Ok(self.state) } + /* /// Sets the `BeaconState` to be in the last slot of the given epoch. /// /// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e., /// highest justified and finalized slots, full justification bitfield, etc). - pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch) { - let state = self.state.as_mut().expect("Genesis required"); + pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch, spec: &ChainSpec) { + let state = &mut self.state; - let slot = epoch.end_slot(self.spec.slots_per_epoch); + let slot = epoch.end_slot(spec.slots_per_epoch); state.slot = slot; state.validator_registry_update_epoch = epoch - 1; @@ -159,7 +108,7 @@ impl BeaconStateBuilder { /// /// These attestations should be fully conducive to justification and finalization. pub fn insert_attestations(&mut self) { - let state = self.state.as_mut().expect("Genesis required"); + let state = &mut self.state; state .build_epoch_cache(RelativeEpoch::Previous, &self.spec) @@ -198,8 +147,10 @@ impl BeaconStateBuilder { pub fn cloned_state(&self) -> BeaconState { self.state.as_ref().expect("Genesis required").clone() } + */ } +/* /// Builds a valid PendingAttestation with full participation for some committee. fn committee_to_pending_attestation( state: &BeaconState, @@ -261,3 +212,4 @@ fn committee_to_pending_attestation( inclusion_slot: slot, } } +*/