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,
|
F: ForkChoice,
|
||||||
{
|
{
|
||||||
/// Instantiate a new Beacon Chain, from genesis.
|
/// Instantiate a new Beacon Chain, from genesis.
|
||||||
#[allow(clippy::too_many_arguments)] // Will be re-factored in the coming weeks.
|
pub fn from_genesis(
|
||||||
pub fn 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,
|
||||||
genesis_time: u64,
|
mut genesis_state: BeaconState,
|
||||||
latest_eth1_data: Eth1Data,
|
genesis_block: BeaconBlock,
|
||||||
initial_validator_deposits: Vec<Deposit>,
|
|
||||||
spec: ChainSpec,
|
spec: ChainSpec,
|
||||||
fork_choice: F,
|
fork_choice: F,
|
||||||
) -> Result<Self, Error> {
|
) -> 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();
|
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)[..])?;
|
||||||
|
|
||||||
let genesis_block = BeaconBlock::genesis(state_root, &spec);
|
|
||||||
let block_root = genesis_block.canonical_root();
|
let block_root = genesis_block.canonical_root();
|
||||||
block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?;
|
block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?;
|
||||||
|
|
||||||
|
@ -9,11 +9,12 @@ use fork_choice::BitwiseLMDGhost;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use slot_clock::TestingSlotClock;
|
use slot_clock::TestingSlotClock;
|
||||||
|
use ssz::TreeHash;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::*;
|
use types::{beacon_state::BeaconStateBuilder, *};
|
||||||
|
|
||||||
mod generate_deposits;
|
mod generate_deposits;
|
||||||
mod load_deposits_from_file;
|
mod load_deposits_from_file;
|
||||||
@ -67,15 +68,20 @@ impl BeaconChainHarness {
|
|||||||
(keypairs, deposits)
|
(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
|
// Create the Beacon Chain
|
||||||
let beacon_chain = Arc::new(
|
let beacon_chain = Arc::new(
|
||||||
BeaconChain::genesis(
|
BeaconChain::from_genesis(
|
||||||
state_store.clone(),
|
state_store.clone(),
|
||||||
block_store.clone(),
|
block_store.clone(),
|
||||||
slot_clock,
|
slot_clock,
|
||||||
genesis_time,
|
genesis_state,
|
||||||
latest_eth1_data,
|
genesis_block,
|
||||||
initial_validator_deposits,
|
|
||||||
spec.clone(),
|
spec.clone(),
|
||||||
fork_choice,
|
fork_choice,
|
||||||
)
|
)
|
||||||
|
@ -114,18 +114,13 @@ pub struct BeaconState {
|
|||||||
|
|
||||||
impl BeaconState {
|
impl BeaconState {
|
||||||
/// Produce the first state of the Beacon Chain.
|
/// Produce the first state of the Beacon Chain.
|
||||||
pub fn genesis_without_validators(
|
pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState {
|
||||||
genesis_time: u64,
|
|
||||||
latest_eth1_data: Eth1Data,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) -> Result<BeaconState, Error> {
|
|
||||||
debug!("Creating genesis state (without validator processing).");
|
|
||||||
let initial_crosslink = Crosslink {
|
let initial_crosslink = Crosslink {
|
||||||
epoch: spec.genesis_epoch,
|
epoch: spec.genesis_epoch,
|
||||||
crosslink_data_root: spec.zero_hash,
|
crosslink_data_root: spec.zero_hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BeaconState {
|
BeaconState {
|
||||||
/*
|
/*
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
@ -188,19 +183,15 @@ impl BeaconState {
|
|||||||
*/
|
*/
|
||||||
cache_index_offset: 0,
|
cache_index_offset: 0,
|
||||||
caches: vec![EpochCache::empty(); CACHED_EPOCHS],
|
caches: vec![EpochCache::empty(); CACHED_EPOCHS],
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produce the first state of the Beacon Chain.
|
/// Produce the first state of the Beacon Chain.
|
||||||
pub fn genesis(
|
pub fn process_initial_deposits(
|
||||||
genesis_time: u64,
|
&mut self,
|
||||||
initial_validator_deposits: Vec<Deposit>,
|
initial_validator_deposits: Vec<Deposit>,
|
||||||
latest_eth1_data: Eth1Data,
|
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<BeaconState, Error> {
|
) -> Result<(), Error> {
|
||||||
let mut genesis_state =
|
|
||||||
BeaconState::genesis_without_validators(genesis_time, latest_eth1_data, spec)?;
|
|
||||||
|
|
||||||
debug!("Processing genesis deposits...");
|
debug!("Processing genesis deposits...");
|
||||||
|
|
||||||
let deposit_data = initial_validator_deposits
|
let deposit_data = initial_validator_deposits
|
||||||
@ -208,29 +199,28 @@ impl BeaconState {
|
|||||||
.map(|deposit| &deposit.deposit_data)
|
.map(|deposit| &deposit.deposit_data)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
genesis_state.process_deposits(deposit_data, spec);
|
self.process_deposits(deposit_data, spec);
|
||||||
|
|
||||||
trace!("Processed genesis deposits.");
|
trace!("Processed genesis deposits.");
|
||||||
|
|
||||||
for validator_index in 0..genesis_state.validator_registry.len() {
|
for validator_index in 0..self.validator_registry.len() {
|
||||||
if genesis_state.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount
|
if self.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount {
|
||||||
{
|
self.activate_validator(validator_index, true, spec);
|
||||||
genesis_state.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(
|
let genesis_active_index_root = hash_tree_root(get_active_validator_indices(
|
||||||
&genesis_state.validator_registry,
|
&self.validator_registry,
|
||||||
spec.genesis_epoch,
|
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];
|
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.
|
/// Returns the `hash_tree_root` of the state.
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
|
use super::BeaconStateError;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use crate::{validator_registry::get_active_validator_indices, *};
|
||||||
use bls::create_proof_of_possession;
|
use bls::create_proof_of_possession;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use ssz::TreeHash;
|
||||||
|
|
||||||
/// Builds a `BeaconState` for use in testing or benchmarking.
|
/// 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
|
/// Step (4) produces a clone of the BeaconState and doesn't consume the `BeaconStateBuilder` to
|
||||||
/// allow access to `self.keypairs` and `self.spec`.
|
/// allow access to `self.keypairs` and `self.spec`.
|
||||||
pub struct BeaconStateBuilder {
|
pub struct BeaconStateBuilder {
|
||||||
pub validator_count: usize,
|
pub state: BeaconState,
|
||||||
pub state: Option<BeaconState>,
|
|
||||||
pub genesis_time: u64,
|
|
||||||
pub latest_eth1_data: Eth1Data,
|
|
||||||
pub spec: ChainSpec,
|
|
||||||
pub keypairs: Vec<Keypair>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeaconStateBuilder {
|
impl BeaconStateBuilder {
|
||||||
/// Create a new builder with the given number of validators.
|
/// Create a new builder with the given number of validators.
|
||||||
pub fn new(validator_count: usize) -> Self {
|
///
|
||||||
let genesis_time = 10_000_000;
|
/// Spec v0.4.0
|
||||||
|
pub fn new(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> Self {
|
||||||
let latest_eth1_data = Eth1Data {
|
|
||||||
deposit_root: Hash256::zero(),
|
|
||||||
block_hash: Hash256::zero(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let spec = ChainSpec::foundation();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
validator_count,
|
state: BeaconState::genesis(genesis_time, latest_eth1_data, spec),
|
||||||
state: None,
|
|
||||||
genesis_time,
|
|
||||||
latest_eth1_data,
|
|
||||||
spec,
|
|
||||||
keypairs: vec![],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Builds a `BeaconState` using the `BeaconState::genesis(..)` function.
|
||||||
///
|
///
|
||||||
/// Each validator is assigned a unique, randomly-generated keypair and all
|
/// Each validator is assigned a unique, randomly-generated keypair and all
|
||||||
/// proof-of-possessions are verified during genesis.
|
/// 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();
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
let state = BeaconState::genesis(
|
|
||||||
self.genesis_time,
|
|
||||||
initial_validator_deposits,
|
|
||||||
self.latest_eth1_data.clone(),
|
|
||||||
&self.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.
|
/// Spec v0.4.0
|
||||||
/// Proof-of-possessions are not created (or validated).
|
pub fn build(mut self, spec: &ChainSpec) -> Result<BeaconState, BeaconStateError> {
|
||||||
///
|
let genesis_active_index_root =
|
||||||
/// This function runs orders of magnitude faster than `Self::build()`, however it will be
|
get_active_validator_indices(&self.state.validator_registry, spec.genesis_epoch)
|
||||||
/// erroneous for functions which use a validators public key as an identifier (e.g.,
|
.hash_tree_root();
|
||||||
/// deposits).
|
|
||||||
pub fn build_fast(&mut self) -> Result<(), BeaconStateError> {
|
|
||||||
let common_keypair = Keypair::random();
|
|
||||||
|
|
||||||
let mut validator_registry = Vec::with_capacity(self.validator_count);
|
self.state.latest_active_index_roots = vec![
|
||||||
let mut validator_balances = Vec::with_capacity(self.validator_count);
|
Hash256::from_slice(&genesis_active_index_root);
|
||||||
self.keypairs = Vec::with_capacity(self.validator_count);
|
spec.latest_active_index_roots_length
|
||||||
|
];
|
||||||
|
|
||||||
for _ in 0..self.validator_count {
|
self.state.current_shuffling_seed = self.state.generate_seed(spec.genesis_epoch, spec)?;
|
||||||
self.keypairs.push(common_keypair.clone());
|
|
||||||
validator_balances.push(32_000_000_000);
|
Ok(self.state)
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Sets the `BeaconState` to be in the last slot of the given epoch.
|
/// 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.,
|
/// Sets all justification/finalization parameters to be be as "perfect" as possible (i.e.,
|
||||||
/// highest justified and finalized slots, full justification bitfield, etc).
|
/// highest justified and finalized slots, full justification bitfield, etc).
|
||||||
pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch) {
|
pub fn teleport_to_end_of_epoch(&mut self, epoch: Epoch, spec: &ChainSpec) {
|
||||||
let state = self.state.as_mut().expect("Genesis required");
|
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.slot = slot;
|
||||||
state.validator_registry_update_epoch = epoch - 1;
|
state.validator_registry_update_epoch = epoch - 1;
|
||||||
@ -159,7 +108,7 @@ impl BeaconStateBuilder {
|
|||||||
///
|
///
|
||||||
/// These attestations should be fully conducive to justification and finalization.
|
/// These attestations should be fully conducive to justification and finalization.
|
||||||
pub fn insert_attestations(&mut self) {
|
pub fn insert_attestations(&mut self) {
|
||||||
let state = self.state.as_mut().expect("Genesis required");
|
let state = &mut self.state;
|
||||||
|
|
||||||
state
|
state
|
||||||
.build_epoch_cache(RelativeEpoch::Previous, &self.spec)
|
.build_epoch_cache(RelativeEpoch::Previous, &self.spec)
|
||||||
@ -198,8 +147,10 @@ impl BeaconStateBuilder {
|
|||||||
pub fn cloned_state(&self) -> BeaconState {
|
pub fn cloned_state(&self) -> BeaconState {
|
||||||
self.state.as_ref().expect("Genesis required").clone()
|
self.state.as_ref().expect("Genesis required").clone()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Builds a valid PendingAttestation with full participation for some committee.
|
/// Builds a valid PendingAttestation with full participation for some committee.
|
||||||
fn committee_to_pending_attestation(
|
fn committee_to_pending_attestation(
|
||||||
state: &BeaconState,
|
state: &BeaconState,
|
||||||
@ -261,3 +212,4 @@ fn committee_to_pending_attestation(
|
|||||||
inclusion_slot: slot,
|
inclusion_slot: slot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user