Move beacon_chain into lighthouse dir
This commit is contained in:
parent
dc8fbf813f
commit
2b63ece244
@ -1,16 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "chain"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bls = { path = "../utils/bls" }
|
|
||||||
db = { path = "../../lighthouse/db" }
|
|
||||||
genesis = { path = "../genesis" }
|
|
||||||
naive_fork_choice = { path = "../naive_fork_choice" }
|
|
||||||
spec = { path = "../spec" }
|
|
||||||
ssz = { path = "../utils/ssz" }
|
|
||||||
types = { path = "../types" }
|
|
||||||
validator_induction = { path = "../validator_induction" }
|
|
||||||
validator_shuffling = { path = "../validator_shuffling" }
|
|
@ -1,29 +0,0 @@
|
|||||||
use super::BeaconChain;
|
|
||||||
use db::ClientDB;
|
|
||||||
use types::Hash256;
|
|
||||||
|
|
||||||
pub enum BlockProcessingOutcome {
|
|
||||||
BlockAlreadyKnown,
|
|
||||||
NewCanonicalBlock,
|
|
||||||
NewReorgBlock,
|
|
||||||
NewForkBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Error {
|
|
||||||
NotImplemented,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> BeaconChain<T>
|
|
||||||
where
|
|
||||||
T: ClientDB + Sized,
|
|
||||||
{
|
|
||||||
pub fn process_block(
|
|
||||||
&mut self,
|
|
||||||
_ssz: &[u8],
|
|
||||||
_present_slot: u64,
|
|
||||||
) -> Result<(BlockProcessingOutcome, Hash256), Error> {
|
|
||||||
// TODO: block processing has been removed.
|
|
||||||
// https://github.com/sigp/lighthouse/issues/98
|
|
||||||
Err(Error::NotImplemented)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
extern crate db;
|
|
||||||
extern crate naive_fork_choice;
|
|
||||||
extern crate genesis;
|
|
||||||
extern crate spec;
|
|
||||||
extern crate ssz;
|
|
||||||
extern crate types;
|
|
||||||
extern crate validator_induction;
|
|
||||||
extern crate validator_shuffling;
|
|
||||||
|
|
||||||
mod block_processing;
|
|
||||||
mod maps;
|
|
||||||
mod stores;
|
|
||||||
|
|
||||||
use db::ClientDB;
|
|
||||||
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::sync::Arc;
|
|
||||||
use types::{AttesterMap, BeaconState, Hash256, ProposerMap};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum BeaconChainError {
|
|
||||||
InvalidGenesis,
|
|
||||||
InsufficientValidators,
|
|
||||||
UnableToGenerateMaps(AttesterAndProposerMapError),
|
|
||||||
GenesisError(GenesisError),
|
|
||||||
DBError(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BeaconChain<T: ClientDB + Sized> {
|
|
||||||
/// The last slot which has been finalized, this is common to all forks.
|
|
||||||
pub last_finalized_slot: u64,
|
|
||||||
/// 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,
|
|
||||||
/// An in-memory map of root hash to beacon state.
|
|
||||||
pub beacon_states: HashMap<Hash256, BeaconState>,
|
|
||||||
/// 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 spec: ChainSpec,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> BeaconChain<T>
|
|
||||||
where
|
|
||||||
T: ClientDB + Sized,
|
|
||||||
{
|
|
||||||
pub fn new(store: BeaconChainStore<T>, spec: ChainSpec) -> Result<Self, BeaconChainError> {
|
|
||||||
if spec.initial_validators.is_empty() {
|
|
||||||
return Err(BeaconChainError::InsufficientValidators);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 head_block_hashes = vec![canonical_latest_block_hash];
|
|
||||||
let canonical_head_block_hash = 0;
|
|
||||||
|
|
||||||
let mut attester_proposer_maps = HashMap::new();
|
|
||||||
|
|
||||||
let (attester_map, proposer_map) = generate_attester_and_proposer_maps(
|
|
||||||
&genesis_state.shard_committees_at_slots,
|
|
||||||
0,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
attester_proposer_maps.insert(
|
|
||||||
canonical_latest_block_hash,
|
|
||||||
(Arc::new(attester_map), Arc::new(proposer_map)),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
last_finalized_slot: 0,
|
|
||||||
head_block_hashes,
|
|
||||||
canonical_head_block_hash,
|
|
||||||
beacon_states,
|
|
||||||
attester_proposer_maps,
|
|
||||||
store,
|
|
||||||
spec,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn canonical_block_hash(&self) -> Hash256 {
|
|
||||||
self.head_block_hashes[self.canonical_head_block_hash]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AttesterAndProposerMapError> for BeaconChainError {
|
|
||||||
fn from(e: AttesterAndProposerMapError) -> BeaconChainError {
|
|
||||||
BeaconChainError::UnableToGenerateMaps(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<GenesisError> for BeaconChainError {
|
|
||||||
fn from(e: GenesisError) -> BeaconChainError {
|
|
||||||
BeaconChainError::GenesisError(e)
|
|
||||||
}
|
|
||||||
}
|
|
17
lighthouse/beacon_chain/Cargo.toml
Normal file
17
lighthouse/beacon_chain/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "chain"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bls = { path = "../../beacon_chain/utils/bls" }
|
||||||
|
db = { path = "../db" }
|
||||||
|
genesis = { path = "../../beacon_chain/genesis" }
|
||||||
|
naive_fork_choice = { path = "../../beacon_chain/naive_fork_choice" }
|
||||||
|
slot_clock = { path = "../../beacon_chain/utils/slot_clock" }
|
||||||
|
spec = { path = "../../beacon_chain/spec" }
|
||||||
|
ssz = { path = "../../beacon_chain/utils/ssz" }
|
||||||
|
types = { path = "../../beacon_chain/types" }
|
||||||
|
validator_induction = { path = "../../beacon_chain/validator_induction" }
|
||||||
|
validator_shuffling = { path = "../../beacon_chain/validator_shuffling" }
|
72
lighthouse/beacon_chain/src/block_processing.rs
Normal file
72
lighthouse/beacon_chain/src/block_processing.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
||||||
|
use slot_clock::TestingSlotClockError;
|
||||||
|
use ssz::{ssz_encode, Encodable};
|
||||||
|
use types::{readers::BeaconBlockReader, Hash256};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Outcome {
|
||||||
|
FutureSlot,
|
||||||
|
Processed,
|
||||||
|
|
||||||
|
NewCanonicalBlock,
|
||||||
|
NewReorgBlock,
|
||||||
|
NewForkBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
DBError(String),
|
||||||
|
NotImplemented,
|
||||||
|
PresentSlotIsNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> BeaconChain<T, U>
|
||||||
|
where
|
||||||
|
T: ClientDB,
|
||||||
|
U: SlotClock,
|
||||||
|
Error: From<<U as SlotClock>::Error>,
|
||||||
|
{
|
||||||
|
pub fn process_block<V>(&mut self, block: &V) -> Result<(Outcome, Hash256), Error>
|
||||||
|
where
|
||||||
|
V: BeaconBlockReader + Encodable + Sized,
|
||||||
|
{
|
||||||
|
let block_root = block.canonical_root();
|
||||||
|
|
||||||
|
let present_slot = self
|
||||||
|
.slot_clock
|
||||||
|
.present_slot()?
|
||||||
|
.ok_or(Error::PresentSlotIsNone)?;
|
||||||
|
|
||||||
|
// Block from future slots (i.e., greater than the present slot) should not be processed.
|
||||||
|
if block.slot() > present_slot {
|
||||||
|
return Ok((Outcome::FutureSlot, block_root));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: block processing has been removed.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/98
|
||||||
|
|
||||||
|
// Update leaf blocks.
|
||||||
|
self.block_store.put(&block_root, &ssz_encode(block)[..])?;
|
||||||
|
if self.leaf_blocks.contains(&block.parent_root()) {
|
||||||
|
self.leaf_blocks.remove(&block.parent_root());
|
||||||
|
}
|
||||||
|
if self.canonical_leaf_block == block.parent_root() {
|
||||||
|
self.canonical_leaf_block = block_root;
|
||||||
|
}
|
||||||
|
self.leaf_blocks.insert(block_root);
|
||||||
|
|
||||||
|
Ok((Outcome::Processed, block_root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DBError> for Error {
|
||||||
|
fn from(e: DBError) -> Error {
|
||||||
|
Error::DBError(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestingSlotClockError> for Error {
|
||||||
|
fn from(_: TestingSlotClockError) -> Error {
|
||||||
|
unreachable!(); // Testing clock never throws an error.
|
||||||
|
}
|
||||||
|
}
|
64
lighthouse/beacon_chain/src/block_production.rs
Normal file
64
lighthouse/beacon_chain/src/block_production.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use super::{BeaconChain, ClientDB, DBError, SlotClock};
|
||||||
|
use slot_clock::TestingSlotClockError;
|
||||||
|
use types::{
|
||||||
|
readers::{BeaconBlockReader, BeaconStateReader},
|
||||||
|
BeaconBlock, BeaconState, Hash256,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
DBError(String),
|
||||||
|
PresentSlotIsNone,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> BeaconChain<T, U>
|
||||||
|
where
|
||||||
|
T: ClientDB,
|
||||||
|
U: SlotClock,
|
||||||
|
Error: From<<U as SlotClock>::Error>,
|
||||||
|
{
|
||||||
|
pub fn produce_block(&mut self) -> Result<(BeaconBlock, BeaconState), Error> {
|
||||||
|
let present_slot = self
|
||||||
|
.slot_clock
|
||||||
|
.present_slot()?
|
||||||
|
.ok_or(Error::PresentSlotIsNone)?;
|
||||||
|
let parent_root = self.canonical_leaf_block;
|
||||||
|
let parent_block = self
|
||||||
|
.block_store
|
||||||
|
.get_deserialized(&parent_root)?
|
||||||
|
.ok_or(Error::DBError("Block not found.".to_string()))?;
|
||||||
|
let parent_state = self
|
||||||
|
.state_store
|
||||||
|
.get_deserialized(&parent_block.state_root())?
|
||||||
|
.ok_or(Error::DBError("State not found.".to_string()))?;
|
||||||
|
|
||||||
|
let mut block = BeaconBlock {
|
||||||
|
slot: present_slot,
|
||||||
|
parent_root,
|
||||||
|
state_root: Hash256::zero(), // Updated after the state is calculated.
|
||||||
|
..parent_block.to_beacon_block()
|
||||||
|
};
|
||||||
|
|
||||||
|
let state = BeaconState {
|
||||||
|
slot: present_slot,
|
||||||
|
..parent_state.to_beacon_state()
|
||||||
|
};
|
||||||
|
let state_root = state.canonical_root();
|
||||||
|
|
||||||
|
block.state_root = state_root;
|
||||||
|
|
||||||
|
Ok((block, state))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DBError> for Error {
|
||||||
|
fn from(e: DBError) -> Error {
|
||||||
|
Error::DBError(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TestingSlotClockError> for Error {
|
||||||
|
fn from(_: TestingSlotClockError) -> Error {
|
||||||
|
unreachable!(); // Testing clock never throws an error.
|
||||||
|
}
|
||||||
|
}
|
83
lighthouse/beacon_chain/src/lib.rs
Normal file
83
lighthouse/beacon_chain/src/lib.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
mod block_processing;
|
||||||
|
mod block_production;
|
||||||
|
mod maps;
|
||||||
|
mod stores;
|
||||||
|
|
||||||
|
use db::{
|
||||||
|
stores::{BeaconBlockStore, BeaconStateStore},
|
||||||
|
ClientDB, DBError,
|
||||||
|
};
|
||||||
|
use genesis::{genesis_beacon_block, genesis_beacon_state, GenesisError};
|
||||||
|
use slot_clock::{SlotClock, TestingSlotClockError};
|
||||||
|
use spec::ChainSpec;
|
||||||
|
use ssz::ssz_encode;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use types::Hash256;
|
||||||
|
|
||||||
|
pub use crate::block_processing::Outcome as BlockProcessingOutcome;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum BeaconChainError {
|
||||||
|
InsufficientValidators,
|
||||||
|
GenesisError(GenesisError),
|
||||||
|
DBError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BeaconChain<T: ClientDB + Sized, U: SlotClock> {
|
||||||
|
pub block_store: Arc<BeaconBlockStore<T>>,
|
||||||
|
pub state_store: Arc<BeaconStateStore<T>>,
|
||||||
|
pub slot_clock: U,
|
||||||
|
pub leaf_blocks: HashSet<Hash256>,
|
||||||
|
pub canonical_leaf_block: Hash256,
|
||||||
|
pub spec: ChainSpec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> BeaconChain<T, U>
|
||||||
|
where
|
||||||
|
T: ClientDB,
|
||||||
|
U: SlotClock,
|
||||||
|
{
|
||||||
|
pub fn genesis(
|
||||||
|
state_store: Arc<BeaconStateStore<T>>,
|
||||||
|
block_store: Arc<BeaconBlockStore<T>>,
|
||||||
|
slot_clock: U,
|
||||||
|
spec: ChainSpec,
|
||||||
|
) -> Result<Self, BeaconChainError> {
|
||||||
|
if spec.initial_validators.is_empty() {
|
||||||
|
return Err(BeaconChainError::InsufficientValidators);
|
||||||
|
}
|
||||||
|
|
||||||
|
let genesis_state = genesis_beacon_state(&spec)?;
|
||||||
|
let state_root = genesis_state.canonical_root();
|
||||||
|
state_store.put(&state_root, &ssz_encode(&genesis_state)[..])?;
|
||||||
|
|
||||||
|
let genesis_block = genesis_beacon_block(state_root, &spec);
|
||||||
|
let block_root = genesis_block.canonical_root();
|
||||||
|
block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?;
|
||||||
|
|
||||||
|
let mut leaf_blocks = HashSet::new();
|
||||||
|
leaf_blocks.insert(block_root.clone());
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
block_store,
|
||||||
|
state_store,
|
||||||
|
slot_clock,
|
||||||
|
leaf_blocks,
|
||||||
|
canonical_leaf_block: block_root,
|
||||||
|
spec,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DBError> for BeaconChainError {
|
||||||
|
fn from(e: DBError) -> BeaconChainError {
|
||||||
|
BeaconChainError::DBError(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GenesisError> for BeaconChainError {
|
||||||
|
fn from(e: GenesisError) -> BeaconChainError {
|
||||||
|
BeaconChainError::GenesisError(e)
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ use db::ClientDB;
|
|||||||
use state_transition::{extend_active_state, StateTransitionError};
|
use state_transition::{extend_active_state, StateTransitionError};
|
||||||
use types::{ActiveState, BeaconBlock, CrystallizedState, Hash256};
|
use types::{ActiveState, BeaconBlock, CrystallizedState, Hash256};
|
||||||
|
|
||||||
impl<T> BeaconChain<T>
|
impl<T, U> BeaconChain<T, U>
|
||||||
where
|
where
|
||||||
T: ClientDB + Sized,
|
T: ClientDB + Sized,
|
||||||
{
|
{
|
49
lighthouse/beacon_chain/tests/chain_test.rs
Normal file
49
lighthouse/beacon_chain/tests/chain_test.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use chain::{BlockProcessingOutcome, BeaconChain};
|
||||||
|
use db::{
|
||||||
|
stores::{BeaconBlockStore, BeaconStateStore},
|
||||||
|
MemoryDB,
|
||||||
|
};
|
||||||
|
use slot_clock::TestingSlotClock;
|
||||||
|
use spec::ChainSpec;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
fn in_memory_test_stores() -> (
|
||||||
|
Arc<MemoryDB>,
|
||||||
|
Arc<BeaconBlockStore<MemoryDB>>,
|
||||||
|
Arc<BeaconStateStore<MemoryDB>>,
|
||||||
|
) {
|
||||||
|
let db = Arc::new(MemoryDB::open());
|
||||||
|
let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
|
||||||
|
let state_store = Arc::new(BeaconStateStore::new(db.clone()));
|
||||||
|
(db, block_store, state_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_memory_test_chain(
|
||||||
|
spec: ChainSpec,
|
||||||
|
) -> (Arc<MemoryDB>, BeaconChain<MemoryDB, TestingSlotClock>) {
|
||||||
|
let (db, block_store, state_store) = in_memory_test_stores();
|
||||||
|
let slot_clock = TestingSlotClock::new(0);
|
||||||
|
|
||||||
|
let chain = BeaconChain::genesis(state_store, block_store, slot_clock, spec);
|
||||||
|
(db, chain.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_constructs() {
|
||||||
|
let (_db, _chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_produces() {
|
||||||
|
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||||
|
let (_block, _state) = chain.produce_block().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_processes_a_block_it_produces() {
|
||||||
|
let (_db, mut chain) = in_memory_test_chain(ChainSpec::foundation());
|
||||||
|
let (block, _state) = chain.produce_block().unwrap();
|
||||||
|
let (outcome, new_block_hash) = chain.process_block(&block).unwrap();
|
||||||
|
assert_eq!(outcome, BlockProcessingOutcome::Processed);
|
||||||
|
assert_eq!(chain.canonical_leaf_block, new_block_hash);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user