Modify genesis processing process.
- Removed BeaconStateBuilder - Added genesis code to `state_processing`.
This commit is contained in:
parent
8677b9e9cc
commit
816c2c651b
@ -19,6 +19,7 @@ slog = "^2.2.3"
|
|||||||
slot_clock = { path = "../eth2/utils/slot_clock" }
|
slot_clock = { path = "../eth2/utils/slot_clock" }
|
||||||
slog-term = "^2.4.0"
|
slog-term = "^2.4.0"
|
||||||
slog-async = "^2.3.0"
|
slog-async = "^2.3.0"
|
||||||
|
state_processing = { path = "../eth2/state_processing" }
|
||||||
types = { path = "../eth2/types" }
|
types = { path = "../eth2/types" }
|
||||||
ssz = { path = "../eth2/utils/ssz" }
|
ssz = { path = "../eth2/utils/ssz" }
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
|
@ -18,10 +18,8 @@ use slog::{error, info, o, Drain};
|
|||||||
use slot_clock::SystemTimeSlotClock;
|
use slot_clock::SystemTimeSlotClock;
|
||||||
use ssz::TreeHash;
|
use ssz::TreeHash;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::test_utils::TestingBeaconStateBuilder;
|
||||||
beacon_state::BeaconStateBuilder, BeaconBlock, ChainSpec, Deposit, DepositData, DepositInput,
|
use types::*;
|
||||||
Eth1Data, Fork, Hash256, Keypair,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let decorator = slog_term::TermDecorator::new().build();
|
let decorator = slog_term::TermDecorator::new().build();
|
||||||
@ -79,61 +77,18 @@ fn main() {
|
|||||||
let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
|
let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
|
||||||
let state_store = Arc::new(BeaconStateStore::new(db.clone()));
|
let state_store = Arc::new(BeaconStateStore::new(db.clone()));
|
||||||
|
|
||||||
|
let state_builder = TestingBeaconStateBuilder::from_deterministic_keypairs(8, &spec);
|
||||||
|
let (genesis_state, _keypairs) = state_builder.build();
|
||||||
|
|
||||||
|
let mut genesis_block = BeaconBlock::empty(&spec);
|
||||||
|
genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root());
|
||||||
|
|
||||||
// Slot clock
|
// Slot clock
|
||||||
let genesis_time = 1_549_935_547; // 12th Feb 2018 (arbitrary value in the past).
|
let slot_clock = SystemTimeSlotClock::new(genesis_state.genesis_time, spec.seconds_per_slot)
|
||||||
let slot_clock = SystemTimeSlotClock::new(genesis_time, spec.seconds_per_slot)
|
|
||||||
.expect("Unable to load SystemTimeSlotClock");
|
.expect("Unable to load SystemTimeSlotClock");
|
||||||
// Choose the fork choice
|
// Choose the fork choice
|
||||||
let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone());
|
let fork_choice = BitwiseLMDGhost::new(block_store.clone(), state_store.clone());
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate some random data to start a chain with.
|
|
||||||
*
|
|
||||||
* This is will need to be replace for production usage.
|
|
||||||
*/
|
|
||||||
let latest_eth1_data = Eth1Data {
|
|
||||||
deposit_root: Hash256::zero(),
|
|
||||||
block_hash: Hash256::zero(),
|
|
||||||
};
|
|
||||||
let keypairs: Vec<Keypair> = (0..10)
|
|
||||||
.collect::<Vec<usize>>()
|
|
||||||
.iter()
|
|
||||||
.map(|_| Keypair::random())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let initial_validator_deposits: Vec<Deposit> = keypairs
|
|
||||||
.iter()
|
|
||||||
.map(|keypair| {
|
|
||||||
let mut deposit_input = DepositInput {
|
|
||||||
pubkey: keypair.pk.clone(),
|
|
||||||
withdrawal_credentials: Hash256::zero(),
|
|
||||||
proof_of_possession: spec.empty_signature.clone(),
|
|
||||||
};
|
|
||||||
deposit_input.proof_of_possession = deposit_input.create_proof_of_possession(
|
|
||||||
&keypair.sk,
|
|
||||||
spec.genesis_epoch,
|
|
||||||
&Fork::genesis(&spec),
|
|
||||||
&spec,
|
|
||||||
);
|
|
||||||
|
|
||||||
Deposit {
|
|
||||||
proof: 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,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
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 mut genesis_block = BeaconBlock::empty(&spec);
|
|
||||||
genesis_block.state_root = Hash256::from_slice(&genesis_state.hash_tree_root());
|
|
||||||
|
|
||||||
// Genesis chain
|
// Genesis chain
|
||||||
let _chain_result = BeaconChain::from_genesis(
|
let _chain_result = BeaconChain::from_genesis(
|
||||||
state_store.clone(),
|
state_store.clone(),
|
||||||
|
59
eth2/state_processing/src/get_genesis_state.rs
Normal file
59
eth2/state_processing/src/get_genesis_state.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use super::per_block_processing::{errors::BlockProcessingError, process_deposits};
|
||||||
|
use ssz::TreeHash;
|
||||||
|
use types::*;
|
||||||
|
|
||||||
|
pub enum GenesisError {
|
||||||
|
BlockProcessingError(BlockProcessingError),
|
||||||
|
BeaconStateError(BeaconStateError),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the genesis `BeaconState`
|
||||||
|
///
|
||||||
|
/// Spec v0.5.0
|
||||||
|
pub fn get_genesis_state(
|
||||||
|
genesis_validator_deposits: &[Deposit],
|
||||||
|
genesis_time: u64,
|
||||||
|
genesis_eth1_data: Eth1Data,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Result<(), BlockProcessingError> {
|
||||||
|
// Get the genesis `BeaconState`
|
||||||
|
let mut state = BeaconState::genesis(genesis_time, genesis_eth1_data, spec);
|
||||||
|
|
||||||
|
// Process genesis deposits.
|
||||||
|
process_deposits(&mut state, genesis_validator_deposits, spec)?;
|
||||||
|
|
||||||
|
// Process genesis activations.
|
||||||
|
for i in 0..state.validator_registry.len() {
|
||||||
|
if state.get_effective_balance(i, spec)? >= spec.max_deposit_amount {
|
||||||
|
state.validator_registry[i].activation_epoch = spec.genesis_epoch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the current epoch cache is built.
|
||||||
|
state.build_epoch_cache(RelativeEpoch::Current, spec)?;
|
||||||
|
|
||||||
|
// Set all the active index roots to be the genesis active index root.
|
||||||
|
let active_validator_indices = state
|
||||||
|
.get_active_validator_indices(spec.genesis_epoch, spec)?
|
||||||
|
.to_vec();
|
||||||
|
let genesis_active_index_root = Hash256::from_slice(&active_validator_indices.hash_tree_root());
|
||||||
|
state.latest_active_index_roots =
|
||||||
|
vec![genesis_active_index_root; spec.latest_active_index_roots_length as usize];
|
||||||
|
|
||||||
|
// Generate the current shuffling seed.
|
||||||
|
state.current_shuffling_seed = state.generate_seed(spec.genesis_epoch, spec)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BlockProcessingError> for GenesisError {
|
||||||
|
fn from(e: BlockProcessingError) -> GenesisError {
|
||||||
|
GenesisError::BlockProcessingError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BeaconStateError> for GenesisError {
|
||||||
|
fn from(e: BeaconStateError) -> GenesisError {
|
||||||
|
GenesisError::BeaconStateError(e)
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
|
pub mod get_genesis_state;
|
||||||
pub mod per_block_processing;
|
pub mod per_block_processing;
|
||||||
pub mod per_epoch_processing;
|
pub mod per_epoch_processing;
|
||||||
pub mod per_slot_processing;
|
pub mod per_slot_processing;
|
||||||
|
|
||||||
|
pub use get_genesis_state::get_genesis_state;
|
||||||
pub use per_block_processing::{
|
pub use per_block_processing::{
|
||||||
errors::{BlockInvalid, BlockProcessingError},
|
errors::{BlockInvalid, BlockProcessingError},
|
||||||
per_block_processing, per_block_processing_without_verifying_block_signature,
|
per_block_processing, per_block_processing_without_verifying_block_signature,
|
||||||
|
@ -45,7 +45,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
|
|||||||
process_rewards_and_penalities(state, &mut statuses, &winning_root_for_shards, spec)?;
|
process_rewards_and_penalities(state, &mut statuses, &winning_root_for_shards, spec)?;
|
||||||
|
|
||||||
// Ejections
|
// Ejections
|
||||||
state.process_ejections(spec);
|
state.process_ejections(spec)?;
|
||||||
|
|
||||||
// Validator Registry
|
// Validator Registry
|
||||||
process_validator_registry(state, spec)?;
|
process_validator_registry(state, spec)?;
|
||||||
@ -53,7 +53,7 @@ pub fn per_epoch_processing(state: &mut BeaconState, spec: &ChainSpec) -> Result
|
|||||||
// Final updates
|
// Final updates
|
||||||
update_active_tree_index_roots(state, spec)?;
|
update_active_tree_index_roots(state, spec)?;
|
||||||
update_latest_slashed_balances(state, spec);
|
update_latest_slashed_balances(state, spec);
|
||||||
clean_attestations(state, spec);
|
clean_attestations(state);
|
||||||
|
|
||||||
// Rotate the epoch caches to suit the epoch transition.
|
// Rotate the epoch caches to suit the epoch transition.
|
||||||
state.advance_caches();
|
state.advance_caches();
|
||||||
@ -472,6 +472,6 @@ pub fn update_latest_slashed_balances(state: &mut BeaconState, spec: &ChainSpec)
|
|||||||
/// Removes all pending attestations from the previous epoch.
|
/// Removes all pending attestations from the previous epoch.
|
||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.4.0
|
||||||
pub fn clean_attestations(state: &mut BeaconState, spec: &ChainSpec) {
|
pub fn clean_attestations(state: &mut BeaconState) {
|
||||||
state.previous_epoch_attestations = vec![];
|
state.previous_epoch_attestations = vec![];
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,6 @@ use ssz_derive::{Decode, Encode, TreeHash};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
|
|
||||||
pub use builder::BeaconStateBuilder;
|
|
||||||
|
|
||||||
mod builder;
|
|
||||||
mod epoch_cache;
|
mod epoch_cache;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
mod pubkey_cache;
|
mod pubkey_cache;
|
||||||
@ -32,7 +29,8 @@ pub enum Error {
|
|||||||
InvalidBitfield,
|
InvalidBitfield,
|
||||||
ValidatorIsWithdrawable,
|
ValidatorIsWithdrawable,
|
||||||
InsufficientRandaoMixes,
|
InsufficientRandaoMixes,
|
||||||
InsufficientValidators,
|
NoValidators,
|
||||||
|
UnableToDetermineProducer,
|
||||||
InsufficientBlockRoots,
|
InsufficientBlockRoots,
|
||||||
InsufficientIndexRoots,
|
InsufficientIndexRoots,
|
||||||
InsufficientAttestations,
|
InsufficientAttestations,
|
||||||
@ -534,7 +532,7 @@ impl BeaconState {
|
|||||||
///
|
///
|
||||||
/// If the state does not contain an index for a beacon proposer at the requested `slot`, then `None` is returned.
|
/// If the state does not contain an index for a beacon proposer at the requested `slot`, then `None` is returned.
|
||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.5.0
|
||||||
pub fn get_beacon_proposer_index(
|
pub fn get_beacon_proposer_index(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
@ -547,14 +545,16 @@ impl BeaconState {
|
|||||||
.get_crosslink_committees_at_slot(slot, spec)
|
.get_crosslink_committees_at_slot(slot, spec)
|
||||||
.ok_or_else(|| Error::SlotOutOfBounds)?;
|
.ok_or_else(|| Error::SlotOutOfBounds)?;
|
||||||
|
|
||||||
|
let epoch = slot.epoch(spec.slots_per_epoch);
|
||||||
|
|
||||||
committees
|
committees
|
||||||
.first()
|
.first()
|
||||||
.ok_or(Error::InsufficientValidators)
|
.ok_or(Error::UnableToDetermineProducer)
|
||||||
.and_then(|first| {
|
.and_then(|first| {
|
||||||
let index = slot
|
let index = epoch
|
||||||
.as_usize()
|
.as_usize()
|
||||||
.checked_rem(first.committee.len())
|
.checked_rem(first.committee.len())
|
||||||
.ok_or(Error::InsufficientValidators)?;
|
.ok_or(Error::UnableToDetermineProducer)?;
|
||||||
Ok(first.committee[index])
|
Ok(first.committee[index])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -581,103 +581,9 @@ impl BeaconState {
|
|||||||
epoch + 1 + spec.activation_exit_delay
|
epoch + 1 + spec.activation_exit_delay
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process multiple deposits in sequence.
|
|
||||||
///
|
|
||||||
/// Builds a hashmap of validator pubkeys to validator index and passes it to each successive
|
|
||||||
/// call to `process_deposit(..)`. This requires much less computation than successive calls to
|
|
||||||
/// `process_deposits(..)` without the hashmap.
|
|
||||||
///
|
|
||||||
/// Spec v0.4.0
|
|
||||||
pub fn process_deposits(
|
|
||||||
&mut self,
|
|
||||||
deposits: Vec<&DepositData>,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) -> Vec<usize> {
|
|
||||||
let mut added_indices = vec![];
|
|
||||||
let mut pubkey_map: HashMap<PublicKey, usize> = HashMap::new();
|
|
||||||
|
|
||||||
for (i, validator) in self.validator_registry.iter().enumerate() {
|
|
||||||
pubkey_map.insert(validator.pubkey.clone(), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for deposit_data in deposits {
|
|
||||||
let result = self.process_deposit(
|
|
||||||
deposit_data.deposit_input.clone(),
|
|
||||||
deposit_data.amount,
|
|
||||||
Some(&pubkey_map),
|
|
||||||
spec,
|
|
||||||
);
|
|
||||||
if let Ok(index) = result {
|
|
||||||
added_indices.push(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
added_indices
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process a validator deposit, returning the validator index if the deposit is valid.
|
|
||||||
///
|
|
||||||
/// Optionally accepts a hashmap of all validator pubkeys to their validator index. Without
|
|
||||||
/// this hashmap, each call to `process_deposits` requires an iteration though
|
|
||||||
/// `self.validator_registry`. This becomes highly inefficient at scale.
|
|
||||||
///
|
|
||||||
/// TODO: this function also exists in a more optimal form in the `state_processing` crate as
|
|
||||||
/// `process_deposits`; unify these two functions.
|
|
||||||
///
|
|
||||||
/// Spec v0.4.0
|
|
||||||
pub fn process_deposit(
|
|
||||||
&mut self,
|
|
||||||
deposit_input: DepositInput,
|
|
||||||
amount: u64,
|
|
||||||
pubkey_map: Option<&HashMap<PublicKey, usize>>,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) -> Result<usize, ()> {
|
|
||||||
let proof_is_valid = deposit_input.proof_of_possession.verify(
|
|
||||||
&deposit_input.signed_root(),
|
|
||||||
spec.get_domain(self.current_epoch(&spec), Domain::Deposit, &self.fork),
|
|
||||||
&deposit_input.pubkey,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !proof_is_valid {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let pubkey = deposit_input.pubkey.clone();
|
|
||||||
let withdrawal_credentials = deposit_input.withdrawal_credentials.clone();
|
|
||||||
|
|
||||||
let validator_index = if let Some(pubkey_map) = pubkey_map {
|
|
||||||
pubkey_map.get(&pubkey).and_then(|i| Some(*i))
|
|
||||||
} else {
|
|
||||||
self.validator_registry
|
|
||||||
.iter()
|
|
||||||
.position(|v| v.pubkey == pubkey)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(index) = validator_index {
|
|
||||||
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,
|
|
||||||
withdrawable_epoch: spec.far_future_epoch,
|
|
||||||
initiated_exit: false,
|
|
||||||
slashed: false,
|
|
||||||
};
|
|
||||||
self.validator_registry.push(validator);
|
|
||||||
self.validator_balances.push(amount);
|
|
||||||
Ok(self.validator_registry.len() - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Activate the validator of the given ``index``.
|
/// Activate the validator of the given ``index``.
|
||||||
///
|
///
|
||||||
/// Spec v0.4.0
|
/// Spec v0.5.0
|
||||||
pub fn activate_validator(
|
pub fn activate_validator(
|
||||||
&mut self,
|
&mut self,
|
||||||
validator_index: usize,
|
validator_index: usize,
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
use super::BeaconStateError;
|
|
||||||
use crate::validator_registry::get_active_validator_indices;
|
|
||||||
use crate::*;
|
|
||||||
use rayon::prelude::*;
|
|
||||||
use ssz::TreeHash;
|
|
||||||
|
|
||||||
/// Builds a `BeaconState` for use in production.
|
|
||||||
///
|
|
||||||
/// This struct should _not_ be modified for use in testing scenarios. Use `TestingBeaconStateBuilder` for that purpose.
|
|
||||||
///
|
|
||||||
/// This struct should remain safe and sensible for production usage.
|
|
||||||
pub struct BeaconStateBuilder {
|
|
||||||
pub state: BeaconState,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BeaconStateBuilder {
|
|
||||||
/// Create a new builder with the given number of validators.
|
|
||||||
///
|
|
||||||
/// Spec v0.4.0
|
|
||||||
pub fn new(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> Self {
|
|
||||||
Self {
|
|
||||||
state: BeaconState::genesis(genesis_time, latest_eth1_data, spec),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process deposit objects.
|
|
||||||
///
|
|
||||||
/// 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);
|
|
||||||
|
|
||||||
self.activate_genesis_validators(spec);
|
|
||||||
|
|
||||||
self.state.deposit_index = initial_validator_deposits.len() as u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate_genesis_validators(&mut self, spec: &ChainSpec) -> Result<(), BeaconStateError> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Instantiate the validator registry from a YAML file.
|
|
||||||
///
|
|
||||||
/// This skips a lot of signing and verification, useful if signing and verification has been
|
|
||||||
/// completed previously.
|
|
||||||
///
|
|
||||||
/// Spec v0.4.0
|
|
||||||
pub fn import_existing_validators(
|
|
||||||
&mut self,
|
|
||||||
validators: Vec<Validator>,
|
|
||||||
initial_balances: Vec<u64>,
|
|
||||||
deposit_index: u64,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) {
|
|
||||||
self.state.validator_registry = validators;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
self.state.validator_registry.len(),
|
|
||||||
initial_balances.len(),
|
|
||||||
"Not enough balances for validators"
|
|
||||||
);
|
|
||||||
|
|
||||||
self.state.validator_balances = initial_balances;
|
|
||||||
|
|
||||||
self.activate_genesis_validators(spec);
|
|
||||||
|
|
||||||
self.state.deposit_index = deposit_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the final state variables and returns a fully built genesis state.
|
|
||||||
///
|
|
||||||
/// 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();
|
|
||||||
|
|
||||||
self.state.latest_active_index_roots = vec![
|
|
||||||
Hash256::from_slice(&genesis_active_index_root);
|
|
||||||
spec.latest_active_index_roots_length
|
|
||||||
];
|
|
||||||
|
|
||||||
self.state.current_shuffling_seed = self.state.generate_seed(spec.genesis_epoch, spec)?;
|
|
||||||
|
|
||||||
Ok(self.state)
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,6 +4,8 @@ use honey_badger_split::SplitExt;
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use swap_or_not_shuffle::shuffle_list;
|
use swap_or_not_shuffle::shuffle_list;
|
||||||
|
|
||||||
|
mod tests;
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
pub struct EpochCache {
|
pub struct EpochCache {
|
||||||
/// `Some(epoch)` if the cache is initialized, where `epoch` is the cache it holds.
|
/// `Some(epoch)` if the cache is initialized, where `epoch` is the cache it holds.
|
||||||
@ -247,7 +249,7 @@ impl EpochCrosslinkCommitteesBuilder {
|
|||||||
|
|
||||||
pub fn build(self, spec: &ChainSpec) -> Result<EpochCrosslinkCommittees, BeaconStateError> {
|
pub fn build(self, spec: &ChainSpec) -> Result<EpochCrosslinkCommittees, BeaconStateError> {
|
||||||
if self.active_validator_indices.is_empty() {
|
if self.active_validator_indices.is_empty() {
|
||||||
return Err(Error::InsufficientValidators);
|
return Err(Error::NoValidators);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shuffled_active_validator_indices = shuffle_list(
|
let shuffled_active_validator_indices = shuffle_list(
|
||||||
@ -277,7 +279,7 @@ impl EpochCrosslinkCommitteesBuilder {
|
|||||||
let crosslink_committee = CrosslinkCommittee {
|
let crosslink_committee = CrosslinkCommittee {
|
||||||
slot,
|
slot,
|
||||||
shard,
|
shard,
|
||||||
committee: committees.remove(j),
|
committee: committees[j].drain(..).collect(),
|
||||||
};
|
};
|
||||||
epoch_crosslink_committees.crosslink_committees[i].push(crosslink_committee);
|
epoch_crosslink_committees.crosslink_committees[i].push(crosslink_committee);
|
||||||
|
|
||||||
|
142
eth2/types/src/beacon_state/epoch_cache/tests.rs
Normal file
142
eth2/types/src/beacon_state/epoch_cache/tests.rs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#![cfg(test)]
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::test_utils::*;
|
||||||
|
use swap_or_not_shuffle::shuffle_list;
|
||||||
|
|
||||||
|
fn do_sane_cache_test(
|
||||||
|
state: BeaconState,
|
||||||
|
epoch: Epoch,
|
||||||
|
validator_count: usize,
|
||||||
|
expected_seed: Hash256,
|
||||||
|
expected_shuffling_start: u64,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) {
|
||||||
|
let active_indices: Vec<usize> = (0..validator_count).collect();
|
||||||
|
assert_eq!(
|
||||||
|
&active_indices[..],
|
||||||
|
state.get_active_validator_indices(epoch, &spec).unwrap(),
|
||||||
|
"Validator indices mismatch"
|
||||||
|
);
|
||||||
|
|
||||||
|
let shuffling = shuffle_list(
|
||||||
|
active_indices,
|
||||||
|
spec.shuffle_round_count,
|
||||||
|
&expected_seed[..],
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let committees_per_epoch = spec.get_epoch_committee_count(shuffling.len());
|
||||||
|
let committees_per_slot = committees_per_epoch / spec.slots_per_epoch;
|
||||||
|
|
||||||
|
let mut expected_indices_iter = shuffling.iter();
|
||||||
|
let mut shard_counter = expected_shuffling_start;
|
||||||
|
|
||||||
|
for (i, slot) in epoch.slot_iter(spec.slots_per_epoch).enumerate() {
|
||||||
|
let crosslink_committees_at_slot =
|
||||||
|
state.get_crosslink_committees_at_slot(slot, &spec).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
crosslink_committees_at_slot.len(),
|
||||||
|
committees_per_slot as usize,
|
||||||
|
"Bad committees per slot ({})",
|
||||||
|
i
|
||||||
|
);
|
||||||
|
|
||||||
|
for c in crosslink_committees_at_slot {
|
||||||
|
assert_eq!(c.shard, shard_counter, "Bad shard");
|
||||||
|
shard_counter += 1;
|
||||||
|
shard_counter %= spec.shard_count;
|
||||||
|
|
||||||
|
for &i in &c.committee {
|
||||||
|
assert_eq!(
|
||||||
|
i,
|
||||||
|
*expected_indices_iter.next().unwrap(),
|
||||||
|
"Non-sequential validators."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_sane_cache_test(validator_count: usize, spec: &ChainSpec) -> BeaconState {
|
||||||
|
let mut builder =
|
||||||
|
TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, spec);
|
||||||
|
|
||||||
|
let epoch = spec.genesis_epoch + 4;
|
||||||
|
let slot = epoch.start_slot(spec.slots_per_epoch);
|
||||||
|
builder.teleport_to_slot(slot, spec);
|
||||||
|
|
||||||
|
let (mut state, _keypairs) = builder.build();
|
||||||
|
|
||||||
|
state.current_shuffling_start_shard = 0;
|
||||||
|
state.current_shuffling_seed = Hash256::from_slice(&[1; 32]);
|
||||||
|
|
||||||
|
state.previous_shuffling_start_shard = spec.shard_count - 1;
|
||||||
|
state.previous_shuffling_seed = Hash256::from_slice(&[2; 32]);
|
||||||
|
|
||||||
|
state
|
||||||
|
.build_epoch_cache(RelativeEpoch::Previous, spec)
|
||||||
|
.unwrap();
|
||||||
|
state
|
||||||
|
.build_epoch_cache(RelativeEpoch::Current, spec)
|
||||||
|
.unwrap();
|
||||||
|
state
|
||||||
|
.build_epoch_cache(RelativeEpoch::NextWithRegistryChange, spec)
|
||||||
|
.unwrap();
|
||||||
|
state
|
||||||
|
.build_epoch_cache(RelativeEpoch::NextWithoutRegistryChange, spec)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builds_sane_current_epoch_cache() {
|
||||||
|
let mut spec = ChainSpec::few_validators();
|
||||||
|
spec.shard_count = 4;
|
||||||
|
let validator_count = (spec.shard_count * spec.target_committee_size) + 1;
|
||||||
|
let state = setup_sane_cache_test(validator_count as usize, &spec);
|
||||||
|
do_sane_cache_test(
|
||||||
|
state.clone(),
|
||||||
|
state.current_epoch(&spec),
|
||||||
|
validator_count as usize,
|
||||||
|
state.current_shuffling_seed,
|
||||||
|
state.current_shuffling_start_shard,
|
||||||
|
&spec,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builds_sane_previous_epoch_cache() {
|
||||||
|
let mut spec = ChainSpec::few_validators();
|
||||||
|
spec.shard_count = 2;
|
||||||
|
let validator_count = (spec.shard_count * spec.target_committee_size) + 1;
|
||||||
|
let state = setup_sane_cache_test(validator_count as usize, &spec);
|
||||||
|
do_sane_cache_test(
|
||||||
|
state.clone(),
|
||||||
|
state.previous_epoch(&spec),
|
||||||
|
validator_count as usize,
|
||||||
|
state.previous_shuffling_seed,
|
||||||
|
state.previous_shuffling_start_shard,
|
||||||
|
&spec,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builds_sane_next_without_update_epoch_cache() {
|
||||||
|
let mut spec = ChainSpec::few_validators();
|
||||||
|
spec.shard_count = 2;
|
||||||
|
let validator_count = (spec.shard_count * spec.target_committee_size) + 1;
|
||||||
|
let mut state = setup_sane_cache_test(validator_count as usize, &spec);
|
||||||
|
state.validator_registry_update_epoch = state.slot.epoch(spec.slots_per_epoch);
|
||||||
|
do_sane_cache_test(
|
||||||
|
state.clone(),
|
||||||
|
state.next_epoch(&spec),
|
||||||
|
validator_count as usize,
|
||||||
|
state.current_shuffling_seed,
|
||||||
|
state.current_shuffling_start_shard,
|
||||||
|
&spec,
|
||||||
|
);
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
use super::{generate_deterministic_keypairs, KeypairsFile};
|
use super::{generate_deterministic_keypairs, KeypairsFile};
|
||||||
use crate::beacon_state::BeaconStateBuilder;
|
|
||||||
use crate::test_utils::TestingPendingAttestationBuilder;
|
use crate::test_utils::TestingPendingAttestationBuilder;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use bls::get_withdrawal_credentials;
|
use bls::get_withdrawal_credentials;
|
||||||
@ -110,7 +109,8 @@ impl TestingBeaconStateBuilder {
|
|||||||
Validator {
|
Validator {
|
||||||
pubkey: keypair.pk.clone(),
|
pubkey: keypair.pk.clone(),
|
||||||
withdrawal_credentials,
|
withdrawal_credentials,
|
||||||
activation_epoch: spec.far_future_epoch,
|
// All validators start active.
|
||||||
|
activation_epoch: spec.genesis_epoch,
|
||||||
exit_epoch: spec.far_future_epoch,
|
exit_epoch: spec.far_future_epoch,
|
||||||
withdrawable_epoch: spec.far_future_epoch,
|
withdrawable_epoch: spec.far_future_epoch,
|
||||||
initiated_exit: false,
|
initiated_exit: false,
|
||||||
@ -119,7 +119,7 @@ impl TestingBeaconStateBuilder {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut state_builder = BeaconStateBuilder::new(
|
let mut state = BeaconState::genesis(
|
||||||
0,
|
0,
|
||||||
Eth1Data {
|
Eth1Data {
|
||||||
deposit_root: Hash256::zero(),
|
deposit_root: Hash256::zero(),
|
||||||
@ -131,14 +131,8 @@ impl TestingBeaconStateBuilder {
|
|||||||
let balances = vec![32_000_000_000; validator_count];
|
let balances = vec![32_000_000_000; validator_count];
|
||||||
|
|
||||||
debug!("Importing {} existing validators...", validator_count);
|
debug!("Importing {} existing validators...", validator_count);
|
||||||
state_builder.import_existing_validators(
|
state.validator_registry = validators;
|
||||||
validators,
|
state.validator_balances = balances;
|
||||||
balances,
|
|
||||||
validator_count as u64,
|
|
||||||
spec,
|
|
||||||
);
|
|
||||||
|
|
||||||
let state = state_builder.build(spec).unwrap();
|
|
||||||
|
|
||||||
debug!("BeaconState built.");
|
debug!("BeaconState built.");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user