Add initial works on extending the chain

This commit is contained in:
Paul Hauner 2018-10-25 10:14:43 +02:00
parent b2495cbcff
commit 7f21fd325e
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
4 changed files with 141 additions and 71 deletions

View File

@ -1,33 +1,24 @@
extern crate ssz_helpers;
extern crate validation;
use db::{
ClientDB,
};
use db::stores::{
BeaconBlockAtSlotError,
};
use self::validation::block_validation::{
use validation::block_validation::{
BeaconBlockValidationContext,
SszBeaconBlockValidationError,
};
use super::{
BeaconChain,
BeaconChainError,
};
use self::ssz_helpers::ssz_beacon_block::{
use 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 {
pub enum BlockValidationContextError {
UnknownCrystallizedState,
UnknownActiveState,
UnknownAttesterProposerMaps,
@ -35,37 +26,20 @@ pub enum BeaconChainBlockError {
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<BeaconBlockAtSlotError> for BlockValidationContextError {
fn from(e: BeaconBlockAtSlotError) -> BlockValidationContextError {
BlockValidationContextError::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
{
fn block_preprocessing(&self, ssz: &[u8], present_slot: u64)
-> Result<BlockStatusTriple, BeaconChainBlockError>
pub(crate) fn block_validation_context(&self, block: &SszBeaconBlock, present_slot: u64)
-> Result<BeaconBlockValidationContext<T>, BlockValidationContextError>
{
/*
* 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.
*
@ -73,7 +47,7 @@ impl<T> BeaconChain<T>
*/
let cry_state_root = Hash256::from(block.cry_state_root());
let cry_state = self.crystallized_states.get(&cry_state_root)
.ok_or(BeaconChainBlockError::UnknownCrystallizedState)?;
.ok_or(BlockValidationContextError::UnknownCrystallizedState)?;
/*
* Load the active state for this block from our caches.
@ -82,7 +56,7 @@ impl<T> BeaconChain<T>
*/
let act_state_root = Hash256::from(block.act_state_root());
let act_state = self.active_states.get(&act_state_root)
.ok_or(BeaconChainBlockError::UnknownActiveState)?;
.ok_or(BlockValidationContextError::UnknownActiveState)?;
/*
* Learn the last justified slot from the crystallized state and load
@ -90,21 +64,18 @@ impl<T> BeaconChain<T>
*/
let last_justified_slot = cry_state.last_justified_slot;
let parent_block_hash = block.parent_hash()
.ok_or(BeaconChainBlockError::NoParentHash)?;
.ok_or(BlockValidationContextError::NoParentHash)?;
let (last_justified_block_hash, _) = self.store.block.block_at_slot(
&parent_block_hash, last_justified_slot)?
.ok_or(BeaconChainBlockError::UnknownJustifiedBlock)?;
.ok_or(BlockValidationContextError::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)?;
.ok_or(BlockValidationContextError::UnknownAttesterProposerMaps)?;
/*
* Build a block validation context to test the block against.
*/
let validation_context = BeaconBlockValidationContext {
Ok(BeaconBlockValidationContext {
present_slot,
cycle_length: self.config.cycle_length,
last_justified_slot: cry_state.last_justified_slot,
@ -116,17 +87,6 @@ impl<T> BeaconChain<T>
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)
})
}
}

View File

@ -0,0 +1,109 @@
use super::{
BeaconChain,
ClientDB,
};
use super::block_context::{
BlockValidationContextError,
};
use ssz_helpers::ssz_beacon_block::{
SszBeaconBlock,
SszBeaconBlockError,
};
use types::{
Hash256,
};
use validation::block_validation::{
BeaconBlockStatus,
SszBeaconBlockValidationError,
};
pub enum BlockProcessingOutcome {
BlockAlreadyKnown,
NewCanonicalBlock,
NewForkBlock,
}
pub enum BlockProcessingError {
ContextGenerationError(BlockValidationContextError),
DeserializationFailed(SszBeaconBlockError),
ValidationFailed(SszBeaconBlockValidationError),
}
impl<T> BeaconChain<T>
where T: ClientDB + Sized
{
pub fn process_block(&mut self, ssz: &[u8], present_slot: u64)
-> Result<(BlockProcessingOutcome, Hash256), BlockProcessingError>
{
/*
* Generate a SszBlock to read directly from the serialized SSZ.
*/
let ssz_block = SszBeaconBlock::from_slice(ssz)?;
let block_hash = Hash256::from(&ssz_block.block_hash()[..]);
let parent_hash = ssz_block.parent_hash()
.ok_or(BlockProcessingError::ValidationFailed(
SszBeaconBlockValidationError::UnknownParentHash))?;
/*
* Generate the context in which to validate this block.
*/
let validation_context = self.block_validation_context(&ssz_block, present_slot)?;
/*
* Validate the block against the context, checking signatures, parent_hashes, etc.
*/
let (block_status, block) = validation_context.validate_ssz_block(&block_hash, &block)?;
match block_status {
/*
*
*/
BeaconBlockStatus::KnownBlock => {
Ok((BlockProcessingOutcome::BlockAlreadyKnown, block_hash))
}
BeaconBlockStatus::NewBlock => {
let head_hash_index = {
match self.head_block_hashes.iter().position(|x| *x == Hash256::from(parent_hash)) {
Some(i) => i,
None => {
self.head_block_hashes.push(block_hash);
self.head_block_hashes.len() - 1
}
}
};
if head_hash_index == self.canonical_head_block_hash {
Ok((BlockProcessingOutcome::NewCanonicalBlock, block_hash))
} else {
Ok((BlockProcessingOutcome::NewForkBlock, block_hash))
}
}
}
}
pub fn extend_chain(
&self,
block: &Block,
block_hash: &Hash256,
head_hash_index: usize)
-> Result<>
}
impl From<BlockValidationContextError> for BlockProcessingError {
fn from(e: BlockValidationContextError) -> Self {
BlockProcessingError::ContextGenerationError(e)
}
}
impl From<SszBeaconBlockError> for BlockProcessingError {
fn from(e: SszBeaconBlockError) -> Self {
BlockProcessingError::DeserializationFailed(e)
}
}
impl From<SszBeaconBlockValidationError> for BlockProcessingError {
fn from(e: SszBeaconBlockValidationError) -> Self {
BlockProcessingError::ValidationFailed(e)
}
}

View File

@ -1,10 +1,13 @@
extern crate db;
extern crate types;
extern crate ssz_helpers;
extern crate validation;
extern crate validator_induction;
extern crate validator_shuffling;
mod stores;
mod block_preprocessing;
mod block_context;
mod block_processing;
mod maps;
mod genesis;
@ -43,10 +46,10 @@ impl From<AttesterAndProposerMapError> for BeaconChainError {
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,
/// A vec of hashes of heads of fork (non-canonical) chains.
pub fork_latest_block_hashes: Vec<Hash256>,
/// A vec of all block heads (tips of chains).
pub head_block_hashes: Vec<Hash256>,
/// The index of the canonical block in `head_block_hashes`.
pub canonical_head_block_hash: usize,
/// A map where the value is an active state the the key is its hash.
pub active_states: HashMap<Hash256, ActiveState>,
/// A map where the value is crystallized state the the key is its hash.
@ -72,7 +75,8 @@ impl<T> BeaconChain<T>
let (active_state, crystallized_state) = genesis_states(&config)?;
let canonical_latest_block_hash = Hash256::zero();
let fork_latest_block_hashes = vec![];
let head_block_hashes = vec![canonical_latest_block_hash];
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();
@ -88,8 +92,8 @@ impl<T> BeaconChain<T>
Ok(Self{
last_finalized_slot: 0,
canonical_latest_block_hash,
fork_latest_block_hashes,
head_block_hashes,
canonical_head_block_hash,
active_states,
crystallized_states,
attester_proposer_maps,
@ -97,6 +101,10 @@ impl<T> BeaconChain<T>
config,
})
}
pub fn canonical_block_hash(self) -> Hash256 {
self.head_block_hashes[self.canonical_head_block_hash]
}
}
@ -128,7 +136,7 @@ mod tests {
let (act, cry) = genesis_states(&config).unwrap();
assert_eq!(chain.last_finalized_slot, 0);
assert_eq!(chain.canonical_latest_block_hash, Hash256::zero());
assert_eq!(chain.canonical_block_hash(), Hash256::zero());
let stored_act = chain.active_states.get(&Hash256::zero()).unwrap();
assert_eq!(act, *stored_act);

View File

@ -51,13 +51,6 @@ impl<T: ClientDB> BeaconBlockStore<T> {
self.db.exists(DB_COLUMN, hash)
}
pub fn block_exists_in_canonical_chain(&self, hash: &[u8])
-> Result<bool, DBError>
{
// TODO: implement logic for canonical chain
self.db.exists(DB_COLUMN, hash)
}
/// Retrieve the block at a slot given a "head_hash" and a slot.
///
/// A "head_hash" must be a block hash with a slot number greater than or equal to the desired