Add unfinished progress on BeaconChain struct
This commit is contained in:
parent
a40b49d586
commit
a34266de0a
@ -5,6 +5,9 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bls = { path = "../utils/bls" }
|
bls = { path = "../utils/bls" }
|
||||||
|
db = { path = "../../lighthouse/db" }
|
||||||
|
ssz_helpers = { path = "../utils/ssz_helpers" }
|
||||||
types = { path = "../types" }
|
types = { path = "../types" }
|
||||||
|
validation = { path = "../validation" }
|
||||||
validator_induction = { path = "../validator_induction" }
|
validator_induction = { path = "../validator_induction" }
|
||||||
validator_shuffling = { path = "../validator_shuffling" }
|
validator_shuffling = { path = "../validator_shuffling" }
|
||||||
|
135
beacon_chain/chain/src/blocks.rs
Normal file
135
beacon_chain/chain/src/blocks.rs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
extern crate ssz_helpers;
|
||||||
|
extern crate validation;
|
||||||
|
|
||||||
|
use db::{
|
||||||
|
ClientDB,
|
||||||
|
};
|
||||||
|
use db::stores::{
|
||||||
|
BeaconBlockAtSlotError,
|
||||||
|
};
|
||||||
|
use self::validation::block_validation::{
|
||||||
|
BeaconBlockValidationContext,
|
||||||
|
SszBeaconBlockValidationError,
|
||||||
|
};
|
||||||
|
use super::{
|
||||||
|
BeaconChain,
|
||||||
|
BeaconChainError,
|
||||||
|
};
|
||||||
|
use self::ssz_helpers::ssz_beacon_block::{
|
||||||
|
SszBeaconBlock,
|
||||||
|
SszBeaconBlockError,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use types::{
|
||||||
|
BeaconBlock,
|
||||||
|
Hash256,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use self::validation::block_validation::BeaconBlockStatus;
|
||||||
|
|
||||||
|
pub enum BeaconChainBlockError {
|
||||||
|
UnknownCrystallizedState,
|
||||||
|
UnknownActiveState,
|
||||||
|
UnknownAttesterProposerMaps,
|
||||||
|
NoParentHash,
|
||||||
|
UnknownJustifiedBlock,
|
||||||
|
BlockAlreadyKnown,
|
||||||
|
BlockSlotLookupError(BeaconBlockAtSlotError),
|
||||||
|
BadSsz(SszBeaconBlockError),
|
||||||
|
BlockValidationError(SszBeaconBlockValidationError),
|
||||||
|
DBError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BeaconBlockAtSlotError> for BeaconChainBlockError {
|
||||||
|
fn from(e: BeaconBlockAtSlotError) -> BeaconChainBlockError {
|
||||||
|
BeaconChainBlockError::BlockSlotLookupError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SszBeaconBlockValidationError> for BeaconChainBlockError {
|
||||||
|
fn from(e: SszBeaconBlockValidationError) -> BeaconChainBlockError {
|
||||||
|
BeaconChainBlockError::BlockValidationError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BlockStatusTriple = (BeaconBlockStatus, Hash256, BeaconBlock);
|
||||||
|
|
||||||
|
|
||||||
|
impl<T> BeaconChain<T>
|
||||||
|
where T: ClientDB + Sized
|
||||||
|
{
|
||||||
|
pub fn process_incoming_block(&self, ssz: &[u8], rx_time: u64)
|
||||||
|
-> Result<BlockStatusTriple, BeaconChainBlockError>
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Generate a SszBlock to read directly from the serialized SSZ.
|
||||||
|
*/
|
||||||
|
let block = SszBeaconBlock::from_slice(ssz)?;
|
||||||
|
let block_hash = Hash256::from(&block.block_hash()[..]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the crystallized state for this block from our caches.
|
||||||
|
*
|
||||||
|
* Fail if the crystallized state is unknown.
|
||||||
|
*/
|
||||||
|
let cry_state_root = Hash256::from(block.cry_state_root());
|
||||||
|
let cry_state = self.crystallized_states.get(&cry_state_root)
|
||||||
|
.ok_or(BeaconChainBlockError::UnknownCrystallizedState)?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the active state for this block from our caches.
|
||||||
|
*
|
||||||
|
* Fail if the active state is unknown.
|
||||||
|
*/
|
||||||
|
let act_state_root = Hash256::from(block.act_state_root());
|
||||||
|
let act_state = self.active_states.get(&act_state_root)
|
||||||
|
.ok_or(BeaconChainBlockError::UnknownActiveState)?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Learn the last justified slot from the crystallized state and load
|
||||||
|
* the hash of this block from the database
|
||||||
|
*/
|
||||||
|
let last_justified_slot = cry_state.last_justified_slot;
|
||||||
|
let parent_block_hash = block.parent_hash()
|
||||||
|
.ok_or(BeaconChainBlockError::NoParentHash)?;
|
||||||
|
let (last_justified_block_hash, _) = self.store.block.block_at_slot(
|
||||||
|
&parent_block_hash, last_justified_slot)?
|
||||||
|
.ok_or(BeaconChainBlockError::UnknownJustifiedBlock)?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the attester and proposer maps for the crystallized state.
|
||||||
|
*/
|
||||||
|
let (attester_map, proposer_map) = self.attester_proposer_maps.get(&cry_state_root)
|
||||||
|
.ok_or(BeaconChainBlockError::UnknownAttesterProposerMaps)?;
|
||||||
|
|
||||||
|
let present_slot = 100; // TODO: fix this
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build a block validation context to test the block against.
|
||||||
|
*/
|
||||||
|
let validation_context = BeaconBlockValidationContext {
|
||||||
|
present_slot,
|
||||||
|
cycle_length: self.config.cycle_length,
|
||||||
|
last_justified_slot: cry_state.last_justified_slot,
|
||||||
|
last_justified_block_hash: Hash256::from(&last_justified_block_hash[..]),
|
||||||
|
last_finalized_slot: self.last_finalized_slot,
|
||||||
|
recent_block_hashes: Arc::new(act_state.recent_block_hashes.clone()),
|
||||||
|
proposer_map: proposer_map.clone(),
|
||||||
|
attester_map: attester_map.clone(),
|
||||||
|
block_store: self.store.block.clone(),
|
||||||
|
validator_store: self.store.validator.clone(),
|
||||||
|
pow_store: self.store.pow_chain.clone(),
|
||||||
|
};
|
||||||
|
let (block_status, deserialized_block) = validation_context.validate_ssz_block(&block_hash, &block)?;
|
||||||
|
match deserialized_block {
|
||||||
|
Some(b) => Ok((block_status, block_hash, b)),
|
||||||
|
None => Err(BeaconChainBlockError::BlockAlreadyKnown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SszBeaconBlockError> for BeaconChainBlockError {
|
||||||
|
fn from(e: SszBeaconBlockError) -> BeaconChainBlockError {
|
||||||
|
BeaconChainBlockError::BadSsz(e)
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ use types::{
|
|||||||
use super::{
|
use super::{
|
||||||
ActiveState,
|
ActiveState,
|
||||||
CrystallizedState,
|
CrystallizedState,
|
||||||
BeaconChain,
|
|
||||||
BeaconChainError,
|
BeaconChainError,
|
||||||
ChainConfig,
|
ChainConfig,
|
||||||
};
|
};
|
||||||
@ -24,7 +23,6 @@ impl From<ValidatorAssignmentError> for BeaconChainError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeaconChain {
|
|
||||||
/// Initialize a new ChainHead with genesis parameters.
|
/// Initialize a new ChainHead with genesis parameters.
|
||||||
///
|
///
|
||||||
/// Used when syncing a chain from scratch.
|
/// Used when syncing a chain from scratch.
|
||||||
@ -107,7 +105,6 @@ impl BeaconChain {
|
|||||||
|
|
||||||
Ok((active_state, crystallized_state))
|
Ok((active_state, crystallized_state))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -128,7 +125,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_genesis_no_validators() {
|
fn test_genesis_no_validators() {
|
||||||
let config = ChainConfig::standard();
|
let config = ChainConfig::standard();
|
||||||
let (act, cry) = BeaconChain::genesis_states(&config).unwrap();
|
let (act, cry) = genesis_states(&config).unwrap();
|
||||||
|
|
||||||
assert_eq!(cry.validator_set_change_slot, 0);
|
assert_eq!(cry.validator_set_change_slot, 0);
|
||||||
assert_eq!(cry.validators.len(), 0);
|
assert_eq!(cry.validators.len(), 0);
|
||||||
@ -175,7 +172,7 @@ mod tests {
|
|||||||
config.initial_validators.push(random_registration());
|
config.initial_validators.push(random_registration());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, cry) = BeaconChain::genesis_states(&config).unwrap();
|
let (_, cry) = genesis_states(&config).unwrap();
|
||||||
|
|
||||||
assert_eq!(cry.validators.len(), validator_count);
|
assert_eq!(cry.validators.len(), validator_count);
|
||||||
}
|
}
|
||||||
@ -198,7 +195,7 @@ mod tests {
|
|||||||
bad_v.withdrawal_shard = config.shard_count + 1;
|
bad_v.withdrawal_shard = config.shard_count + 1;
|
||||||
config.initial_validators.push(bad_v);
|
config.initial_validators.push(bad_v);
|
||||||
|
|
||||||
let (_, cry) = BeaconChain::genesis_states(&config).unwrap();
|
let (_, cry) = genesis_states(&config).unwrap();
|
||||||
|
|
||||||
assert!(config.initial_validators.len() != good_validator_count, "test is invalid");
|
assert!(config.initial_validators.len() != good_validator_count, "test is invalid");
|
||||||
assert_eq!(cry.validators.len(), good_validator_count);
|
assert_eq!(cry.validators.len(), good_validator_count);
|
||||||
|
@ -1,52 +1,99 @@
|
|||||||
|
extern crate db;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
extern crate validator_induction;
|
extern crate validator_induction;
|
||||||
extern crate validator_shuffling;
|
extern crate validator_shuffling;
|
||||||
|
|
||||||
|
mod stores;
|
||||||
|
mod blocks;
|
||||||
|
mod maps;
|
||||||
mod genesis;
|
mod genesis;
|
||||||
|
|
||||||
|
use db::ClientDB;
|
||||||
|
use genesis::genesis_states;
|
||||||
|
use maps::{
|
||||||
|
generate_attester_and_proposer_maps,
|
||||||
|
AttesterAndProposerMapError,
|
||||||
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use stores::BeaconChainStore;
|
||||||
use types::{
|
use types::{
|
||||||
ActiveState,
|
ActiveState,
|
||||||
|
AttesterMap,
|
||||||
ChainConfig,
|
ChainConfig,
|
||||||
CrystallizedState,
|
CrystallizedState,
|
||||||
Hash256,
|
Hash256,
|
||||||
|
ProposerMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum BeaconChainError {
|
pub enum BeaconChainError {
|
||||||
InvalidGenesis,
|
InvalidGenesis,
|
||||||
|
InsufficientValidators,
|
||||||
|
UnableToGenerateMaps(AttesterAndProposerMapError),
|
||||||
DBError(String),
|
DBError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BeaconChain {
|
impl From<AttesterAndProposerMapError> for BeaconChainError {
|
||||||
pub last_finalized_slot: Option<u64>,
|
fn from(e: AttesterAndProposerMapError) -> BeaconChainError {
|
||||||
|
BeaconChainError::UnableToGenerateMaps(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BeaconChain<T: ClientDB + Sized> {
|
||||||
|
/// The last slot which has been finalized, this is common to all forks.
|
||||||
|
pub last_finalized_slot: u64,
|
||||||
|
/// The hash of the head of the canonical chain.
|
||||||
pub canonical_latest_block_hash: Hash256,
|
pub canonical_latest_block_hash: Hash256,
|
||||||
|
/// A vec of hashes of heads of fork (non-canonical) chains.
|
||||||
pub fork_latest_block_hashes: Vec<Hash256>,
|
pub fork_latest_block_hashes: Vec<Hash256>,
|
||||||
|
/// A map where the value is an active state the the key is its hash.
|
||||||
pub active_states: HashMap<Hash256, ActiveState>,
|
pub active_states: HashMap<Hash256, ActiveState>,
|
||||||
|
/// A map where the value is crystallized state the the key is its hash.
|
||||||
pub crystallized_states: HashMap<Hash256, CrystallizedState>,
|
pub crystallized_states: HashMap<Hash256, CrystallizedState>,
|
||||||
|
/// A map of crystallized state to a proposer and attester map.
|
||||||
|
pub attester_proposer_maps: HashMap<Hash256, (Arc<AttesterMap>, Arc<ProposerMap>)>,
|
||||||
|
/// A collection of database stores used by the chain.
|
||||||
|
pub store: BeaconChainStore<T>,
|
||||||
|
/// The chain configuration.
|
||||||
pub config: ChainConfig,
|
pub config: ChainConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeaconChain {
|
impl<T> BeaconChain<T>
|
||||||
pub fn new(config: ChainConfig)
|
where T: ClientDB + Sized
|
||||||
|
{
|
||||||
|
pub fn new(store: BeaconChainStore<T>, config: ChainConfig)
|
||||||
-> Result<Self, BeaconChainError>
|
-> Result<Self, BeaconChainError>
|
||||||
{
|
{
|
||||||
let (active_state, crystallized_state) = BeaconChain::genesis_states(&config)?;
|
if config.initial_validators.is_empty() {
|
||||||
|
return Err(BeaconChainError::InsufficientValidators);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (active_state, crystallized_state) = genesis_states(&config)?;
|
||||||
|
|
||||||
let canonical_latest_block_hash = Hash256::zero();
|
let canonical_latest_block_hash = Hash256::zero();
|
||||||
let fork_latest_block_hashes = vec![];
|
let fork_latest_block_hashes = vec![];
|
||||||
let mut active_states = HashMap::new();
|
let mut active_states = HashMap::new();
|
||||||
let mut crystallized_states = HashMap::new();
|
let mut crystallized_states = HashMap::new();
|
||||||
|
let mut attester_proposer_maps = HashMap::new();
|
||||||
|
|
||||||
|
let (attester_map, proposer_map) = generate_attester_and_proposer_maps(
|
||||||
|
&crystallized_state, 0)?;
|
||||||
|
|
||||||
active_states.insert(canonical_latest_block_hash, active_state);
|
active_states.insert(canonical_latest_block_hash, active_state);
|
||||||
crystallized_states.insert(canonical_latest_block_hash, crystallized_state);
|
crystallized_states.insert(canonical_latest_block_hash, crystallized_state);
|
||||||
|
attester_proposer_maps.insert(
|
||||||
|
canonical_latest_block_hash,
|
||||||
|
(Arc::new(attester_map), Arc::new(proposer_map)));
|
||||||
|
|
||||||
Ok(Self{
|
Ok(Self{
|
||||||
last_finalized_slot: None,
|
last_finalized_slot: 0,
|
||||||
canonical_latest_block_hash,
|
canonical_latest_block_hash,
|
||||||
fork_latest_block_hashes,
|
fork_latest_block_hashes,
|
||||||
active_states,
|
active_states,
|
||||||
crystallized_states,
|
crystallized_states,
|
||||||
|
attester_proposer_maps,
|
||||||
|
store,
|
||||||
config,
|
config,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -55,21 +102,32 @@ impl BeaconChain {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use super::*;
|
use super::*;
|
||||||
use types::ValidatorRegistration;
|
use types::ValidatorRegistration;
|
||||||
|
use db::MemoryDB;
|
||||||
|
use db::stores::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_chain() {
|
fn test_new_chain() {
|
||||||
let mut config = ChainConfig::standard();
|
let mut config = ChainConfig::standard();
|
||||||
|
config.cycle_length = 4;
|
||||||
|
config.shard_count = 4;
|
||||||
|
let db = Arc::new(MemoryDB::open());
|
||||||
|
let store = BeaconChainStore {
|
||||||
|
block: Arc::new(BeaconBlockStore::new(db.clone())),
|
||||||
|
pow_chain: Arc::new(PoWChainStore::new(db.clone())),
|
||||||
|
validator: Arc::new(ValidatorStore::new(db.clone())),
|
||||||
|
};
|
||||||
|
|
||||||
for _ in 0..4 {
|
for _ in 0..config.cycle_length * 2 {
|
||||||
config.initial_validators.push(ValidatorRegistration::random())
|
config.initial_validators.push(ValidatorRegistration::random())
|
||||||
}
|
}
|
||||||
|
|
||||||
let chain = BeaconChain::new(config.clone()).unwrap();
|
let chain = BeaconChain::new(store, config.clone()).unwrap();
|
||||||
let (act, cry) = BeaconChain::genesis_states(&config).unwrap();
|
let (act, cry) = genesis_states(&config).unwrap();
|
||||||
|
|
||||||
assert_eq!(chain.last_finalized_slot, None);
|
assert_eq!(chain.last_finalized_slot, 0);
|
||||||
assert_eq!(chain.canonical_latest_block_hash, Hash256::zero());
|
assert_eq!(chain.canonical_latest_block_hash, Hash256::zero());
|
||||||
|
|
||||||
let stored_act = chain.active_states.get(&Hash256::zero()).unwrap();
|
let stored_act = chain.active_states.get(&Hash256::zero()).unwrap();
|
||||||
|
45
beacon_chain/chain/src/maps.rs
Normal file
45
beacon_chain/chain/src/maps.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use types::{
|
||||||
|
AttesterMap,
|
||||||
|
CrystallizedState,
|
||||||
|
ProposerMap,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum AttesterAndProposerMapError {
|
||||||
|
NoShardAndCommitteeForSlot,
|
||||||
|
NoAvailableProposer,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a map of `(slot, shard) |--> committee`.
|
||||||
|
///
|
||||||
|
/// The attester map is used to optimise the lookup of a committee.
|
||||||
|
pub fn generate_attester_and_proposer_maps(cry_state: &CrystallizedState, start_slot: u64)
|
||||||
|
-> Result<(AttesterMap, ProposerMap), AttesterAndProposerMapError>
|
||||||
|
{
|
||||||
|
let mut attester_map = AttesterMap::new();
|
||||||
|
let mut proposer_map = ProposerMap::new();
|
||||||
|
for (i, slot) in cry_state.shard_and_committee_for_slots.iter().enumerate() {
|
||||||
|
/*
|
||||||
|
* Store the proposer for the block.
|
||||||
|
*/
|
||||||
|
let slot_number = (i as u64).saturating_add(start_slot);
|
||||||
|
let first_committee = {
|
||||||
|
let first_shard_and_committee = slot.get(0)
|
||||||
|
.ok_or(AttesterAndProposerMapError::NoShardAndCommitteeForSlot)?;
|
||||||
|
first_shard_and_committee.committee.clone()
|
||||||
|
};
|
||||||
|
println!("{:?}", slot);
|
||||||
|
let proposer_index = (slot_number as usize).checked_rem(first_committee.len())
|
||||||
|
.ok_or(AttesterAndProposerMapError::NoAvailableProposer)?;
|
||||||
|
proposer_map.insert(slot_number, proposer_index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop through the shards and extend the attester map.
|
||||||
|
*/
|
||||||
|
for shard_and_committee in slot {
|
||||||
|
let committee = shard_and_committee.committee.clone();
|
||||||
|
attester_map.insert((slot_number, shard_and_committee.shard), committee);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((attester_map, proposer_map))
|
||||||
|
}
|
15
beacon_chain/chain/src/stores.rs
Normal file
15
beacon_chain/chain/src/stores.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use db::{
|
||||||
|
ClientDB,
|
||||||
|
};
|
||||||
|
use db::stores::{
|
||||||
|
BeaconBlockStore,
|
||||||
|
PoWChainStore,
|
||||||
|
ValidatorStore,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct BeaconChainStore<T: ClientDB + Sized> {
|
||||||
|
pub block: Arc<BeaconBlockStore<T>>,
|
||||||
|
pub pow_chain: Arc<PoWChainStore<T>>,
|
||||||
|
pub validator: Arc<ValidatorStore<T>>,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user