mirror of
https://gitlab.com/pulsechaincom/lighthouse-pulse.git
synced 2024-12-28 14:57:17 +00:00
Refactor BeaconChain and BeaconState genesis
Now it more easily supports using pre-build validator registries.
This commit is contained in:
parent
6efe2ad3e3
commit
4b21252ce4
@ -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<BeaconStateStore<T>>,
|
||||
block_store: Arc<BeaconBlockStore<T>>,
|
||||
slot_clock: U,
|
||||
genesis_time: u64,
|
||||
latest_eth1_data: Eth1Data,
|
||||
initial_validator_deposits: Vec<Deposit>,
|
||||
mut genesis_state: BeaconState,
|
||||
genesis_block: BeaconBlock,
|
||||
spec: ChainSpec,
|
||||
fork_choice: F,
|
||||
) -> Result<Self, Error> {
|
||||
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)[..])?;
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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<BeaconState, Error> {
|
||||
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<Deposit>,
|
||||
latest_eth1_data: Eth1Data,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<BeaconState, Error> {
|
||||
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.
|
||||
|
@ -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<BeaconState>,
|
||||
pub genesis_time: u64,
|
||||
pub latest_eth1_data: Eth1Data,
|
||||
pub spec: ChainSpec,
|
||||
pub keypairs: Vec<Keypair>,
|
||||
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::<Vec<usize>>()
|
||||
.iter()
|
||||
.map(|_| Keypair::random())
|
||||
.collect();
|
||||
///
|
||||
/// Spec v0.4.0
|
||||
pub fn build(mut self, spec: &ChainSpec) -> Result<BeaconState, BeaconStateError> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user