From 3b75e931223b61c866c62853a9fed067b34a6e3f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 12 Feb 2019 11:54:02 +1100 Subject: [PATCH] Add `genesis()` to `BeaconState` --- eth2/types/src/beacon_state.rs | 163 +++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 16 deletions(-) diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 0d5b19eb6..1b959976b 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -1,10 +1,10 @@ use crate::test_utils::TestRandom; use crate::{ - validator::StatusFlags, validator_registry::get_active_validator_indices, AggregatePublicKey, - Attestation, AttestationData, Bitfield, ChainSpec, Crosslink, Epoch, Eth1Data, Eth1DataVote, - Fork, Hash256, PendingAttestation, Slot, Validator, + validator::StatusFlags, validator_registry::get_active_validator_indices, AttestationData, + Bitfield, ChainSpec, Crosslink, Deposit, Epoch, Eth1Data, Eth1DataVote, Fork, Hash256, + PendingAttestation, PublicKey, Signature, Slot, Validator, }; -use bls::bls_verify_aggregate; +use bls::verify_proof_of_possession; use honey_badger_split::SplitExt; use rand::RngCore; use serde_derive::Serialize; @@ -12,10 +12,6 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use std::ops::Range; use vec_shuffle::shuffle; -// TODO: define elsehwere. -const PHASE_0_CUSTODY_BIT: bool = false; -const DOMAIN_ATTESTATION: u64 = 1; - pub enum Error { InsufficientValidators, BadBlockSignature, @@ -65,14 +61,6 @@ pub enum AttestationValidationError { AttestationParticipantsError(AttestationParticipantsError), } -macro_rules! ensure { - ($condition: expr, $result: expr) => { - if !$condition { - return Err($result); - } - }; -} - macro_rules! safe_add_assign { ($a: expr, $b: expr) => { $a = $a.saturating_add($b); @@ -125,6 +113,103 @@ pub struct BeaconState { } impl BeaconState { + /// Produce the first state of the Beacon Chain. + pub fn genesis( + genesis_time: u64, + initial_validator_deposits: Vec, + latest_eth1_data: Eth1Data, + spec: &ChainSpec, + ) -> BeaconState { + let initial_crosslink = Crosslink { + epoch: spec.genesis_epoch, + shard_block_root: spec.zero_hash, + }; + + let mut genesis_state = BeaconState { + /* + * Misc + */ + slot: spec.genesis_slot, + genesis_time, + fork: Fork { + previous_version: spec.genesis_fork_version, + current_version: spec.genesis_fork_version, + epoch: spec.genesis_epoch, + }, + + /* + * Validator registry + */ + validator_registry: vec![], // Set later in the function. + validator_balances: vec![], // Set later in the function. + validator_registry_update_epoch: spec.genesis_epoch, + + /* + * Randomness and committees + */ + latest_randao_mixes: vec![spec.zero_hash; spec.latest_randao_mixes_length as usize], + previous_epoch_start_shard: spec.genesis_start_shard, + current_epoch_start_shard: spec.genesis_start_shard, + previous_calculation_epoch: spec.genesis_epoch, + current_calculation_epoch: spec.genesis_epoch, + previous_epoch_seed: spec.zero_hash, + current_epoch_seed: spec.zero_hash, + + /* + * Finality + */ + previous_justified_epoch: spec.genesis_epoch, + justified_epoch: spec.genesis_epoch, + justification_bitfield: 0, + finalized_epoch: spec.genesis_epoch, + + /* + * Recent state + */ + latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize], + latest_block_roots: vec![spec.zero_hash; spec.latest_block_roots_length as usize], + latest_index_roots: vec![spec.zero_hash; spec.latest_index_roots_length as usize], + latest_penalized_balances: vec![0; spec.latest_penalized_exit_length as usize], + latest_attestations: vec![], + batched_block_roots: vec![], + + /* + * PoW receipt root + */ + latest_eth1_data, + eth1_data_votes: vec![], + }; + + for deposit in initial_validator_deposits { + let _index = genesis_state.process_deposit( + deposit.deposit_data.deposit_input.pubkey, + deposit.deposit_data.amount, + deposit.deposit_data.deposit_input.proof_of_possession, + deposit.deposit_data.deposit_input.withdrawal_credentials, + spec, + ); + } + + 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); + } + } + + let genesis_active_index_root = hash_tree_root(get_active_validator_indices( + &genesis_state.validator_registry, + spec.genesis_epoch, + )); + genesis_state.latest_index_roots = + vec![genesis_active_index_root; spec.latest_index_roots_length]; + genesis_state.current_epoch_seed = genesis_state + .generate_seed(spec.genesis_epoch, spec) + .expect("Unable to generate seed."); + + genesis_state + } + /// Return the tree hash root for this `BeaconState`. /// /// Spec v0.2.0 @@ -512,6 +597,48 @@ impl BeaconState { self.validator_registry_update_epoch = current_epoch; } + /// Process a validator deposit, returning the validator index if the deposit is valid. + /// + /// Spec v0.2.0 + pub fn process_deposit( + &mut self, + pubkey: PublicKey, + amount: u64, + proof_of_possession: Signature, + withdrawal_credentials: Hash256, + spec: &ChainSpec, + ) -> Result { + // TODO: ensure verify proof-of-possession represents the spec accurately. + if !verify_proof_of_possession(&proof_of_possession, &pubkey) { + return Err(()); + } + + if let Some(index) = self + .validator_registry + .iter() + .position(|v| v.pubkey == pubkey) + { + if self.validator_registry[index].withdrawal_credentials == withdrawal_credentials { + safe_add_assign!(self.validator_balances[index], amount); + Ok(index) + } else { + Err(()) + } + } else { + let validator = Validator { + pubkey, + withdrawal_credentials, + activation_epoch: spec.far_future_epoch, + exit_epoch: spec.far_future_epoch, + withdrawal_epoch: spec.far_future_epoch, + penalized_epoch: spec.far_future_epoch, + status_flags: None, + }; + self.validator_registry.push(validator); + self.validator_balances.push(amount); + Ok(self.validator_registry.len() - 1) + } + } /// Activate the validator of the given ``index``. /// @@ -790,6 +917,10 @@ impl BeaconState { } } +fn hash_tree_root(input: Vec) -> Hash256 { + Hash256::from(&input.hash_tree_root()[..]) +} + impl From for AttestationValidationError { fn from(e: AttestationParticipantsError) -> AttestationValidationError { AttestationValidationError::AttestationParticipantsError(e)