Merge branch 'master' into validator-record-update
This commit is contained in:
commit
f48eb568ba
@ -35,6 +35,7 @@ name = "lighthouse"
|
|||||||
members = [
|
members = [
|
||||||
"beacon_chain/attestation_validation",
|
"beacon_chain/attestation_validation",
|
||||||
"beacon_chain/chain",
|
"beacon_chain/chain",
|
||||||
|
"beacon_chain/genesis",
|
||||||
"beacon_chain/naive_fork_choice",
|
"beacon_chain/naive_fork_choice",
|
||||||
"beacon_chain/spec",
|
"beacon_chain/spec",
|
||||||
"beacon_chain/types",
|
"beacon_chain/types",
|
||||||
|
@ -12,8 +12,9 @@ use super::{Error, Invalid, Outcome};
|
|||||||
pub fn validate_attestation_justified_slot(
|
pub fn validate_attestation_justified_slot(
|
||||||
data: &AttestationData,
|
data: &AttestationData,
|
||||||
state: &BeaconState,
|
state: &BeaconState,
|
||||||
|
epoch_length: u64,
|
||||||
) -> Result<Outcome, Error> {
|
) -> Result<Outcome, Error> {
|
||||||
let permissable_justified_slot = if data.slot >= state.latest_state_recalculation_slot {
|
let permissable_justified_slot = if data.slot >= state.slot - (state.slot % epoch_length) {
|
||||||
state.justified_slot
|
state.justified_slot
|
||||||
} else {
|
} else {
|
||||||
state.previous_justified_slot
|
state.previous_justified_slot
|
||||||
|
@ -19,7 +19,7 @@ where
|
|||||||
match state.latest_crosslinks.get(data.shard as usize) {
|
match state.latest_crosslinks.get(data.shard as usize) {
|
||||||
None => reject!(Invalid::UnknownShard),
|
None => reject!(Invalid::UnknownShard),
|
||||||
Some(crosslink) => {
|
Some(crosslink) => {
|
||||||
let local_shard_block_hash = crosslink.shard_block_hash;
|
let local_shard_block_hash = crosslink.shard_block_root;
|
||||||
let shard_block_hash_is_permissable = {
|
let shard_block_hash_is_permissable = {
|
||||||
(local_shard_block_hash == data.latest_crosslink_hash)
|
(local_shard_block_hash == data.latest_crosslink_hash)
|
||||||
|| (local_shard_block_hash == data.shard_block_hash)
|
|| (local_shard_block_hash == data.shard_block_hash)
|
||||||
|
@ -7,7 +7,9 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bls = { path = "../utils/bls" }
|
bls = { path = "../utils/bls" }
|
||||||
db = { path = "../../lighthouse/db" }
|
db = { path = "../../lighthouse/db" }
|
||||||
|
genesis = { path = "../genesis" }
|
||||||
naive_fork_choice = { path = "../naive_fork_choice" }
|
naive_fork_choice = { path = "../naive_fork_choice" }
|
||||||
|
spec = { path = "../spec" }
|
||||||
ssz = { path = "../utils/ssz" }
|
ssz = { path = "../utils/ssz" }
|
||||||
types = { path = "../types" }
|
types = { path = "../types" }
|
||||||
validator_induction = { path = "../validator_induction" }
|
validator_induction = { path = "../validator_induction" }
|
||||||
|
@ -1,157 +0,0 @@
|
|||||||
use super::{ActiveState, ChainConfig, CrystallizedState};
|
|
||||||
use types::ValidatorStatus;
|
|
||||||
use validator_shuffling::{shard_and_committees_for_cycle, ValidatorAssignmentError};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
ValidationAssignmentError(ValidatorAssignmentError),
|
|
||||||
NotImplemented,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ValidatorAssignmentError> for Error {
|
|
||||||
fn from(e: ValidatorAssignmentError) -> Error {
|
|
||||||
Error::ValidationAssignmentError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a new ChainHead with genesis parameters.
|
|
||||||
///
|
|
||||||
/// Used when syncing a chain from scratch.
|
|
||||||
pub fn genesis_states(config: &ChainConfig) -> Result<(ActiveState, CrystallizedState), Error> {
|
|
||||||
/*
|
|
||||||
* Parse the ValidatorRegistrations into ValidatorRecords and induct them.
|
|
||||||
*
|
|
||||||
* Ignore any records which fail proof-of-possession or are invalid.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
TODO: refactor this
|
|
||||||
let validators = {
|
|
||||||
let mut inductor = ValidatorInductor::new(0, config.shard_count, vec![]);
|
|
||||||
for registration in &config.initial_validators {
|
|
||||||
let _ = inductor.induct(®istration, ValidatorStatus::Active);
|
|
||||||
}
|
|
||||||
inductor.to_vec()
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
let validators = vec![];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Assign the validators to shards, using all zeros as the seed.
|
|
||||||
*
|
|
||||||
* Crystallizedstate stores two cycles, so we simply repeat the same assignment twice.
|
|
||||||
*/
|
|
||||||
let _shard_and_committee_for_slots = {
|
|
||||||
let mut a = shard_and_committees_for_cycle(&vec![0; 32], &validators, 0, &config)?;
|
|
||||||
let mut b = a.clone();
|
|
||||||
a.append(&mut b);
|
|
||||||
a
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: implement genesis for `BeaconState`
|
|
||||||
// https://github.com/sigp/lighthouse/issues/99
|
|
||||||
|
|
||||||
Err(Error::NotImplemented)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
extern crate bls;
|
|
||||||
extern crate validator_induction;
|
|
||||||
|
|
||||||
// TODO: implement genesis for `BeaconState`
|
|
||||||
// https://github.com/sigp/lighthouse/issues/99
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
use self::bls::{create_proof_of_possession, Keypair};
|
|
||||||
use super::*;
|
|
||||||
use types::{Address, Hash256, ValidatorRegistration};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_genesis_no_validators() {
|
|
||||||
let config = ChainConfig::standard();
|
|
||||||
let (act, cry) = genesis_states(&config).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(cry.validator_set_change_slot, 0);
|
|
||||||
assert_eq!(cry.validators.len(), 0);
|
|
||||||
assert_eq!(cry.crosslinks.len(), config.shard_count as usize);
|
|
||||||
for cl in cry.crosslinks {
|
|
||||||
assert_eq!(cl.recently_changed, false);
|
|
||||||
assert_eq!(cl.slot, 0);
|
|
||||||
assert_eq!(cl.hash, Hash256::zero());
|
|
||||||
}
|
|
||||||
assert_eq!(cry.last_state_recalculation_slot, 0);
|
|
||||||
assert_eq!(cry.last_finalized_slot, 0);
|
|
||||||
assert_eq!(cry.last_justified_slot, 0);
|
|
||||||
assert_eq!(cry.justified_streak, 0);
|
|
||||||
assert_eq!(
|
|
||||||
cry.shard_and_committee_for_slots.len(),
|
|
||||||
(config.cycle_length as usize) * 2
|
|
||||||
);
|
|
||||||
assert_eq!(cry.deposits_penalized_in_period.len(), 0);
|
|
||||||
assert_eq!(cry.validator_set_delta_hash_chain, Hash256::zero());
|
|
||||||
assert_eq!(cry.pre_fork_version, INITIAL_FORK_VERSION);
|
|
||||||
assert_eq!(cry.post_fork_version, INITIAL_FORK_VERSION);
|
|
||||||
assert_eq!(cry.fork_slot_number, 0);
|
|
||||||
|
|
||||||
assert_eq!(act.pending_attestations.len(), 0);
|
|
||||||
assert_eq!(act.pending_specials.len(), 0);
|
|
||||||
assert_eq!(
|
|
||||||
act.recent_block_hashes,
|
|
||||||
vec![Hash256::zero(); config.cycle_length as usize]
|
|
||||||
);
|
|
||||||
assert_eq!(act.randao_mix, Hash256::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn random_registration() -> ValidatorRegistration {
|
|
||||||
let keypair = Keypair::random();
|
|
||||||
ValidatorRegistration {
|
|
||||||
pubkey: keypair.pk.clone(),
|
|
||||||
withdrawal_shard: 0,
|
|
||||||
withdrawal_address: Address::random(),
|
|
||||||
randao_commitment: Hash256::random(),
|
|
||||||
proof_of_possession: create_proof_of_possession(&keypair),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_genesis_valid_validators() {
|
|
||||||
let mut config = ChainConfig::standard();
|
|
||||||
let validator_count = 5;
|
|
||||||
|
|
||||||
for _ in 0..validator_count {
|
|
||||||
config.initial_validators.push(random_registration());
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_, cry) = genesis_states(&config).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(cry.validators.len(), validator_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_genesis_invalid_validators() {
|
|
||||||
let mut config = ChainConfig::standard();
|
|
||||||
let good_validator_count = 5;
|
|
||||||
|
|
||||||
for _ in 0..good_validator_count {
|
|
||||||
config.initial_validators.push(random_registration());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut bad_v = random_registration();
|
|
||||||
let bad_kp = Keypair::random();
|
|
||||||
bad_v.proof_of_possession = create_proof_of_possession(&bad_kp);
|
|
||||||
config.initial_validators.push(bad_v);
|
|
||||||
|
|
||||||
let mut bad_v = random_registration();
|
|
||||||
bad_v.withdrawal_shard = config.shard_count + 1;
|
|
||||||
config.initial_validators.push(bad_v);
|
|
||||||
|
|
||||||
let (_, cry) = genesis_states(&config).unwrap();
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
config.initial_validators.len() != good_validator_count,
|
|
||||||
"test is invalid"
|
|
||||||
);
|
|
||||||
assert_eq!(cry.validators.len(), good_validator_count);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,22 +1,24 @@
|
|||||||
extern crate db;
|
extern crate db;
|
||||||
extern crate naive_fork_choice;
|
extern crate naive_fork_choice;
|
||||||
|
extern crate genesis;
|
||||||
|
extern crate spec;
|
||||||
extern crate ssz;
|
extern crate ssz;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
extern crate validator_induction;
|
extern crate validator_induction;
|
||||||
extern crate validator_shuffling;
|
extern crate validator_shuffling;
|
||||||
|
|
||||||
mod block_processing;
|
mod block_processing;
|
||||||
mod genesis;
|
|
||||||
mod maps;
|
mod maps;
|
||||||
mod stores;
|
mod stores;
|
||||||
|
|
||||||
use db::ClientDB;
|
use db::ClientDB;
|
||||||
use crate::genesis::{genesis_states, Error as GenesisError};
|
|
||||||
use crate::maps::{generate_attester_and_proposer_maps, AttesterAndProposerMapError};
|
use crate::maps::{generate_attester_and_proposer_maps, AttesterAndProposerMapError};
|
||||||
|
use crate::stores::BeaconChainStore;
|
||||||
|
use genesis::{genesis_beacon_state, GenesisError};
|
||||||
|
use spec::ChainSpec;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::stores::BeaconChainStore;
|
use types::{AttesterMap, BeaconState, Hash256, ProposerMap};
|
||||||
use types::{ActiveState, AttesterMap, ChainConfig, CrystallizedState, Hash256, ProposerMap};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum BeaconChainError {
|
pub enum BeaconChainError {
|
||||||
@ -34,43 +36,46 @@ pub struct BeaconChain<T: ClientDB + Sized> {
|
|||||||
pub head_block_hashes: Vec<Hash256>,
|
pub head_block_hashes: Vec<Hash256>,
|
||||||
/// The index of the canonical block in `head_block_hashes`.
|
/// The index of the canonical block in `head_block_hashes`.
|
||||||
pub canonical_head_block_hash: usize,
|
pub canonical_head_block_hash: usize,
|
||||||
/// A map where the value is an active state the the key is its hash.
|
/// An in-memory map of root hash to beacon state.
|
||||||
pub active_states: HashMap<Hash256, ActiveState>,
|
pub beacon_states: HashMap<Hash256, BeaconState>,
|
||||||
/// A map where the value is crystallized state the the key is its hash.
|
|
||||||
pub crystallized_states: HashMap<Hash256, CrystallizedState>,
|
|
||||||
/// A map of crystallized state to a proposer and attester map.
|
/// A map of crystallized state to a proposer and attester map.
|
||||||
pub attester_proposer_maps: HashMap<Hash256, (Arc<AttesterMap>, Arc<ProposerMap>)>,
|
pub attester_proposer_maps: HashMap<Hash256, (Arc<AttesterMap>, Arc<ProposerMap>)>,
|
||||||
/// A collection of database stores used by the chain.
|
/// A collection of database stores used by the chain.
|
||||||
pub store: BeaconChainStore<T>,
|
pub store: BeaconChainStore<T>,
|
||||||
/// The chain configuration.
|
/// The chain configuration.
|
||||||
pub config: ChainConfig,
|
pub spec: ChainSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> BeaconChain<T>
|
impl<T> BeaconChain<T>
|
||||||
where
|
where
|
||||||
T: ClientDB + Sized,
|
T: ClientDB + Sized,
|
||||||
{
|
{
|
||||||
pub fn new(store: BeaconChainStore<T>, config: ChainConfig) -> Result<Self, BeaconChainError> {
|
pub fn new(store: BeaconChainStore<T>, spec: ChainSpec) -> Result<Self, BeaconChainError> {
|
||||||
if config.initial_validators.is_empty() {
|
if spec.initial_validators.is_empty() {
|
||||||
return Err(BeaconChainError::InsufficientValidators);
|
return Err(BeaconChainError::InsufficientValidators);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (active_state, crystallized_state) = genesis_states(&config)?;
|
/*
|
||||||
|
* Generate and process the genesis state.
|
||||||
|
*/
|
||||||
|
let genesis_state = genesis_beacon_state(&spec)?;
|
||||||
|
let mut beacon_states = HashMap::new();
|
||||||
|
beacon_states.insert(genesis_state.canonical_root(), genesis_state.clone());
|
||||||
|
|
||||||
|
// TODO: implement genesis block
|
||||||
|
// https://github.com/sigp/lighthouse/issues/105
|
||||||
let canonical_latest_block_hash = Hash256::zero();
|
let canonical_latest_block_hash = Hash256::zero();
|
||||||
|
|
||||||
let head_block_hashes = vec![canonical_latest_block_hash];
|
let head_block_hashes = vec![canonical_latest_block_hash];
|
||||||
let canonical_head_block_hash = 0;
|
let canonical_head_block_hash = 0;
|
||||||
let mut active_states = HashMap::new();
|
|
||||||
let mut crystallized_states = HashMap::new();
|
|
||||||
let mut attester_proposer_maps = HashMap::new();
|
let mut attester_proposer_maps = HashMap::new();
|
||||||
|
|
||||||
let (attester_map, proposer_map) = generate_attester_and_proposer_maps(
|
let (attester_map, proposer_map) = generate_attester_and_proposer_maps(
|
||||||
&crystallized_state.shard_and_committee_for_slots,
|
&genesis_state.shard_committees_at_slots,
|
||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
active_states.insert(canonical_latest_block_hash, active_state);
|
|
||||||
crystallized_states.insert(canonical_latest_block_hash, crystallized_state);
|
|
||||||
attester_proposer_maps.insert(
|
attester_proposer_maps.insert(
|
||||||
canonical_latest_block_hash,
|
canonical_latest_block_hash,
|
||||||
(Arc::new(attester_map), Arc::new(proposer_map)),
|
(Arc::new(attester_map), Arc::new(proposer_map)),
|
||||||
@ -80,11 +85,10 @@ where
|
|||||||
last_finalized_slot: 0,
|
last_finalized_slot: 0,
|
||||||
head_block_hashes,
|
head_block_hashes,
|
||||||
canonical_head_block_hash,
|
canonical_head_block_hash,
|
||||||
active_states,
|
beacon_states,
|
||||||
crystallized_states,
|
|
||||||
attester_proposer_maps,
|
attester_proposer_maps,
|
||||||
store,
|
store,
|
||||||
config,
|
spec,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use types::{AttesterMap, ProposerMap, ShardAndCommittee};
|
use types::{AttesterMap, ProposerMap, ShardCommittee};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum AttesterAndProposerMapError {
|
pub enum AttesterAndProposerMapError {
|
||||||
NoShardAndCommitteeForSlot,
|
NoShardCommitteeForSlot,
|
||||||
NoAvailableProposer,
|
NoAvailableProposer,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ pub enum AttesterAndProposerMapError {
|
|||||||
///
|
///
|
||||||
/// The attester map is used to optimise the lookup of a committee.
|
/// The attester map is used to optimise the lookup of a committee.
|
||||||
pub fn generate_attester_and_proposer_maps(
|
pub fn generate_attester_and_proposer_maps(
|
||||||
shard_and_committee_for_slots: &Vec<Vec<ShardAndCommittee>>,
|
shard_and_committee_for_slots: &Vec<Vec<ShardCommittee>>,
|
||||||
start_slot: u64,
|
start_slot: u64,
|
||||||
) -> Result<(AttesterMap, ProposerMap), AttesterAndProposerMapError> {
|
) -> Result<(AttesterMap, ProposerMap), AttesterAndProposerMapError> {
|
||||||
let mut attester_map = AttesterMap::new();
|
let mut attester_map = AttesterMap::new();
|
||||||
@ -22,7 +22,7 @@ pub fn generate_attester_and_proposer_maps(
|
|||||||
let slot_number = (i as u64).saturating_add(start_slot);
|
let slot_number = (i as u64).saturating_add(start_slot);
|
||||||
let first_committee = &slot
|
let first_committee = &slot
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or(AttesterAndProposerMapError::NoShardAndCommitteeForSlot)?
|
.ok_or(AttesterAndProposerMapError::NoShardCommitteeForSlot)?
|
||||||
.committee;
|
.committee;
|
||||||
let proposer_index = (slot_number as usize)
|
let proposer_index = (slot_number as usize)
|
||||||
.checked_rem(first_committee.len())
|
.checked_rem(first_committee.len())
|
||||||
@ -49,15 +49,15 @@ mod tests {
|
|||||||
slot_count: usize,
|
slot_count: usize,
|
||||||
sac_per_slot: usize,
|
sac_per_slot: usize,
|
||||||
committee_size: usize,
|
committee_size: usize,
|
||||||
) -> Vec<Vec<ShardAndCommittee>> {
|
) -> Vec<Vec<ShardCommittee>> {
|
||||||
let mut shard = 0;
|
let mut shard = 0;
|
||||||
let mut validator = 0;
|
let mut validator = 0;
|
||||||
let mut cycle = vec![];
|
let mut cycle = vec![];
|
||||||
|
|
||||||
for _ in 0..slot_count {
|
for _ in 0..slot_count {
|
||||||
let mut slot: Vec<ShardAndCommittee> = vec![];
|
let mut slot: Vec<ShardCommittee> = vec![];
|
||||||
for _ in 0..sac_per_slot {
|
for _ in 0..sac_per_slot {
|
||||||
let mut sac = ShardAndCommittee {
|
let mut sac = ShardCommittee {
|
||||||
shard: shard % shard_count,
|
shard: shard % shard_count,
|
||||||
committee: vec![],
|
committee: vec![],
|
||||||
};
|
};
|
||||||
@ -79,7 +79,7 @@ mod tests {
|
|||||||
let result = generate_attester_and_proposer_maps(&sac, 0);
|
let result = generate_attester_and_proposer_maps(&sac, 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
Err(AttesterAndProposerMapError::NoShardAndCommitteeForSlot)
|
Err(AttesterAndProposerMapError::NoShardCommitteeForSlot)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
beacon_chain/chain/src/transition.rs
Normal file
29
beacon_chain/chain/src/transition.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use super::BeaconChain;
|
||||||
|
use db::ClientDB;
|
||||||
|
use state_transition::{extend_active_state, StateTransitionError};
|
||||||
|
use types::{ActiveState, BeaconBlock, CrystallizedState, Hash256};
|
||||||
|
|
||||||
|
impl<T> BeaconChain<T>
|
||||||
|
where
|
||||||
|
T: ClientDB + Sized,
|
||||||
|
{
|
||||||
|
pub(crate) fn transition_states(
|
||||||
|
&self,
|
||||||
|
act_state: &ActiveState,
|
||||||
|
cry_state: &CrystallizedState,
|
||||||
|
block: &BeaconBlock,
|
||||||
|
block_hash: &Hash256,
|
||||||
|
) -> Result<(ActiveState, Option<CrystallizedState>), StateTransitionError> {
|
||||||
|
let state_recalc_distance = block
|
||||||
|
.slot
|
||||||
|
.checked_sub(cry_state.last_state_recalculation_slot)
|
||||||
|
.ok_or(StateTransitionError::BlockSlotBeforeRecalcSlot)?;
|
||||||
|
|
||||||
|
if state_recalc_distance >= u64::from(self.spec.epoch_length) {
|
||||||
|
panic!("Not implemented!")
|
||||||
|
} else {
|
||||||
|
let new_act_state = extend_active_state(act_state, block, block_hash)?;
|
||||||
|
Ok((new_act_state, None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
beacon_chain/genesis/Cargo.toml
Normal file
13
beacon_chain/genesis/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "genesis"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bls = { path = "../utils/bls" }
|
||||||
|
spec = { path = "../spec" }
|
||||||
|
ssz = { path = "../utils/ssz" }
|
||||||
|
types = { path = "../types" }
|
||||||
|
validator_induction = { path = "../validator_induction" }
|
||||||
|
validator_shuffling = { path = "../validator_shuffling" }
|
49
beacon_chain/genesis/src/beacon_block.rs
Normal file
49
beacon_chain/genesis/src/beacon_block.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use bls::{Signature, BLS_AGG_SIG_BYTE_SIZE};
|
||||||
|
use spec::ChainSpec;
|
||||||
|
use ssz::{encode::encode_length, Decodable, LENGTH_BYTES};
|
||||||
|
use types::{BeaconBlock, BeaconBlockBody};
|
||||||
|
|
||||||
|
/// Generate a genesis BeaconBlock.
|
||||||
|
pub fn genesis_beacon_block(spec: &ChainSpec) -> BeaconBlock {
|
||||||
|
BeaconBlock {
|
||||||
|
slot: spec.initial_slot_number,
|
||||||
|
parent_root: spec.zero_hash,
|
||||||
|
state_root: spec.zero_hash,
|
||||||
|
randao_reveal: spec.zero_hash,
|
||||||
|
candidate_pow_receipt_root: spec.zero_hash,
|
||||||
|
signature: genesis_signature(),
|
||||||
|
body: BeaconBlockBody {
|
||||||
|
proposer_slashings: vec![],
|
||||||
|
casper_slashings: vec![],
|
||||||
|
attestations: vec![],
|
||||||
|
deposits: vec![],
|
||||||
|
exits: vec![],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn genesis_signature() -> Signature {
|
||||||
|
let mut bytes = encode_length(BLS_AGG_SIG_BYTE_SIZE, LENGTH_BYTES);
|
||||||
|
bytes.append(&mut vec![0; BLS_AGG_SIG_BYTE_SIZE]);
|
||||||
|
let (signature, _) = match Signature::ssz_decode(&bytes, 0) {
|
||||||
|
Ok(sig) => sig,
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
};
|
||||||
|
signature
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// TODO: enhance these tests.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/117
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_genesis() {
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
|
||||||
|
// This only checks that the function runs without panic.
|
||||||
|
genesis_beacon_block(&spec);
|
||||||
|
}
|
||||||
|
}
|
135
beacon_chain/genesis/src/beacon_state.rs
Normal file
135
beacon_chain/genesis/src/beacon_state.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
use spec::ChainSpec;
|
||||||
|
use types::{BeaconState, CrosslinkRecord, ForkData, ValidatorStatus};
|
||||||
|
use validator_induction::ValidatorInductor;
|
||||||
|
use validator_shuffling::{shard_and_committees_for_cycle, ValidatorAssignmentError};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
NoValidators,
|
||||||
|
ValidationAssignmentError(ValidatorAssignmentError),
|
||||||
|
NotImplemented,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn genesis_beacon_state(spec: &ChainSpec) -> Result<BeaconState, Error> {
|
||||||
|
/*
|
||||||
|
* Parse the ValidatorRegistrations into ValidatorRecords and induct them.
|
||||||
|
*
|
||||||
|
* Ignore any records which fail proof-of-possession or are invalid.
|
||||||
|
*/
|
||||||
|
let validators = {
|
||||||
|
let mut inductor = ValidatorInductor::new(0, spec.shard_count, vec![]);
|
||||||
|
for registration in &spec.initial_validators {
|
||||||
|
let _ = inductor.induct(®istration, ValidatorStatus::Active);
|
||||||
|
}
|
||||||
|
inductor.to_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign the validators to shards, using all zeros as the seed.
|
||||||
|
*
|
||||||
|
* Crystallizedstate stores two cycles, so we simply repeat the same assignment twice.
|
||||||
|
*/
|
||||||
|
let _shard_and_committee_for_slots = {
|
||||||
|
let mut a = shard_and_committees_for_cycle(&[0; 32], &validators, 0, &spec)?;
|
||||||
|
let mut b = a.clone();
|
||||||
|
a.append(&mut b);
|
||||||
|
a
|
||||||
|
};
|
||||||
|
|
||||||
|
let initial_crosslink = CrosslinkRecord {
|
||||||
|
slot: spec.initial_slot_number,
|
||||||
|
shard_block_root: spec.zero_hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(BeaconState {
|
||||||
|
/*
|
||||||
|
* Misc
|
||||||
|
*/
|
||||||
|
slot: spec.initial_slot_number,
|
||||||
|
genesis_time: spec.genesis_time,
|
||||||
|
fork_data: ForkData {
|
||||||
|
pre_fork_version: spec.initial_fork_version,
|
||||||
|
post_fork_version: spec.initial_fork_version,
|
||||||
|
fork_slot: spec.initial_slot_number,
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
* Validator registry
|
||||||
|
*/
|
||||||
|
validator_registry: validators,
|
||||||
|
validator_registry_latest_change_slot: spec.initial_slot_number,
|
||||||
|
validator_registry_exit_count: 0,
|
||||||
|
validator_registry_delta_chain_tip: spec.zero_hash,
|
||||||
|
/*
|
||||||
|
* Randomness and committees
|
||||||
|
*/
|
||||||
|
randao_mix: spec.zero_hash,
|
||||||
|
next_seed: spec.zero_hash,
|
||||||
|
shard_committees_at_slots: vec![],
|
||||||
|
persistent_committees: vec![],
|
||||||
|
persistent_committee_reassignments: vec![],
|
||||||
|
/*
|
||||||
|
* Finality
|
||||||
|
*/
|
||||||
|
previous_justified_slot: spec.initial_slot_number,
|
||||||
|
justified_slot: spec.initial_slot_number,
|
||||||
|
justification_bitfield: 0,
|
||||||
|
finalized_slot: spec.initial_slot_number,
|
||||||
|
/*
|
||||||
|
* Recent state
|
||||||
|
*/
|
||||||
|
latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize],
|
||||||
|
latest_block_roots: vec![spec.zero_hash; spec.epoch_length as usize],
|
||||||
|
latest_penalized_exit_balances: vec![],
|
||||||
|
latest_attestations: vec![],
|
||||||
|
/*
|
||||||
|
* PoW receipt root
|
||||||
|
*/
|
||||||
|
processed_pow_receipt_root: spec.processed_pow_receipt_root,
|
||||||
|
candidate_pow_receipt_roots: vec![],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ValidatorAssignmentError> for Error {
|
||||||
|
fn from(e: ValidatorAssignmentError) -> Error {
|
||||||
|
Error::ValidationAssignmentError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
extern crate bls;
|
||||||
|
extern crate validator_induction;
|
||||||
|
|
||||||
|
use self::bls::{create_proof_of_possession, Keypair};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// TODO: enhance these tests.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/117
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_genesis() {
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
|
||||||
|
let state = genesis_beacon_state(&spec).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state.validator_registry.len(),
|
||||||
|
spec.initial_validators.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_genesis_bad_validator() {
|
||||||
|
let mut spec = ChainSpec::foundation();
|
||||||
|
|
||||||
|
let random_kp = Keypair::random();
|
||||||
|
spec.initial_validators[4].proof_of_possession = create_proof_of_possession(&random_kp);
|
||||||
|
|
||||||
|
let state = genesis_beacon_state(&spec).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
state.validator_registry.len(),
|
||||||
|
spec.initial_validators.len() - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
10
beacon_chain/genesis/src/lib.rs
Normal file
10
beacon_chain/genesis/src/lib.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
extern crate spec;
|
||||||
|
extern crate types;
|
||||||
|
extern crate validator_induction;
|
||||||
|
extern crate validator_shuffling;
|
||||||
|
|
||||||
|
mod beacon_state;
|
||||||
|
mod beacon_block;
|
||||||
|
|
||||||
|
pub use crate::beacon_block::genesis_beacon_block;
|
||||||
|
pub use crate::beacon_state::{genesis_beacon_state, Error as GenesisError};
|
@ -5,4 +5,5 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bls = { path = "../utils/bls" }
|
||||||
types = { path = "../types" }
|
types = { path = "../types" }
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
use super::ChainSpec;
|
use super::ChainSpec;
|
||||||
|
use bls::{create_proof_of_possession, Keypair, PublicKey, SecretKey};
|
||||||
|
|
||||||
use types::{Address, Hash256};
|
use types::{Address, Hash256, ValidatorRegistration};
|
||||||
|
|
||||||
impl ChainSpec {
|
impl ChainSpec {
|
||||||
/// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
|
/// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
|
||||||
|
///
|
||||||
|
/// Of course, the actual foundation specs are unknown at this point so these are just a rough
|
||||||
|
/// estimate.
|
||||||
pub fn foundation() -> Self {
|
pub fn foundation() -> Self {
|
||||||
Self {
|
Self {
|
||||||
/*
|
/*
|
||||||
@ -56,6 +60,59 @@ impl ChainSpec {
|
|||||||
max_attestations: 128,
|
max_attestations: 128,
|
||||||
max_deposits: 16,
|
max_deposits: 16,
|
||||||
max_exits: 16,
|
max_exits: 16,
|
||||||
|
/*
|
||||||
|
* Intialization parameters
|
||||||
|
*/
|
||||||
|
initial_validators: initial_validators_for_testing(),
|
||||||
|
genesis_time: 1544672897,
|
||||||
|
processed_pow_receipt_root: Hash256::from("pow_root".as_bytes()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a set of validator registrations to use with testing until the real chain starts.
|
||||||
|
fn initial_validators_for_testing() -> Vec<ValidatorRegistration> {
|
||||||
|
// Some dummy private keys to start with.
|
||||||
|
let key_strings = vec![
|
||||||
|
"jzjxxgjajfjrmgodszzsgqccmhnyvetcuxobhtynojtpdtbj",
|
||||||
|
"gpeehcjudxdijzhjgirfuhahmnjutlchjmoffxmimbdejakd",
|
||||||
|
"ntrrdwwebodokuwaclhoqreqyodngoyhurvesghjfxeswoaj",
|
||||||
|
"cibmzkqrzdgdlrvqaxinwpvyhcgjkeysrsjkqtkcxvznsvth",
|
||||||
|
"erqrfuahdwprsstkawggounxmihzhrvbhchcyiwtaypqcedr",
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut initial_validators = Vec::with_capacity(key_strings.len());
|
||||||
|
for key_string in key_strings {
|
||||||
|
let keypair = {
|
||||||
|
let secret_key = match SecretKey::from_bytes(&key_string.as_bytes()) {
|
||||||
|
Ok(key) => key,
|
||||||
|
Err(_) => unreachable!(), // Keys are static and should not fail.
|
||||||
|
};
|
||||||
|
let public_key = PublicKey::from_secret_key(&secret_key);
|
||||||
|
Keypair {
|
||||||
|
sk: secret_key,
|
||||||
|
pk: public_key,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let validator_registration = ValidatorRegistration {
|
||||||
|
pubkey: keypair.pk.clone(),
|
||||||
|
withdrawal_shard: 0,
|
||||||
|
withdrawal_address: Address::random(),
|
||||||
|
randao_commitment: Hash256::random(),
|
||||||
|
proof_of_possession: create_proof_of_possession(&keypair),
|
||||||
|
};
|
||||||
|
initial_validators.push(validator_registration);
|
||||||
|
}
|
||||||
|
|
||||||
|
initial_validators
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_foundation_spec_can_be_constructed() {
|
||||||
|
let _ = ChainSpec::foundation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
extern crate bls;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
|
|
||||||
mod foundation;
|
mod foundation;
|
||||||
|
|
||||||
use types::{Address, Hash256};
|
use types::{Address, Hash256, ValidatorRegistration};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct ChainSpec {
|
pub struct ChainSpec {
|
||||||
/*
|
/*
|
||||||
* Misc
|
* Misc
|
||||||
@ -55,4 +57,10 @@ pub struct ChainSpec {
|
|||||||
pub max_attestations: u64,
|
pub max_attestations: u64,
|
||||||
pub max_deposits: u64,
|
pub max_deposits: u64,
|
||||||
pub max_exits: u64,
|
pub max_exits: u64,
|
||||||
|
/*
|
||||||
|
* Intialization parameters
|
||||||
|
*/
|
||||||
|
pub initial_validators: Vec<ValidatorRegistration>,
|
||||||
|
pub genesis_time: u64,
|
||||||
|
pub processed_pow_receipt_root: Hash256,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
|
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
|
||||||
use super::{BeaconBlockBody, Hash256};
|
use super::{BeaconBlockBody, Hash256};
|
||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use bls::AggregateSignature;
|
use bls::Signature;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -11,7 +11,7 @@ pub struct BeaconBlock {
|
|||||||
pub state_root: Hash256,
|
pub state_root: Hash256,
|
||||||
pub randao_reveal: Hash256,
|
pub randao_reveal: Hash256,
|
||||||
pub candidate_pow_receipt_root: Hash256,
|
pub candidate_pow_receipt_root: Hash256,
|
||||||
pub signature: AggregateSignature,
|
pub signature: Signature,
|
||||||
pub body: BeaconBlockBody,
|
pub body: BeaconBlockBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,37 +2,53 @@ use super::candidate_pow_receipt_root_record::CandidatePoWReceiptRootRecord;
|
|||||||
use super::crosslink_record::CrosslinkRecord;
|
use super::crosslink_record::CrosslinkRecord;
|
||||||
use super::fork_data::ForkData;
|
use super::fork_data::ForkData;
|
||||||
use super::pending_attestation_record::PendingAttestationRecord;
|
use super::pending_attestation_record::PendingAttestationRecord;
|
||||||
use super::shard_and_committee::ShardAndCommittee;
|
use super::shard_committee::ShardCommittee;
|
||||||
use super::shard_reassignment_record::ShardReassignmentRecord;
|
use super::shard_reassignment_record::ShardReassignmentRecord;
|
||||||
use super::validator_record::ValidatorRecord;
|
use super::validator_record::ValidatorRecord;
|
||||||
use super::Hash256;
|
use super::Hash256;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct BeaconState {
|
pub struct BeaconState {
|
||||||
pub slot: u64,
|
// Misc
|
||||||
|
pub slot: u64,
|
||||||
pub genesis_time: u64,
|
pub genesis_time: u64,
|
||||||
pub fork_data: ForkData,
|
pub fork_data: ForkData,
|
||||||
|
|
||||||
|
// Validator registry
|
||||||
pub validator_registry: Vec<ValidatorRecord>,
|
pub validator_registry: Vec<ValidatorRecord>,
|
||||||
pub validator_balances: Vec<u64>,
|
pub validator_balances: Vec<u64>,
|
||||||
pub validator_registry_latest_change_slot: u64,
|
pub validator_registry_latest_change_slot: u64,
|
||||||
pub validator_registry_exit_count: u64,
|
pub validator_registry_exit_count: u64,
|
||||||
pub validator_registry_delta_chain_tip: Hash256,
|
pub validator_registry_delta_chain_tip: Hash256,
|
||||||
pub latest_randao_mixes: Vec<Hash256>,
|
|
||||||
pub latest_vdf_outputs: Vec<Hash256>,
|
// Randomness and committees
|
||||||
pub shard_committees_at_slots: Vec<Vec<ShardAndCommittee>>,
|
pub randao_mix: Hash256,
|
||||||
|
pub next_seed: Hash256,
|
||||||
|
pub shard_committees_at_slots: Vec<Vec<ShardCommittee>>,
|
||||||
pub persistent_committees: Vec<Vec<u32>>,
|
pub persistent_committees: Vec<Vec<u32>>,
|
||||||
pub persistent_committee_reassignments: Vec<ShardReassignmentRecord>,
|
pub persistent_committee_reassignments: Vec<ShardReassignmentRecord>,
|
||||||
|
|
||||||
|
// Finality
|
||||||
pub previous_justified_slot: u64,
|
pub previous_justified_slot: u64,
|
||||||
pub justified_slot: u64,
|
pub justified_slot: u64,
|
||||||
pub justification_bitfield: u64,
|
pub justification_bitfield: u64,
|
||||||
pub finalized_slot: u64,
|
pub finalized_slot: u64,
|
||||||
|
|
||||||
|
// Recent state
|
||||||
pub latest_crosslinks: Vec<CrosslinkRecord>,
|
pub latest_crosslinks: Vec<CrosslinkRecord>,
|
||||||
// TODO: remove this, it's no longer in the spec
|
|
||||||
pub latest_state_recalculation_slot: u64,
|
|
||||||
pub latest_block_roots: Vec<Hash256>,
|
pub latest_block_roots: Vec<Hash256>,
|
||||||
pub latest_penalized_exit_balances: Vec<u64>,
|
pub latest_penalized_exit_balances: Vec<u64>,
|
||||||
pub latest_attestations: Vec<PendingAttestationRecord>,
|
pub latest_attestations: Vec<PendingAttestationRecord>,
|
||||||
pub batched_block_roots: Vec<Hash256>,
|
|
||||||
|
// PoW receipt root
|
||||||
pub processed_pow_receipt_root: Hash256,
|
pub processed_pow_receipt_root: Hash256,
|
||||||
pub candidate_pow_receipt_roots: Vec<CandidatePoWReceiptRootRecord>,
|
pub candidate_pow_receipt_roots: Vec<CandidatePoWReceiptRootRecord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BeaconState {
|
||||||
|
pub fn canonical_root(&self) -> Hash256 {
|
||||||
|
// TODO: implement tree hashing.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/70
|
||||||
|
Hash256::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::Hash256;
|
use super::Hash256;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct CandidatePoWReceiptRootRecord {
|
pub struct CandidatePoWReceiptRootRecord {
|
||||||
pub candidate_pow_receipt_root: Hash256,
|
pub candidate_pow_receipt_root: Hash256,
|
||||||
pub votes: u64,
|
pub votes: u64,
|
||||||
|
@ -3,7 +3,7 @@ use super::Hash256;
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct CrosslinkRecord {
|
pub struct CrosslinkRecord {
|
||||||
pub slot: u64,
|
pub slot: u64,
|
||||||
pub shard_block_hash: Hash256,
|
pub shard_block_root: Hash256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrosslinkRecord {
|
impl CrosslinkRecord {
|
||||||
@ -11,7 +11,7 @@ impl CrosslinkRecord {
|
|||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self {
|
Self {
|
||||||
slot: 0,
|
slot: 0,
|
||||||
shard_block_hash: Hash256::zero(),
|
shard_block_root: Hash256::zero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::crosslink_record::CrosslinkRecord;
|
use super::crosslink_record::CrosslinkRecord;
|
||||||
use super::shard_and_committee::ShardAndCommittee;
|
use super::shard_committee::ShardCommittee;
|
||||||
use super::validator_record::ValidatorRecord;
|
use super::validator_record::ValidatorRecord;
|
||||||
use super::Hash256;
|
use super::Hash256;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ pub struct CrystallizedState {
|
|||||||
pub last_finalized_slot: u64,
|
pub last_finalized_slot: u64,
|
||||||
pub last_justified_slot: u64,
|
pub last_justified_slot: u64,
|
||||||
pub justified_streak: u64,
|
pub justified_streak: u64,
|
||||||
pub shard_and_committee_for_slots: Vec<Vec<ShardAndCommittee>>,
|
pub shard_and_committee_for_slots: Vec<Vec<ShardCommittee>>,
|
||||||
pub deposits_penalized_in_period: Vec<u32>,
|
pub deposits_penalized_in_period: Vec<u32>,
|
||||||
pub validator_set_delta_hash_chain: Hash256,
|
pub validator_set_delta_hash_chain: Hash256,
|
||||||
pub pre_fork_version: u32,
|
pub pre_fork_version: u32,
|
||||||
|
@ -24,7 +24,7 @@ pub mod fork_data;
|
|||||||
pub mod pending_attestation_record;
|
pub mod pending_attestation_record;
|
||||||
pub mod proposal_signed_data;
|
pub mod proposal_signed_data;
|
||||||
pub mod proposer_slashing;
|
pub mod proposer_slashing;
|
||||||
pub mod shard_and_committee;
|
pub mod shard_committee;
|
||||||
pub mod shard_reassignment_record;
|
pub mod shard_reassignment_record;
|
||||||
pub mod special_record;
|
pub mod special_record;
|
||||||
pub mod slashable_vote_data;
|
pub mod slashable_vote_data;
|
||||||
@ -52,7 +52,7 @@ pub use crate::pending_attestation_record::PendingAttestationRecord;
|
|||||||
pub use crate::proposal_signed_data::ProposalSignedData;
|
pub use crate::proposal_signed_data::ProposalSignedData;
|
||||||
pub use crate::proposer_slashing::ProposerSlashing;
|
pub use crate::proposer_slashing::ProposerSlashing;
|
||||||
pub use crate::slashable_vote_data::SlashableVoteData;
|
pub use crate::slashable_vote_data::SlashableVoteData;
|
||||||
pub use crate::shard_and_committee::ShardAndCommittee;
|
pub use crate::shard_committee::ShardCommittee;
|
||||||
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
|
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
|
||||||
pub use crate::validator_record::{ValidatorRecord, ValidatorStatus};
|
pub use crate::validator_record::{ValidatorRecord, ValidatorStatus};
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ShardAndCommittee {
|
pub struct ShardCommittee {
|
||||||
pub shard: u16,
|
pub shard: u16,
|
||||||
pub committee: Vec<usize>,
|
pub committee: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShardAndCommittee {
|
impl ShardCommittee {
|
||||||
/// Returns a new instance where the `shard_id` is zero and the
|
/// Returns a new instance where the `shard_id` is zero and the
|
||||||
/// committee is an empty vector.
|
/// committee is an empty vector.
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
@ -21,7 +21,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shard_and_committee_zero() {
|
fn test_shard_and_committee_zero() {
|
||||||
let s = ShardAndCommittee::zero();
|
let s = ShardCommittee::zero();
|
||||||
assert_eq!(s.shard, 0);
|
assert_eq!(s.shard, 0);
|
||||||
assert_eq!(s.committee.len(), 0);
|
assert_eq!(s.committee.len(), 0);
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct ShardReassignmentRecord {
|
pub struct ShardReassignmentRecord {
|
||||||
pub validator_index: u64,
|
pub validator_index: u64,
|
||||||
pub shard: u64,
|
pub shard: u64,
|
||||||
|
26
beacon_chain/types/src/validator_registration.rs
Normal file
26
beacon_chain/types/src/validator_registration.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use super::{Address, Hash256};
|
||||||
|
use bls::{create_proof_of_possession, Keypair, PublicKey, Signature};
|
||||||
|
|
||||||
|
/// The information gathered from the PoW chain validator registration function.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ValidatorRegistration {
|
||||||
|
pub pubkey: PublicKey,
|
||||||
|
pub withdrawal_shard: u64,
|
||||||
|
pub withdrawal_address: Address,
|
||||||
|
pub randao_commitment: Hash256,
|
||||||
|
pub proof_of_possession: Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidatorRegistration {
|
||||||
|
pub fn random() -> Self {
|
||||||
|
let keypair = Keypair::random();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pubkey: keypair.pk.clone(),
|
||||||
|
withdrawal_shard: 0,
|
||||||
|
withdrawal_address: Address::random(),
|
||||||
|
randao_commitment: Hash256::random(),
|
||||||
|
proof_of_possession: create_proof_of_possession(&keypair),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,5 +6,6 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
honey-badger-split = { path = "../utils/honey-badger-split" }
|
honey-badger-split = { path = "../utils/honey-badger-split" }
|
||||||
|
spec = { path = "../spec" }
|
||||||
types = { path = "../types" }
|
types = { path = "../types" }
|
||||||
vec_shuffle = { path = "../utils/vec_shuffle" }
|
vec_shuffle = { path = "../utils/vec_shuffle" }
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
extern crate honey_badger_split;
|
extern crate honey_badger_split;
|
||||||
|
extern crate spec;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
extern crate vec_shuffle;
|
extern crate vec_shuffle;
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
use honey_badger_split::SplitExt;
|
use honey_badger_split::SplitExt;
|
||||||
use types::{ChainConfig, ShardAndCommittee, ValidatorRecord, ValidatorStatus};
|
use spec::ChainSpec;
|
||||||
|
use types::{ShardCommittee, ValidatorRecord, ValidatorStatus};
|
||||||
use vec_shuffle::{shuffle, ShuffleErr};
|
use vec_shuffle::{shuffle, ShuffleErr};
|
||||||
|
|
||||||
type DelegatedCycle = Vec<Vec<ShardAndCommittee>>;
|
type DelegatedCycle = Vec<Vec<ShardCommittee>>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ValidatorAssignmentError {
|
pub enum ValidatorAssignmentError {
|
||||||
@ -20,10 +21,10 @@ pub fn shard_and_committees_for_cycle(
|
|||||||
seed: &[u8],
|
seed: &[u8],
|
||||||
validators: &[ValidatorRecord],
|
validators: &[ValidatorRecord],
|
||||||
crosslinking_shard_start: u16,
|
crosslinking_shard_start: u16,
|
||||||
config: &ChainConfig,
|
spec: &ChainSpec,
|
||||||
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
|
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
|
||||||
let shuffled_validator_indices = {
|
let shuffled_validator_indices = {
|
||||||
let mut validator_indices = validators
|
let validator_indices = validators
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, validator)| {
|
.filter_map(|(i, validator)| {
|
||||||
@ -36,15 +37,15 @@ pub fn shard_and_committees_for_cycle(
|
|||||||
.collect();
|
.collect();
|
||||||
shuffle(seed, validator_indices)?
|
shuffle(seed, validator_indices)?
|
||||||
};
|
};
|
||||||
let shard_indices: Vec<usize> = (0_usize..config.shard_count as usize).into_iter().collect();
|
let shard_indices: Vec<usize> = (0_usize..spec.shard_count as usize).into_iter().collect();
|
||||||
let crosslinking_shard_start = crosslinking_shard_start as usize;
|
let crosslinking_shard_start = crosslinking_shard_start as usize;
|
||||||
let cycle_length = config.cycle_length as usize;
|
let epoch_length = spec.epoch_length as usize;
|
||||||
let min_committee_size = config.min_committee_size as usize;
|
let min_committee_size = spec.target_committee_size as usize;
|
||||||
generate_cycle(
|
generate_cycle(
|
||||||
&shuffled_validator_indices,
|
&shuffled_validator_indices,
|
||||||
&shard_indices,
|
&shard_indices,
|
||||||
crosslinking_shard_start,
|
crosslinking_shard_start,
|
||||||
cycle_length,
|
epoch_length,
|
||||||
min_committee_size,
|
min_committee_size,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -54,29 +55,29 @@ fn generate_cycle(
|
|||||||
validator_indices: &[usize],
|
validator_indices: &[usize],
|
||||||
shard_indices: &[usize],
|
shard_indices: &[usize],
|
||||||
crosslinking_shard_start: usize,
|
crosslinking_shard_start: usize,
|
||||||
cycle_length: usize,
|
epoch_length: usize,
|
||||||
min_committee_size: usize,
|
min_committee_size: usize,
|
||||||
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
|
) -> Result<DelegatedCycle, ValidatorAssignmentError> {
|
||||||
let validator_count = validator_indices.len();
|
let validator_count = validator_indices.len();
|
||||||
let shard_count = shard_indices.len();
|
let shard_count = shard_indices.len();
|
||||||
|
|
||||||
if shard_count / cycle_length == 0 {
|
if shard_count / epoch_length == 0 {
|
||||||
return Err(ValidatorAssignmentError::TooFewShards);
|
return Err(ValidatorAssignmentError::TooFewShards);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (committees_per_slot, slots_per_committee) = {
|
let (committees_per_slot, slots_per_committee) = {
|
||||||
if validator_count >= cycle_length * min_committee_size {
|
if validator_count >= epoch_length * min_committee_size {
|
||||||
let committees_per_slot = min(
|
let committees_per_slot = min(
|
||||||
validator_count / cycle_length / (min_committee_size * 2) + 1,
|
validator_count / epoch_length / (min_committee_size * 2) + 1,
|
||||||
shard_count / cycle_length,
|
shard_count / epoch_length,
|
||||||
);
|
);
|
||||||
let slots_per_committee = 1;
|
let slots_per_committee = 1;
|
||||||
(committees_per_slot, slots_per_committee)
|
(committees_per_slot, slots_per_committee)
|
||||||
} else {
|
} else {
|
||||||
let committees_per_slot = 1;
|
let committees_per_slot = 1;
|
||||||
let mut slots_per_committee = 1;
|
let mut slots_per_committee = 1;
|
||||||
while (validator_count * slots_per_committee < cycle_length * min_committee_size)
|
while (validator_count * slots_per_committee < epoch_length * min_committee_size)
|
||||||
& (slots_per_committee < cycle_length)
|
& (slots_per_committee < epoch_length)
|
||||||
{
|
{
|
||||||
slots_per_committee *= 2;
|
slots_per_committee *= 2;
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ fn generate_cycle(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let cycle = validator_indices
|
let cycle = validator_indices
|
||||||
.honey_badger_split(cycle_length)
|
.honey_badger_split(epoch_length)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, slot_indices)| {
|
.map(|(i, slot_indices)| {
|
||||||
let shard_start =
|
let shard_start =
|
||||||
@ -93,7 +94,7 @@ fn generate_cycle(
|
|||||||
slot_indices
|
slot_indices
|
||||||
.honey_badger_split(committees_per_slot)
|
.honey_badger_split(committees_per_slot)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(j, shard_indices)| ShardAndCommittee {
|
.map(|(j, shard_indices)| ShardCommittee {
|
||||||
shard: ((shard_start + j) % shard_count) as u16,
|
shard: ((shard_start + j) % shard_count) as u16,
|
||||||
committee: shard_indices.to_vec(),
|
committee: shard_indices.to_vec(),
|
||||||
})
|
})
|
||||||
@ -119,7 +120,7 @@ mod tests {
|
|||||||
validator_count: &usize,
|
validator_count: &usize,
|
||||||
shard_count: &usize,
|
shard_count: &usize,
|
||||||
crosslinking_shard_start: usize,
|
crosslinking_shard_start: usize,
|
||||||
cycle_length: usize,
|
epoch_length: usize,
|
||||||
min_committee_size: usize,
|
min_committee_size: usize,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<usize>,
|
Vec<usize>,
|
||||||
@ -132,7 +133,7 @@ mod tests {
|
|||||||
&validator_indices,
|
&validator_indices,
|
||||||
&shard_indices,
|
&shard_indices,
|
||||||
crosslinking_shard_start,
|
crosslinking_shard_start,
|
||||||
cycle_length,
|
epoch_length,
|
||||||
min_committee_size,
|
min_committee_size,
|
||||||
);
|
);
|
||||||
(validator_indices, shard_indices, result)
|
(validator_indices, shard_indices, result)
|
||||||
@ -194,13 +195,13 @@ mod tests {
|
|||||||
let validator_count: usize = 100;
|
let validator_count: usize = 100;
|
||||||
let shard_count: usize = 20;
|
let shard_count: usize = 20;
|
||||||
let crosslinking_shard_start: usize = 0;
|
let crosslinking_shard_start: usize = 0;
|
||||||
let cycle_length: usize = 20;
|
let epoch_length: usize = 20;
|
||||||
let min_committee_size: usize = 10;
|
let min_committee_size: usize = 10;
|
||||||
let (validators, shards, result) = generate_cycle_helper(
|
let (validators, shards, result) = generate_cycle_helper(
|
||||||
&validator_count,
|
&validator_count,
|
||||||
&shard_count,
|
&shard_count,
|
||||||
crosslinking_shard_start,
|
crosslinking_shard_start,
|
||||||
cycle_length,
|
epoch_length,
|
||||||
min_committee_size,
|
min_committee_size,
|
||||||
);
|
);
|
||||||
let cycle = result.unwrap();
|
let cycle = result.unwrap();
|
||||||
@ -253,13 +254,13 @@ mod tests {
|
|||||||
let validator_count: usize = 523;
|
let validator_count: usize = 523;
|
||||||
let shard_count: usize = 31;
|
let shard_count: usize = 31;
|
||||||
let crosslinking_shard_start: usize = 0;
|
let crosslinking_shard_start: usize = 0;
|
||||||
let cycle_length: usize = 11;
|
let epoch_length: usize = 11;
|
||||||
let min_committee_size: usize = 5;
|
let min_committee_size: usize = 5;
|
||||||
let (validators, shards, result) = generate_cycle_helper(
|
let (validators, shards, result) = generate_cycle_helper(
|
||||||
&validator_count,
|
&validator_count,
|
||||||
&shard_count,
|
&shard_count,
|
||||||
crosslinking_shard_start,
|
crosslinking_shard_start,
|
||||||
cycle_length,
|
epoch_length,
|
||||||
min_committee_size,
|
min_committee_size,
|
||||||
);
|
);
|
||||||
let cycle = result.unwrap();
|
let cycle = result.unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user