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::{
|
use db::{
|
||||||
ClientDB,
|
ClientDB,
|
||||||
};
|
};
|
||||||
use db::stores::{
|
use db::stores::{
|
||||||
BeaconBlockAtSlotError,
|
BeaconBlockAtSlotError,
|
||||||
};
|
};
|
||||||
use self::validation::block_validation::{
|
use validation::block_validation::{
|
||||||
BeaconBlockValidationContext,
|
BeaconBlockValidationContext,
|
||||||
SszBeaconBlockValidationError,
|
|
||||||
};
|
};
|
||||||
use super::{
|
use super::{
|
||||||
BeaconChain,
|
BeaconChain,
|
||||||
BeaconChainError,
|
|
||||||
};
|
};
|
||||||
use self::ssz_helpers::ssz_beacon_block::{
|
use ssz_helpers::ssz_beacon_block::{
|
||||||
SszBeaconBlock,
|
SszBeaconBlock,
|
||||||
SszBeaconBlockError,
|
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlock,
|
|
||||||
Hash256,
|
Hash256,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::validation::block_validation::BeaconBlockStatus;
|
pub enum BlockValidationContextError {
|
||||||
|
|
||||||
pub enum BeaconChainBlockError {
|
|
||||||
UnknownCrystallizedState,
|
UnknownCrystallizedState,
|
||||||
UnknownActiveState,
|
UnknownActiveState,
|
||||||
UnknownAttesterProposerMaps,
|
UnknownAttesterProposerMaps,
|
||||||
@ -35,37 +26,20 @@ pub enum BeaconChainBlockError {
|
|||||||
UnknownJustifiedBlock,
|
UnknownJustifiedBlock,
|
||||||
BlockAlreadyKnown,
|
BlockAlreadyKnown,
|
||||||
BlockSlotLookupError(BeaconBlockAtSlotError),
|
BlockSlotLookupError(BeaconBlockAtSlotError),
|
||||||
BadSsz(SszBeaconBlockError),
|
|
||||||
BlockValidationError(SszBeaconBlockValidationError),
|
|
||||||
DBError(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BeaconBlockAtSlotError> for BeaconChainBlockError {
|
impl From<BeaconBlockAtSlotError> for BlockValidationContextError {
|
||||||
fn from(e: BeaconBlockAtSlotError) -> BeaconChainBlockError {
|
fn from(e: BeaconBlockAtSlotError) -> BlockValidationContextError {
|
||||||
BeaconChainBlockError::BlockSlotLookupError(e)
|
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>
|
impl<T> BeaconChain<T>
|
||||||
where T: ClientDB + Sized
|
where T: ClientDB + Sized
|
||||||
{
|
{
|
||||||
fn block_preprocessing(&self, ssz: &[u8], present_slot: u64)
|
pub(crate) fn block_validation_context(&self, block: &SszBeaconBlock, present_slot: u64)
|
||||||
-> Result<BlockStatusTriple, BeaconChainBlockError>
|
-> 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.
|
* 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_root = Hash256::from(block.cry_state_root());
|
||||||
let cry_state = self.crystallized_states.get(&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.
|
* 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_root = Hash256::from(block.act_state_root());
|
||||||
let act_state = self.active_states.get(&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
|
* 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 last_justified_slot = cry_state.last_justified_slot;
|
||||||
let parent_block_hash = block.parent_hash()
|
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(
|
let (last_justified_block_hash, _) = self.store.block.block_at_slot(
|
||||||
&parent_block_hash, last_justified_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.
|
* Load the attester and proposer maps for the crystallized state.
|
||||||
*/
|
*/
|
||||||
let (attester_map, proposer_map) = self.attester_proposer_maps.get(&cry_state_root)
|
let (attester_map, proposer_map) = self.attester_proposer_maps.get(&cry_state_root)
|
||||||
.ok_or(BeaconChainBlockError::UnknownAttesterProposerMaps)?;
|
.ok_or(BlockValidationContextError::UnknownAttesterProposerMaps)?;
|
||||||
|
|
||||||
/*
|
Ok(BeaconBlockValidationContext {
|
||||||
* Build a block validation context to test the block against.
|
|
||||||
*/
|
|
||||||
let validation_context = BeaconBlockValidationContext {
|
|
||||||
present_slot,
|
present_slot,
|
||||||
cycle_length: self.config.cycle_length,
|
cycle_length: self.config.cycle_length,
|
||||||
last_justified_slot: cry_state.last_justified_slot,
|
last_justified_slot: cry_state.last_justified_slot,
|
||||||
@ -116,17 +87,6 @@ impl<T> BeaconChain<T>
|
|||||||
block_store: self.store.block.clone(),
|
block_store: self.store.block.clone(),
|
||||||
validator_store: self.store.validator.clone(),
|
validator_store: self.store.validator.clone(),
|
||||||
pow_store: self.store.pow_chain.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 db;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
|
extern crate ssz_helpers;
|
||||||
|
extern crate validation;
|
||||||
extern crate validator_induction;
|
extern crate validator_induction;
|
||||||
extern crate validator_shuffling;
|
extern crate validator_shuffling;
|
||||||
|
|
||||||
mod stores;
|
mod stores;
|
||||||
mod block_preprocessing;
|
mod block_context;
|
||||||
|
mod block_processing;
|
||||||
mod maps;
|
mod maps;
|
||||||
mod genesis;
|
mod genesis;
|
||||||
|
|
||||||
@ -43,10 +46,10 @@ impl From<AttesterAndProposerMapError> for BeaconChainError {
|
|||||||
pub struct BeaconChain<T: ClientDB + Sized> {
|
pub struct BeaconChain<T: ClientDB + Sized> {
|
||||||
/// The last slot which has been finalized, this is common to all forks.
|
/// The last slot which has been finalized, this is common to all forks.
|
||||||
pub last_finalized_slot: u64,
|
pub last_finalized_slot: u64,
|
||||||
/// The hash of the head of the canonical chain.
|
/// A vec of all block heads (tips of chains).
|
||||||
pub canonical_latest_block_hash: Hash256,
|
pub head_block_hashes: Vec<Hash256>,
|
||||||
/// A vec of hashes of heads of fork (non-canonical) chains.
|
/// The index of the canonical block in `head_block_hashes`.
|
||||||
pub fork_latest_block_hashes: Vec<Hash256>,
|
pub canonical_head_block_hash: usize,
|
||||||
/// A map where the value is an active state the the key is its hash.
|
/// 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.
|
/// 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 (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 head_block_hashes = vec![canonical_latest_block_hash];
|
||||||
|
let canonical_head_block_hash = 0;
|
||||||
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 mut attester_proposer_maps = HashMap::new();
|
||||||
@ -88,8 +92,8 @@ impl<T> BeaconChain<T>
|
|||||||
|
|
||||||
Ok(Self{
|
Ok(Self{
|
||||||
last_finalized_slot: 0,
|
last_finalized_slot: 0,
|
||||||
canonical_latest_block_hash,
|
head_block_hashes,
|
||||||
fork_latest_block_hashes,
|
canonical_head_block_hash,
|
||||||
active_states,
|
active_states,
|
||||||
crystallized_states,
|
crystallized_states,
|
||||||
attester_proposer_maps,
|
attester_proposer_maps,
|
||||||
@ -97,6 +101,10 @@ impl<T> BeaconChain<T>
|
|||||||
config,
|
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();
|
let (act, cry) = genesis_states(&config).unwrap();
|
||||||
|
|
||||||
assert_eq!(chain.last_finalized_slot, 0);
|
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();
|
let stored_act = chain.active_states.get(&Hash256::zero()).unwrap();
|
||||||
assert_eq!(act, *stored_act);
|
assert_eq!(act, *stored_act);
|
||||||
|
@ -51,13 +51,6 @@ impl<T: ClientDB> BeaconBlockStore<T> {
|
|||||||
self.db.exists(DB_COLUMN, hash)
|
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.
|
/// 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
|
/// 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