Add initial works on extending the chain
This commit is contained in:
parent
b2495cbcff
commit
7f21fd325e
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
109
beacon_chain/chain/src/block_processing.rs
Normal file
109
beacon_chain/chain/src/block_processing.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user