Remove block_graph from beacon_chain.
This commit is contained in:
parent
03a5a892d0
commit
ef1717312f
@ -17,7 +17,6 @@ use types::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::attestation_aggregator::{AttestationAggregator, Outcome as AggregationOutcome};
|
use crate::attestation_aggregator::{AttestationAggregator, Outcome as AggregationOutcome};
|
||||||
use crate::block_graph::BlockGraph;
|
|
||||||
use crate::checkpoint::CheckPoint;
|
use crate::checkpoint::CheckPoint;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -65,7 +64,6 @@ pub struct BeaconChain<T: ClientDB + Sized, U: SlotClock, F: ForkChoice> {
|
|||||||
pub block_store: Arc<BeaconBlockStore<T>>,
|
pub block_store: Arc<BeaconBlockStore<T>>,
|
||||||
pub state_store: Arc<BeaconStateStore<T>>,
|
pub state_store: Arc<BeaconStateStore<T>>,
|
||||||
pub slot_clock: U,
|
pub slot_clock: U,
|
||||||
pub block_graph: BlockGraph,
|
|
||||||
pub attestation_aggregator: RwLock<AttestationAggregator>,
|
pub attestation_aggregator: RwLock<AttestationAggregator>,
|
||||||
canonical_head: RwLock<CheckPoint>,
|
canonical_head: RwLock<CheckPoint>,
|
||||||
finalized_head: RwLock<CheckPoint>,
|
finalized_head: RwLock<CheckPoint>,
|
||||||
@ -101,9 +99,6 @@ where
|
|||||||
let block_root = genesis_block.canonical_root();
|
let block_root = genesis_block.canonical_root();
|
||||||
block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?;
|
block_store.put(&block_root, &ssz_encode(&genesis_block)[..])?;
|
||||||
|
|
||||||
let block_graph = BlockGraph::new();
|
|
||||||
block_graph.add_leaf(&Hash256::zero(), block_root);
|
|
||||||
|
|
||||||
let finalized_head = RwLock::new(CheckPoint::new(
|
let finalized_head = RwLock::new(CheckPoint::new(
|
||||||
genesis_block.clone(),
|
genesis_block.clone(),
|
||||||
block_root,
|
block_root,
|
||||||
@ -128,7 +123,6 @@ where
|
|||||||
block_store,
|
block_store,
|
||||||
state_store,
|
state_store,
|
||||||
slot_clock,
|
slot_clock,
|
||||||
block_graph,
|
|
||||||
attestation_aggregator,
|
attestation_aggregator,
|
||||||
state: RwLock::new(genesis_state.clone()),
|
state: RwLock::new(genesis_state.clone()),
|
||||||
justified_head,
|
justified_head,
|
||||||
@ -484,9 +478,6 @@ where
|
|||||||
self.block_store.put(&block_root, &ssz_encode(&block)[..])?;
|
self.block_store.put(&block_root, &ssz_encode(&block)[..])?;
|
||||||
self.state_store.put(&state_root, &ssz_encode(&state)[..])?;
|
self.state_store.put(&state_root, &ssz_encode(&state)[..])?;
|
||||||
|
|
||||||
// Update the block DAG.
|
|
||||||
self.block_graph.add_leaf(&parent_block_root, block_root);
|
|
||||||
|
|
||||||
// run the fork_choice add_block logic
|
// run the fork_choice add_block logic
|
||||||
self.fork_choice.add_block(&block, &block_root)?;
|
self.fork_choice.add_block(&block, &block_root)?;
|
||||||
|
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
use parking_lot::{RwLock, RwLockReadGuard};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use types::Hash256;
|
|
||||||
|
|
||||||
/// Maintains a view of the block DAG, also known as the "blockchain" (except, it tracks multiple
|
|
||||||
/// chains eminating from a single root instead of just the head of some canonical chain).
|
|
||||||
///
|
|
||||||
/// The BlockGraph does not store the blocks, instead it tracks the block hashes of blocks at the
|
|
||||||
/// tip of the DAG. It is out of the scope of the object to retrieve blocks.
|
|
||||||
///
|
|
||||||
/// Presently, the DAG root (genesis block) is not tracked.
|
|
||||||
///
|
|
||||||
/// The BlogGraph is thread-safe due to internal RwLocks.
|
|
||||||
pub struct BlockGraph {
|
|
||||||
pub leaves: RwLock<HashSet<Hash256>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockGraph {
|
|
||||||
/// Create a new block graph without any leaves.
|
|
||||||
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();
|
|
||||||
|
|
||||||
if leaves.contains(parent) {
|
|
||||||
leaves.remove(parent);
|
|
||||||
leaves.insert(leaf);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
leaves.insert(leaf);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a read-guarded HashSet of all leaf blocks.
|
|
||||||
pub fn leaves(&self) -> RwLockReadGuard<HashSet<Hash256>> {
|
|
||||||
self.leaves.read()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
extern crate db;
|
|
||||||
|
|
||||||
// TODO: Pull out the dependency on self and beacon_chain
|
|
||||||
|
|
||||||
/*
|
|
||||||
use db::{
|
|
||||||
stores::{BeaconBlockAtSlotError, BeaconBlockStore},
|
|
||||||
ClientDB, DBError,
|
|
||||||
};
|
|
||||||
use slot_clock::{SlotClock, TestingSlotClockError};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use types::{
|
|
||||||
readers::{BeaconBlockReader, BeaconStateReader},
|
|
||||||
validator_registry::get_active_validator_indices,
|
|
||||||
Hash256,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
DBError(String),
|
|
||||||
MissingBeaconState(Hash256),
|
|
||||||
InvalidBeaconState(Hash256),
|
|
||||||
MissingBeaconBlock(Hash256),
|
|
||||||
InvalidBeaconBlock(Hash256),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A very inefficient implementation of LMD ghost.
|
|
||||||
pub fn slow_lmd_ghost(&self, start_hash: &Hash256) -> Result<Hash256, Error> {
|
|
||||||
let start = self
|
|
||||||
.block_store
|
|
||||||
.get_reader(&start_hash)?
|
|
||||||
.ok_or(Error::MissingBeaconBlock(*start_hash))?;
|
|
||||||
|
|
||||||
let start_state_root = start.state_root();
|
|
||||||
|
|
||||||
let state = self
|
|
||||||
.state_store
|
|
||||||
.get_reader(&start_state_root)?
|
|
||||||
.ok_or(Error::MissingBeaconState(start_state_root))?
|
|
||||||
.into_beacon_state()
|
|
||||||
.ok_or(Error::InvalidBeaconState(start_state_root))?;
|
|
||||||
|
|
||||||
let active_validator_indices =
|
|
||||||
get_active_validator_indices(&state.validator_registry, start.slot());
|
|
||||||
|
|
||||||
let mut attestation_targets = Vec::with_capacity(active_validator_indices.len());
|
|
||||||
for i in active_validator_indices {
|
|
||||||
if let Some(target) = self.get_latest_attestation_target(i as u64) {
|
|
||||||
attestation_targets.push(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut head_hash = Hash256::zero();
|
|
||||||
let mut head_vote_count = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (child_hash, child_slot) in child_hashes_and_slots {
|
|
||||||
let vote_count = get_vote_count(
|
|
||||||
&self.block_store,
|
|
||||||
&attestation_targets[..],
|
|
||||||
&child_hash,
|
|
||||||
child_slot,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if vote_count > head_vote_count {
|
|
||||||
head_hash = child_hash;
|
|
||||||
head_vote_count = vote_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(head_hash)
|
|
||||||
}
|
|
||||||
/// Get the total number of votes for some given block root.
|
|
||||||
///
|
|
||||||
/// The vote count is incrememented each time an attestation target votes for a block root.
|
|
||||||
fn get_vote_count<T: ClientDB>(
|
|
||||||
block_store: &Arc<BeaconBlockStore<T>>,
|
|
||||||
attestation_targets: &[Hash256],
|
|
||||||
block_root: &Hash256,
|
|
||||||
slot: u64,
|
|
||||||
) -> Result<u64, Error> {
|
|
||||||
let mut count = 0;
|
|
||||||
for target in attestation_targets {
|
|
||||||
let (root_at_slot, _) = block_store
|
|
||||||
.block_at_slot(&block_root, slot)?
|
|
||||||
.ok_or(Error::MissingBeaconBlock(*block_root))?;
|
|
||||||
if root_at_slot == *target {
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(count)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Starting from some `leaf_hashes`, recurse back down each branch until the `root_hash`, adding
|
|
||||||
/// each `block_root` and `slot` to a HashSet.
|
|
||||||
fn get_child_hashes_and_slots<T: ClientDB>(
|
|
||||||
block_store: &Arc<BeaconBlockStore<T>>,
|
|
||||||
root_hash: &Hash256,
|
|
||||||
leaf_hashes: &HashSet<Hash256>,
|
|
||||||
) -> Result<HashSet<(Hash256, u64)>, Error> {
|
|
||||||
let mut hash_set = HashSet::new();
|
|
||||||
|
|
||||||
for leaf_hash in leaf_hashes {
|
|
||||||
let mut current_hash = *leaf_hash;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let Some(block_reader) = block_store.get_reader(¤t_hash)? {
|
|
||||||
let parent_root = block_reader.parent_root();
|
|
||||||
|
|
||||||
let new_hash = hash_set.insert((current_hash, block_reader.slot()));
|
|
||||||
|
|
||||||
// If the hash just added was already in the set, break the loop.
|
|
||||||
//
|
|
||||||
// In such a case, the present branch has merged with a branch that is already in
|
|
||||||
// the set.
|
|
||||||
if !new_hash {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The branch is exhausted if the parent of this block is the root_hash.
|
|
||||||
if parent_root == *root_hash {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
current_hash = parent_root.clone();
|
|
||||||
} else {
|
|
||||||
return Err(Error::MissingBeaconBlock(current_hash));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(hash_set)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DBError> for Error {
|
|
||||||
fn from(e: DBError) -> Error {
|
|
||||||
Error::DBError(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BeaconBlockAtSlotError> for Error {
|
|
||||||
fn from(e: BeaconBlockAtSlotError) -> Error {
|
|
||||||
match e {
|
|
||||||
BeaconBlockAtSlotError::UnknownBeaconBlock(h) => Error::MissingBeaconBlock(h),
|
|
||||||
BeaconBlockAtSlotError::InvalidBeaconBlock(h) => Error::InvalidBeaconBlock(h),
|
|
||||||
BeaconBlockAtSlotError::DBError(msg) => Error::DBError(msg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TestingSlotClockError> for Error {
|
|
||||||
fn from(_: TestingSlotClockError) -> Error {
|
|
||||||
unreachable!(); // Testing clock never throws an error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
@ -18,10 +18,10 @@
|
|||||||
//! [`optimised_lmd_ghost`]: struct.OptimisedLmdGhost.html
|
//! [`optimised_lmd_ghost`]: struct.OptimisedLmdGhost.html
|
||||||
//! [`protolambda_lmd_ghost`]: struct.ProtolambdaLmdGhost.html
|
//! [`protolambda_lmd_ghost`]: struct.ProtolambdaLmdGhost.html
|
||||||
|
|
||||||
pub mod basic_lmd_ghost;
|
|
||||||
pub mod longest_chain;
|
pub mod longest_chain;
|
||||||
pub mod optimised_lmd_ghost;
|
pub mod optimised_lmd_ghost;
|
||||||
pub mod protolambda_lmd_ghost;
|
pub mod protolambda_lmd_ghost;
|
||||||
|
pub mod slow_lmd_ghost;
|
||||||
|
|
||||||
use db::DBError;
|
use db::DBError;
|
||||||
use types::{BeaconBlock, Hash256};
|
use types::{BeaconBlock, Hash256};
|
||||||
@ -71,7 +71,7 @@ pub enum ForkChoiceAlgorithms {
|
|||||||
/// Chooses the longest chain becomes the head. Not for production.
|
/// Chooses the longest chain becomes the head. Not for production.
|
||||||
LongestChain,
|
LongestChain,
|
||||||
/// A simple and highly inefficient implementation of LMD ghost.
|
/// A simple and highly inefficient implementation of LMD ghost.
|
||||||
BasicLMDGhost,
|
SlowLMDGhost,
|
||||||
/// An optimised version of LMD-GHOST by Vitalik.
|
/// An optimised version of LMD-GHOST by Vitalik.
|
||||||
OptimmisedLMDGhost,
|
OptimmisedLMDGhost,
|
||||||
/// An optimised version of LMD-GHOST by Protolambda.
|
/// An optimised version of LMD-GHOST by Protolambda.
|
||||||
|
@ -71,6 +71,42 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the latest votes weighted by validator balance. Returns a hashmap of block_hash to
|
||||||
|
/// weighted votes.
|
||||||
|
pub fn get_latest_votes(
|
||||||
|
state_root: &Hash256,
|
||||||
|
block_slot: &Hash256,
|
||||||
|
) -> Result<HashMap<Has256, u64>, ForkChoiceError> {
|
||||||
|
// get latest votes
|
||||||
|
// Note: Votes are weighted by min(balance, MAX_DEPOSIT_AMOUNT) //
|
||||||
|
// FORK_CHOICE_BALANCE_INCREMENT
|
||||||
|
// build a hashmap of block_hash to weighted votes
|
||||||
|
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
|
||||||
|
// gets the current weighted votes
|
||||||
|
let current_state = self
|
||||||
|
.state_store
|
||||||
|
.get_reader(&state_root)?
|
||||||
|
.ok_or_else(|| ForkChoiceError::MissingBeaconState(state_root))?
|
||||||
|
.into_beacon_state()
|
||||||
|
.ok_or_else(|| ForkChoiceError::IncorrectBeaconState(state_root))?;
|
||||||
|
|
||||||
|
let active_validator_indices =
|
||||||
|
get_active_validator_indices(¤t_state.validator_registry, block_slot);
|
||||||
|
|
||||||
|
for index in active_validator_indices {
|
||||||
|
let balance =
|
||||||
|
std::cmp::min(current_state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
||||||
|
/ FORK_CHOICE_BALANCE_INCREMENT;
|
||||||
|
if balance > 0 {
|
||||||
|
if let Some(target) = self.latest_attestation_targets.get(&(index as u64)) {
|
||||||
|
*latest_votes.entry(*target).or_insert_with(|| 0) += balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(latest_votes)
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the ancestor at a given height `at_height` of a block specified by `block_hash`.
|
/// Gets the ancestor at a given height `at_height` of a block specified by `block_hash`.
|
||||||
fn get_ancestor(&mut self, block_hash: Hash256, at_height: u32) -> Option<Hash256> {
|
fn get_ancestor(&mut self, block_hash: Hash256, at_height: u32) -> Option<Hash256> {
|
||||||
// return None if we can't get the block from the db.
|
// return None if we can't get the block from the db.
|
||||||
@ -271,43 +307,15 @@ impl<T: ClientDB + Sized> ForkChoice for OptimisedLMDGhost<T> {
|
|||||||
.block_store
|
.block_store
|
||||||
.get_reader(&justified_block_start)?
|
.get_reader(&justified_block_start)?
|
||||||
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*justified_block_start))?;
|
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*justified_block_start))?;
|
||||||
//.into_beacon_block()?;
|
|
||||||
|
|
||||||
let block_slot = block.slot();
|
let block_slot = block.slot();
|
||||||
let block_height = block_slot - GENESIS_SLOT;
|
let block_height = block_slot - GENESIS_SLOT;
|
||||||
let state_root = block.state_root();
|
let state_root = block.state_root();
|
||||||
|
|
||||||
// get latest votes
|
|
||||||
// Note: Votes are weighted by min(balance, MAX_DEPOSIT_AMOUNT) //
|
|
||||||
// FORK_CHOICE_BALANCE_INCREMENT
|
|
||||||
// build a hashmap of block_hash to weighted votes
|
|
||||||
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
|
|
||||||
// gets the current weighted votes
|
|
||||||
{
|
|
||||||
let current_state = self
|
|
||||||
.state_store
|
|
||||||
.get_reader(&state_root)?
|
|
||||||
.ok_or_else(|| ForkChoiceError::MissingBeaconState(state_root))?
|
|
||||||
.into_beacon_state()
|
|
||||||
.ok_or_else(|| ForkChoiceError::IncorrectBeaconState(state_root))?;
|
|
||||||
|
|
||||||
let active_validator_indices =
|
|
||||||
get_active_validator_indices(¤t_state.validator_registry, block_slot);
|
|
||||||
|
|
||||||
for index in active_validator_indices {
|
|
||||||
let balance =
|
|
||||||
std::cmp::min(current_state.validator_balances[index], MAX_DEPOSIT_AMOUNT)
|
|
||||||
/ FORK_CHOICE_BALANCE_INCREMENT;
|
|
||||||
if balance > 0 {
|
|
||||||
if let Some(target) = self.latest_attestation_targets.get(&(index as u64)) {
|
|
||||||
*latest_votes.entry(*target).or_insert_with(|| 0) += balance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut current_head = *justified_block_start;
|
let mut current_head = *justified_block_start;
|
||||||
|
|
||||||
|
let mut latest_votes = self.get_latest_votes(&state_root, &block_slot)?;
|
||||||
|
|
||||||
// remove any votes that don't relate to our current head.
|
// remove any votes that don't relate to our current head.
|
||||||
latest_votes
|
latest_votes
|
||||||
.retain(|hash, _| self.get_ancestor(*hash, block_height as u32) == Some(current_head));
|
.retain(|hash, _| self.get_ancestor(*hash, block_height as u32) == Some(current_head));
|
||||||
|
Loading…
Reference in New Issue
Block a user