Add progress on test rig

This commit is contained in:
Paul Hauner
2019-01-24 17:05:48 +11:00
parent b29934aed4
commit 6fd3a1a03e
19 changed files with 595 additions and 144 deletions

View File

@@ -0,0 +1,50 @@
use crate::{BeaconChain, CheckPoint, ClientDB, SlotClock};
use std::collections::HashMap;
use std::sync::RwLockReadGuard;
use types::{BeaconBlock, BeaconState, Hash256};
pub struct AttestationTargets {
map: HashMap<u64, Hash256>,
}
impl AttestationTargets {
pub fn new() -> Self {
Self {
map: HashMap::new(),
}
}
pub fn get(&self, validator_index: u64) -> Option<&Hash256> {
self.map.get(&validator_index)
}
pub fn insert(&mut self, validator_index: u64, block_hash: Hash256) -> Option<Hash256> {
self.map.insert(validator_index, block_hash)
}
}
impl<T, U> BeaconChain<T, U>
where
T: ClientDB,
U: SlotClock,
{
pub fn insert_latest_attestation_target(&self, validator_index: u64, block_root: Hash256) {
let mut targets = self
.latest_attestation_targets
.write()
.expect("CRITICAL: CanonicalHead poisioned.");
targets.insert(validator_index, block_root);
}
pub fn get_latest_attestation_target(&self, validator_index: u64) -> Option<Hash256> {
let targets = self
.latest_attestation_targets
.read()
.expect("CRITICAL: CanonicalHead poisioned.");
match targets.get(validator_index) {
Some(hash) => Some(hash.clone()),
None => None,
}
}
}

View File

@@ -0,0 +1,37 @@
use crate::{BeaconChain, CheckPoint, ClientDB, SlotClock};
use std::collections::HashSet;
use std::sync::{RwLock, RwLockReadGuard};
use types::{BeaconBlock, BeaconState, Hash256};
pub struct BlockGraph {
pub leaves: RwLock<HashSet<Hash256>>,
}
impl BlockGraph {
pub fn new() -> Self {
Self {
leaves: RwLock::new(HashSet::new()),
}
}
/// Add a new leaf to the block hash graph. Returns `true` if the leaf was built upon another
/// leaf.
pub fn add_leaf(&self, parent: &Hash256, leaf: Hash256) -> bool {
let mut leaves = self
.leaves
.write()
.expect("CRITICAL: BlockGraph poisioned.");
if leaves.contains(parent) {
leaves.remove(parent);
leaves.insert(leaf);
true
} else {
leaves.insert(leaf);
false
}
}
pub fn leaves(&self) -> RwLockReadGuard<HashSet<Hash256>> {
self.leaves.read().expect("CRITICAL: BlockGraph poisioned.")
}
}

View File

@@ -54,7 +54,7 @@ where
U: SlotClock,
Error: From<<U as SlotClock>::Error>,
{
pub fn process_block<V>(&mut self, block: V) -> Result<Outcome, Error>
pub fn process_block<V>(&self, block: V) -> Result<Outcome, Error>
where
V: BeaconBlockReader + Encodable + Sized,
{
@@ -103,14 +103,20 @@ where
self.block_store.put(&block_root, &ssz_encode(&block)[..])?;
self.state_store.put(&state_root, &ssz_encode(&state)[..])?;
// Update leaf blocks so the implementation can track the chain heads.
if self.leaf_blocks.contains(&block.parent_root()) {
self.leaf_blocks.remove(&block.parent_root());
self.block_graph
.add_leaf(&parent_block_root, block_root.clone());
// If the parent block was the parent_block, automatically update the canonical head.
//
// TODO: this is a first-in-best-dressed scenario that is not ideal -- find a solution.
if self.canonical_head().beacon_block_root == parent_block_root {
self.update_canonical_head(
block.clone(),
block_root.clone(),
state.clone(),
state_root.clone(),
);
}
if self.canonical_leaf_block == block.parent_root() {
self.canonical_leaf_block = block_root;
}
self.leaf_blocks.insert(block_root);
// The block was sucessfully processed.
Ok(Outcome::Processed)

View File

@@ -18,18 +18,22 @@ impl<T, U> BeaconChain<T, U>
where
T: ClientDB,
U: SlotClock,
Error: From<<U as SlotClock>::Error>,
{
pub fn produce_block(
&mut self,
&self,
randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState), Error> {
) -> Result<(BeaconBlock, BeaconState), Error>
where
Error: From<<U>::Error>,
{
// TODO: allow producing a block from a previous (or future?) slot.
let present_slot = self
.slot_clock
.present_slot()?
.present_slot()
.map_err(|e| e.into())?
.ok_or(Error::PresentSlotIsNone)?;
let parent_root = self.canonical_leaf_block;
let parent_root = self.canonical_head().beacon_block_root;
let parent_block_reader = self
.block_store
.get_reader(&parent_root)?
@@ -43,7 +47,7 @@ where
let mut block = BeaconBlock {
slot: present_slot,
parent_root,
parent_root: parent_root.clone(),
state_root: Hash256::zero(), // Updated after the state is calculated.
randao_reveal: randao_reveal,
eth1_data: Eth1Data {

View File

@@ -0,0 +1,34 @@
use crate::{BeaconChain, CheckPoint, ClientDB, SlotClock};
use std::sync::RwLockReadGuard;
use types::{BeaconBlock, BeaconState, Hash256};
impl<T, U> BeaconChain<T, U>
where
T: ClientDB,
U: SlotClock,
{
pub fn update_canonical_head(
&self,
new_beacon_block: BeaconBlock,
new_beacon_block_root: Hash256,
new_beacon_state: BeaconState,
new_beacon_state_root: Hash256,
) {
let mut canonical_head = self
.canonical_head
.write()
.expect("CRITICAL: CanonicalHead poisioned.");
canonical_head.update(
new_beacon_block,
new_beacon_block_root,
new_beacon_state,
new_beacon_state_root,
);
}
pub fn canonical_head(&self) -> RwLockReadGuard<CheckPoint> {
self.canonical_head
.read()
.expect("CRITICAL: CanonicalHead poisioned.")
}
}

View File

@@ -0,0 +1,49 @@
use super::{BeaconChain, ClientDB, SlotClock};
use types::PublicKey;
impl<T, U> BeaconChain<T, U>
where
T: ClientDB,
U: SlotClock,
{
pub fn validator_index(&self, pubkey: &PublicKey) -> Option<usize> {
for (i, validator) in self
.canonical_head()
.beacon_state
.validator_registry
.iter()
.enumerate()
{
if validator.pubkey == *pubkey {
return Some(i);
}
}
None
}
pub fn proposer_slots(&self, validator_index: usize) -> Option<u64> {
if let Some(validator) = self
.canonical_head()
.beacon_state
.validator_registry
.get(validator_index)
{
Some(validator.proposer_slots)
} else {
None
}
}
pub fn present_slot(&self) -> Option<u64> {
match self.slot_clock.present_slot() {
Ok(some_slot) => some_slot,
_ => None,
}
}
pub fn block_proposer(&self, slot: u64) -> Option<usize> {
//TODO: this is a stub; fix.
let validator_count = self.canonical_head().beacon_state.validator_registry.len();
Some((slot as usize) % validator_count)
}
}

View File

@@ -1,8 +1,14 @@
mod attestation_targets;
mod block_graph;
mod block_processing;
mod block_production;
pub mod block_production;
mod canonical_head;
mod info;
mod lmd_ghost;
mod state_transition;
use self::attestation_targets::AttestationTargets;
use self::block_graph::BlockGraph;
use db::{
stores::{BeaconBlockStore, BeaconStateStore},
ClientDB, DBError,
@@ -12,18 +18,11 @@ use slot_clock::SlotClock;
use spec::ChainSpec;
use ssz::ssz_encode;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use types::Hash256;
use std::sync::{Arc, RwLock};
use types::{BeaconBlock, BeaconState, Hash256, PublicKey};
pub use self::block_processing::Outcome as BlockProcessingOutcome;
#[derive(Debug, PartialEq)]
pub struct CheckPoint {
block_root: Hash256,
state_root: Hash256,
slot: u64,
}
#[derive(Debug, PartialEq)]
pub enum BeaconChainError {
InsufficientValidators,
@@ -31,15 +30,51 @@ pub enum BeaconChainError {
DBError(String),
}
pub struct CheckPoint {
beacon_block: BeaconBlock,
beacon_block_root: Hash256,
beacon_state: BeaconState,
beacon_state_root: Hash256,
}
impl CheckPoint {
pub fn new(
beacon_block: BeaconBlock,
beacon_block_root: Hash256,
beacon_state: BeaconState,
beacon_state_root: Hash256,
) -> Self {
Self {
beacon_block,
beacon_block_root,
beacon_state,
beacon_state_root,
}
}
pub fn update(
&mut self,
beacon_block: BeaconBlock,
beacon_block_root: Hash256,
beacon_state: BeaconState,
beacon_state_root: Hash256,
) {
self.beacon_block = beacon_block;
self.beacon_block_root = beacon_block_root;
self.beacon_state = beacon_state;
self.beacon_state_root = beacon_state_root;
}
}
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 block_graph: BlockGraph,
canonical_head: RwLock<CheckPoint>,
finalized_head: RwLock<CheckPoint>,
pub latest_attestation_targets: RwLock<AttestationTargets>,
pub spec: ChainSpec,
latest_attestation_targets: HashMap<usize, Hash256>,
finalized_checkpoint: CheckPoint,
}
impl<T, U> BeaconChain<T, U>
@@ -65,24 +100,33 @@ where
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);
let block_graph = BlockGraph::new();
block_graph.add_leaf(&Hash256::zero(), block_root.clone());
let finalized_checkpoint = CheckPoint {
block_root,
state_root,
slot: genesis_block.slot,
};
let finalized_head = RwLock::new(CheckPoint::new(
genesis_block.clone(),
block_root.clone(),
genesis_state.clone(),
state_root.clone(),
));
let canonical_head = RwLock::new(CheckPoint::new(
genesis_block.clone(),
block_root.clone(),
genesis_state.clone(),
state_root.clone(),
));
let latest_attestation_targets = RwLock::new(AttestationTargets::new());
Ok(Self {
block_store,
state_store,
slot_clock,
leaf_blocks,
canonical_leaf_block: block_root,
spec,
latest_attestation_targets: HashMap::new(),
finalized_checkpoint,
block_graph,
finalized_head,
canonical_head,
latest_attestation_targets,
spec: spec,
})
}
}

View File

@@ -4,13 +4,12 @@ use db::{
ClientDB, DBError,
};
use slot_clock::TestingSlotClockError;
use ssz::{ssz_encode, Encodable};
use std::collections::HashSet;
use std::sync::Arc;
use types::{
readers::{BeaconBlockReader, BeaconStateReader},
validator_registry::get_active_validator_indices,
BeaconBlock, Hash256,
Hash256,
};
#[derive(Debug, PartialEq)]
@@ -53,7 +52,7 @@ where
let mut attestation_targets = Vec::with_capacity(active_validator_indices.len());
for i in active_validator_indices {
if let Some(target) = self.latest_attestation_targets.get(&i) {
if let Some(target) = self.get_latest_attestation_target(i as u64) {
attestation_targets.push(target);
}
}
@@ -62,8 +61,11 @@ where
let mut head_vote_count = 0;
loop {
let child_hashes_and_slots =
get_child_hashes_and_slots(&self.block_store, &head_hash, &self.leaf_blocks)?;
let child_hashes_and_slots = get_child_hashes_and_slots(
&self.block_store,
&head_hash,
&self.block_graph.leaves(),
)?;
if child_hashes_and_slots.len() == 0 {
break;
@@ -90,7 +92,7 @@ where
fn get_vote_count<T: ClientDB>(
block_store: &Arc<BeaconBlockStore<T>>,
attestation_targets: &[&Hash256],
attestation_targets: &[Hash256],
block_root: &Hash256,
slot: u64,
) -> Result<u64, Error> {
@@ -99,7 +101,7 @@ fn get_vote_count<T: ClientDB>(
let (root_at_slot, _) = block_store
.block_at_slot(&block_root, slot)?
.ok_or(Error::MissingBeaconBlock(*block_root))?;
if root_at_slot == *block_root {
if root_at_slot == *target {
count += 1;
}
}