Merge branch 'master' into v0.6.1

This commit is contained in:
Paul Hauner
2019-06-02 13:49:24 +10:00
67 changed files with 1663 additions and 1634 deletions

View File

@@ -5,7 +5,7 @@ authors = ["Age Manning <Age@AgeManning.com>"]
edition = "2018"
[dependencies]
db = { path = "../../beacon_node/db" }
store = { path = "../../beacon_node/store" }
ssz = { path = "../utils/ssz" }
types = { path = "../types" }
log = "0.4.6"

View File

@@ -1,16 +1,11 @@
//! The optimised bitwise LMD-GHOST fork choice rule.
extern crate bit_vec;
use crate::{ForkChoice, ForkChoiceError};
use bit_vec::BitVec;
use db::{
stores::{BeaconBlockStore, BeaconStateStore},
ClientDB,
};
use log::{debug, trace};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use store::Store;
use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot, SlotHeight};
//TODO: Pruning - Children
@@ -34,7 +29,7 @@ fn power_of_2_below(x: u64) -> u64 {
}
/// Stores the necessary data structures to run the optimised bitwise lmd ghost algorithm.
pub struct BitwiseLMDGhost<T: ClientDB + Sized, E> {
pub struct BitwiseLMDGhost<T, E> {
/// A cache of known ancestors at given heights for a specific block.
//TODO: Consider FnvHashMap
cache: HashMap<CacheKey<u64>, Hash256>,
@@ -46,30 +41,21 @@ pub struct BitwiseLMDGhost<T: ClientDB + Sized, E> {
/// The latest attestation targets as a map of validator index to block hash.
//TODO: Could this be a fixed size vec
latest_attestation_targets: HashMap<u64, Hash256>,
/// Block storage access.
block_store: Arc<BeaconBlockStore<T>>,
/// State storage access.
state_store: Arc<BeaconStateStore<T>>,
/// Block and state storage.
store: Arc<T>,
max_known_height: SlotHeight,
_phantom: PhantomData<E>,
}
impl<T, E: EthSpec> BitwiseLMDGhost<T, E>
where
T: ClientDB + Sized,
{
pub fn new(
block_store: Arc<BeaconBlockStore<T>>,
state_store: Arc<BeaconStateStore<T>>,
) -> Self {
impl<T: Store, E: EthSpec> BitwiseLMDGhost<T, E> {
pub fn new(store: Arc<T>) -> Self {
BitwiseLMDGhost {
cache: HashMap::new(),
ancestors: vec![HashMap::new(); 16],
latest_attestation_targets: HashMap::new(),
children: HashMap::new(),
max_known_height: SlotHeight::new(0),
block_store,
state_store,
store,
_phantom: PhantomData,
}
}
@@ -89,8 +75,8 @@ where
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes
let current_state: BeaconState<E> = self
.state_store
.get_deserialized(&state_root)?
.store
.get(&state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
let active_validator_indices =
@@ -121,8 +107,8 @@ where
// return None if we can't get the block from the db.
let block_height = {
let block_slot = self
.block_store
.get_deserialized(&block_hash)
.store
.get::<BeaconBlock>(&block_hash)
.ok()?
.expect("Should have returned already if None")
.slot;
@@ -243,7 +229,7 @@ where
}
}
impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
impl<T: Store, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
fn add_block(
&mut self,
block: &BeaconBlock,
@@ -252,8 +238,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
) -> Result<(), ForkChoiceError> {
// get the height of the parent
let parent_height = self
.block_store
.get_deserialized(&block.previous_block_root)?
.store
.get::<BeaconBlock>(&block.previous_block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(block.previous_block_root))?
.slot
.height(spec.genesis_slot);
@@ -304,16 +290,16 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
trace!("Old attestation found: {:?}", attestation_target);
// get the height of the target block
let block_height = self
.block_store
.get_deserialized(&target_block_root)?
.store
.get::<BeaconBlock>(&target_block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*target_block_root))?
.slot
.height(spec.genesis_slot);
// get the height of the past target block
let past_block_height = self
.block_store
.get_deserialized(&attestation_target)?
.store
.get::<BeaconBlock>(&attestation_target)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*attestation_target))?
.slot
.height(spec.genesis_slot);
@@ -337,8 +323,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
justified_block_start
);
let block = self
.block_store
.get_deserialized(&justified_block_start)?
.store
.get::<BeaconBlock>(&justified_block_start)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*justified_block_start))?;
let block_slot = block.slot;
@@ -429,8 +415,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for BitwiseLMDGhost<T, E> {
// didn't find head yet, proceed to next iteration
// update block height
block_height = self
.block_store
.get_deserialized(&current_head)?
.store
.get::<BeaconBlock>(&current_head)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(current_head))?
.slot
.height(spec.genesis_slot);

View File

@@ -16,17 +16,14 @@
//! [`slow_lmd_ghost`]: struct.SlowLmdGhost.html
//! [`bitwise_lmd_ghost`]: struct.OptimisedLmdGhost.html
extern crate db;
extern crate ssz;
extern crate types;
pub mod bitwise_lmd_ghost;
pub mod longest_chain;
pub mod optimized_lmd_ghost;
pub mod slow_lmd_ghost;
use db::stores::BeaconBlockAtSlotError;
use db::DBError;
// use store::stores::BeaconBlockAtSlotError;
// use store::DBError;
use store::Error as DBError;
use types::{BeaconBlock, ChainSpec, Hash256};
pub use bitwise_lmd_ghost::BitwiseLMDGhost;
@@ -77,10 +74,11 @@ pub enum ForkChoiceError {
impl From<DBError> for ForkChoiceError {
fn from(e: DBError) -> ForkChoiceError {
ForkChoiceError::StorageError(e.message)
ForkChoiceError::StorageError(format!("{:?}", e))
}
}
/*
impl From<BeaconBlockAtSlotError> for ForkChoiceError {
fn from(e: BeaconBlockAtSlotError) -> ForkChoiceError {
match e {
@@ -94,6 +92,7 @@ impl From<BeaconBlockAtSlotError> for ForkChoiceError {
}
}
}
*/
/// Fork choice options that are currently implemented.
#[derive(Debug, Clone)]

View File

@@ -1,31 +1,25 @@
use crate::{ForkChoice, ForkChoiceError};
use db::{stores::BeaconBlockStore, ClientDB};
use std::sync::Arc;
use store::Store;
use types::{BeaconBlock, ChainSpec, Hash256, Slot};
pub struct LongestChain<T>
where
T: ClientDB + Sized,
{
pub struct LongestChain<T> {
/// List of head block hashes
head_block_hashes: Vec<Hash256>,
/// Block storage access.
block_store: Arc<BeaconBlockStore<T>>,
/// Block storage.
store: Arc<T>,
}
impl<T> LongestChain<T>
where
T: ClientDB + Sized,
{
pub fn new(block_store: Arc<BeaconBlockStore<T>>) -> Self {
impl<T: Store> LongestChain<T> {
pub fn new(store: Arc<T>) -> Self {
LongestChain {
head_block_hashes: Vec::new(),
block_store,
store,
}
}
}
impl<T: ClientDB + Sized> ForkChoice for LongestChain<T> {
impl<T: Store> ForkChoice for LongestChain<T> {
fn add_block(
&mut self,
block: &BeaconBlock,
@@ -55,9 +49,9 @@ impl<T: ClientDB + Sized> ForkChoice for LongestChain<T> {
* Load all the head_block hashes from the DB as SszBeaconBlocks.
*/
for (index, block_hash) in self.head_block_hashes.iter().enumerate() {
let block = self
.block_store
.get_deserialized(&block_hash)?
let block: BeaconBlock = self
.store
.get(&block_hash)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*block_hash))?;
head_blocks.push((index, block));
}

View File

@@ -1,16 +1,11 @@
//! The optimised bitwise LMD-GHOST fork choice rule.
extern crate bit_vec;
use crate::{ForkChoice, ForkChoiceError};
use db::{
stores::{BeaconBlockStore, BeaconStateStore},
ClientDB,
};
use log::{debug, trace};
use std::cmp::Ordering;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use store::Store;
use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot, SlotHeight};
//TODO: Pruning - Children
@@ -34,7 +29,7 @@ fn power_of_2_below(x: u64) -> u64 {
}
/// Stores the necessary data structures to run the optimised lmd ghost algorithm.
pub struct OptimizedLMDGhost<T: ClientDB + Sized, E> {
pub struct OptimizedLMDGhost<T, E> {
/// A cache of known ancestors at given heights for a specific block.
//TODO: Consider FnvHashMap
cache: HashMap<CacheKey<u64>, Hash256>,
@@ -46,30 +41,21 @@ pub struct OptimizedLMDGhost<T: ClientDB + Sized, E> {
/// The latest attestation targets as a map of validator index to block hash.
//TODO: Could this be a fixed size vec
latest_attestation_targets: HashMap<u64, Hash256>,
/// Block storage access.
block_store: Arc<BeaconBlockStore<T>>,
/// State storage access.
state_store: Arc<BeaconStateStore<T>>,
/// Block and state storage.
store: Arc<T>,
max_known_height: SlotHeight,
_phantom: PhantomData<E>,
}
impl<T, E: EthSpec> OptimizedLMDGhost<T, E>
where
T: ClientDB + Sized,
{
pub fn new(
block_store: Arc<BeaconBlockStore<T>>,
state_store: Arc<BeaconStateStore<T>>,
) -> Self {
impl<T: Store, E: EthSpec> OptimizedLMDGhost<T, E> {
pub fn new(store: Arc<T>) -> Self {
OptimizedLMDGhost {
cache: HashMap::new(),
ancestors: vec![HashMap::new(); 16],
latest_attestation_targets: HashMap::new(),
children: HashMap::new(),
max_known_height: SlotHeight::new(0),
block_store,
state_store,
store,
_phantom: PhantomData,
}
}
@@ -89,8 +75,8 @@ where
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes
let current_state: BeaconState<E> = self
.state_store
.get_deserialized(&state_root)?
.store
.get(&state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
let active_validator_indices =
@@ -121,8 +107,8 @@ where
// return None if we can't get the block from the db.
let block_height = {
let block_slot = self
.block_store
.get_deserialized(&block_hash)
.store
.get::<BeaconBlock>(&block_hash)
.ok()?
.expect("Should have returned already if None")
.slot;
@@ -214,7 +200,7 @@ where
}
}
impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
impl<T: Store, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
fn add_block(
&mut self,
block: &BeaconBlock,
@@ -223,8 +209,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
) -> Result<(), ForkChoiceError> {
// get the height of the parent
let parent_height = self
.block_store
.get_deserialized(&block.previous_block_root)?
.store
.get::<BeaconBlock>(&block.previous_block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(block.previous_block_root))?
.slot
.height(spec.genesis_slot);
@@ -275,16 +261,16 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
trace!("Old attestation found: {:?}", attestation_target);
// get the height of the target block
let block_height = self
.block_store
.get_deserialized(&target_block_root)?
.store
.get::<BeaconBlock>(&target_block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*target_block_root))?
.slot
.height(spec.genesis_slot);
// get the height of the past target block
let past_block_height = self
.block_store
.get_deserialized(&attestation_target)?
.store
.get::<BeaconBlock>(&attestation_target)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*attestation_target))?
.slot
.height(spec.genesis_slot);
@@ -308,8 +294,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
justified_block_start
);
let block = self
.block_store
.get_deserialized(&justified_block_start)?
.store
.get::<BeaconBlock>(&justified_block_start)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*justified_block_start))?;
let block_slot = block.slot;
@@ -400,8 +386,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for OptimizedLMDGhost<T, E> {
// didn't find head yet, proceed to next iteration
// update block height
block_height = self
.block_store
.get_deserialized(&current_head)?
.store
.get::<BeaconBlock>(&current_head)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(current_head))?
.slot
.height(spec.genesis_slot);

View File

@@ -1,44 +1,30 @@
extern crate db;
use crate::{ForkChoice, ForkChoiceError};
use db::{
stores::{BeaconBlockStore, BeaconStateStore},
ClientDB,
};
use log::{debug, trace};
use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::Arc;
use store::Store;
use types::{BeaconBlock, BeaconState, ChainSpec, EthSpec, Hash256, Slot};
//TODO: Pruning and syncing
pub struct SlowLMDGhost<T: ClientDB + Sized, E> {
pub struct SlowLMDGhost<T, E> {
/// The latest attestation targets as a map of validator index to block hash.
//TODO: Could this be a fixed size vec
latest_attestation_targets: HashMap<u64, Hash256>,
/// Stores the children for any given parent.
children: HashMap<Hash256, Vec<Hash256>>,
/// Block storage access.
block_store: Arc<BeaconBlockStore<T>>,
/// State storage access.
state_store: Arc<BeaconStateStore<T>>,
/// Block and state storage.
store: Arc<T>,
_phantom: PhantomData<E>,
}
impl<T, E: EthSpec> SlowLMDGhost<T, E>
where
T: ClientDB + Sized,
{
pub fn new(
block_store: Arc<BeaconBlockStore<T>>,
state_store: Arc<BeaconStateStore<T>>,
) -> Self {
impl<T: Store, E: EthSpec> SlowLMDGhost<T, E> {
pub fn new(store: Arc<T>) -> Self {
SlowLMDGhost {
latest_attestation_targets: HashMap::new(),
children: HashMap::new(),
block_store,
state_store,
store,
_phantom: PhantomData,
}
}
@@ -58,8 +44,8 @@ where
let mut latest_votes: HashMap<Hash256, u64> = HashMap::new();
// gets the current weighted votes
let current_state: BeaconState<E> = self
.state_store
.get_deserialized(&state_root)?
.store
.get(state_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconState(*state_root))?;
let active_validator_indices =
@@ -90,15 +76,15 @@ where
) -> Result<u64, ForkChoiceError> {
let mut count = 0;
let block_slot = self
.block_store
.get_deserialized(&block_root)?
.store
.get::<BeaconBlock>(&block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*block_root))?
.slot;
for (vote_hash, votes) in latest_votes.iter() {
let (root_at_slot, _) = self
.block_store
.block_at_slot(&vote_hash, block_slot)?
.store
.get_block_at_preceeding_slot(*vote_hash, block_slot)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*block_root))?;
if root_at_slot == *block_root {
count += votes;
@@ -108,7 +94,7 @@ where
}
}
impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for SlowLMDGhost<T, E> {
impl<T: Store, E: EthSpec> ForkChoice for SlowLMDGhost<T, E> {
/// Process when a block is added
fn add_block(
&mut self,
@@ -150,16 +136,16 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for SlowLMDGhost<T, E> {
trace!("Old attestation found: {:?}", attestation_target);
// get the height of the target block
let block_height = self
.block_store
.get_deserialized(&target_block_root)?
.store
.get::<BeaconBlock>(&target_block_root)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*target_block_root))?
.slot
.height(spec.genesis_slot);
// get the height of the past target block
let past_block_height = self
.block_store
.get_deserialized(&attestation_target)?
.store
.get::<BeaconBlock>(&attestation_target)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*attestation_target))?
.slot
.height(spec.genesis_slot);
@@ -180,8 +166,8 @@ impl<T: ClientDB + Sized, E: EthSpec> ForkChoice for SlowLMDGhost<T, E> {
) -> Result<Hash256, ForkChoiceError> {
debug!("Running LMD Ghost Fork-choice rule");
let start = self
.block_store
.get_deserialized(&justified_block_start)?
.store
.get::<BeaconBlock>(&justified_block_start)?
.ok_or_else(|| ForkChoiceError::MissingBeaconBlock(*justified_block_start))?;
let start_state_root = start.state_root;

View File

@@ -1,26 +1,14 @@
#![cfg(not(debug_assertions))]
// Tests the available fork-choice algorithms
extern crate beacon_chain;
extern crate bls;
extern crate db;
// extern crate env_logger; // for debugging
extern crate fork_choice;
extern crate hex;
extern crate log;
extern crate slot_clock;
extern crate types;
extern crate yaml_rust;
pub use beacon_chain::BeaconChain;
use bls::Signature;
use db::stores::{BeaconBlockStore, BeaconStateStore};
use db::MemoryDB;
use store::MemoryStore;
use store::Store;
// use env_logger::{Builder, Env};
use fork_choice::{
BitwiseLMDGhost, ForkChoice, ForkChoiceAlgorithm, LongestChain, OptimizedLMDGhost, SlowLMDGhost,
};
use ssz::ssz_encode;
use std::collections::HashMap;
use std::sync::Arc;
use std::{fs::File, io::prelude::*, path::PathBuf};
@@ -106,7 +94,7 @@ fn test_yaml_vectors(
// process the tests
for test_case in test_cases {
// setup a fresh test
let (mut fork_choice, block_store, state_root) =
let (mut fork_choice, store, state_root) =
setup_inital_state(&fork_choice_algo, emulated_validators);
// keep a hashmap of block_id's to block_hashes (random hashes to abstract block_id)
@@ -149,9 +137,7 @@ fn test_yaml_vectors(
};
// Store the block.
block_store
.put(&block_hash, &ssz_encode(&beacon_block)[..])
.unwrap();
store.put(&block_hash, &beacon_block).unwrap();
// run add block for fork choice if not genesis
if parent_id != block_id {
@@ -222,29 +208,26 @@ fn load_test_cases_from_yaml(file_path: &str) -> Vec<yaml_rust::Yaml> {
fn setup_inital_state(
fork_choice_algo: &ForkChoiceAlgorithm,
num_validators: usize,
) -> (Box<ForkChoice>, Arc<BeaconBlockStore<MemoryDB>>, Hash256) {
let db = Arc::new(MemoryDB::open());
let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
let state_store = Arc::new(BeaconStateStore::new(db.clone()));
) -> (Box<ForkChoice>, Arc<MemoryStore>, Hash256) {
let store = Arc::new(MemoryStore::open());
// the fork choice instantiation
let fork_choice: Box<ForkChoice> = match fork_choice_algo {
ForkChoiceAlgorithm::OptimizedLMDGhost => {
let f: OptimizedLMDGhost<MemoryDB, FoundationEthSpec> =
OptimizedLMDGhost::new(block_store.clone(), state_store.clone());
let f: OptimizedLMDGhost<MemoryStore, FoundationEthSpec> =
OptimizedLMDGhost::new(store.clone());
Box::new(f)
}
ForkChoiceAlgorithm::BitwiseLMDGhost => {
let f: BitwiseLMDGhost<MemoryDB, FoundationEthSpec> =
BitwiseLMDGhost::new(block_store.clone(), state_store.clone());
let f: BitwiseLMDGhost<MemoryStore, FoundationEthSpec> =
BitwiseLMDGhost::new(store.clone());
Box::new(f)
}
ForkChoiceAlgorithm::SlowLMDGhost => {
let f: SlowLMDGhost<MemoryDB, FoundationEthSpec> =
SlowLMDGhost::new(block_store.clone(), state_store.clone());
let f: SlowLMDGhost<MemoryStore, FoundationEthSpec> = SlowLMDGhost::new(store.clone());
Box::new(f)
}
ForkChoiceAlgorithm::LongestChain => Box::new(LongestChain::new(block_store.clone())),
ForkChoiceAlgorithm::LongestChain => Box::new(LongestChain::new(store.clone())),
};
let spec = FoundationEthSpec::spec();
@@ -255,12 +238,10 @@ fn setup_inital_state(
let (state, _keypairs) = state_builder.build();
let state_root = state.canonical_root();
state_store
.put(&state_root, &ssz_encode(&state)[..])
.unwrap();
store.put(&state_root, &state).unwrap();
// return initialised vars
(fork_choice, block_store, state_root)
(fork_choice, store, state_root)
}
// convert a block_id into a Hash256 -- assume input is hex encoded;

View File

@@ -30,3 +30,6 @@ tree_hash = { path = "../utils/tree_hash" }
tree_hash_derive = { path = "../utils/tree_hash_derive" }
types = { path = "../types" }
rayon = "1.0"
[features]
fake_crypto = ["bls/fake_crypto"]

View File

@@ -22,7 +22,9 @@ pub use verify_transfer::{
execute_transfer, verify_transfer, verify_transfer_time_independent_only,
};
pub mod block_processing_builder;
pub mod errors;
pub mod tests;
mod validate_attestation;
mod verify_attester_slashing;
mod verify_deposit;

View File

@@ -0,0 +1,66 @@
use tree_hash::SignedRoot;
use types::test_utils::{TestingBeaconBlockBuilder, TestingBeaconStateBuilder};
use types::*;
pub struct BlockProcessingBuilder<T: EthSpec> {
pub state_builder: TestingBeaconStateBuilder<T>,
pub block_builder: TestingBeaconBlockBuilder,
pub num_validators: usize,
}
impl<T: EthSpec> BlockProcessingBuilder<T> {
pub fn new(num_validators: usize, spec: &ChainSpec) -> Self {
let state_builder =
TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, &spec);
let block_builder = TestingBeaconBlockBuilder::new(spec);
Self {
state_builder,
block_builder,
num_validators: 0,
}
}
pub fn set_slot(&mut self, slot: Slot, spec: &ChainSpec) {
self.state_builder.teleport_to_slot(slot, &spec);
}
pub fn build_caches(&mut self, spec: &ChainSpec) {
// Builds all caches; benches will not contain shuffling/committee building times.
self.state_builder.build_caches(&spec).unwrap();
}
pub fn build(
mut self,
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock, BeaconState<T>) {
let (state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
builder.set_slot(state.slot);
match previous_block_root {
Some(root) => builder.set_previous_block_root(root),
None => builder.set_previous_block_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
)),
}
let proposer_index = state
.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec)
.unwrap();
let keypair = &keypairs[proposer_index];
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
}
let block = self.block_builder.build(&keypair.sk, &state.fork, spec);
(block, state)
}
}

View File

@@ -0,0 +1,112 @@
#![cfg(all(test, not(feature = "fake_crypto")))]
use super::block_processing_builder::BlockProcessingBuilder;
use super::errors::*;
use crate::per_block_processing;
use tree_hash::SignedRoot;
use types::*;
pub const VALIDATOR_COUNT: usize = 10;
#[test]
fn valid_block_ok() {
let spec = FoundationEthSpec::spec();
let builder = get_builder(&spec);
let (block, mut state) = builder.build(None, None, &spec);
let result = per_block_processing(&mut state, &block, &spec);
assert_eq!(result, Ok(()));
}
#[test]
fn invalid_block_header_state_slot() {
let spec = FoundationEthSpec::spec();
let builder = get_builder(&spec);
let (mut block, mut state) = builder.build(None, None, &spec);
state.slot = Slot::new(133713);
block.slot = Slot::new(424242);
let result = per_block_processing(&mut state, &block, &spec);
assert_eq!(
result,
Err(BlockProcessingError::Invalid(
BlockInvalid::StateSlotMismatch
))
);
}
#[test]
fn invalid_parent_block_root() {
let spec = FoundationEthSpec::spec();
let builder = get_builder(&spec);
let invalid_parent_root = Hash256::from([0xAA; 32]);
let (block, mut state) = builder.build(None, Some(invalid_parent_root), &spec);
let result = per_block_processing(&mut state, &block, &spec);
assert_eq!(
result,
Err(BlockProcessingError::Invalid(
BlockInvalid::ParentBlockRootMismatch {
state: Hash256::from_slice(&state.latest_block_header.signed_root()),
block: block.previous_block_root
}
))
);
}
#[test]
fn invalid_block_signature() {
let spec = FoundationEthSpec::spec();
let builder = get_builder(&spec);
let (mut block, mut state) = builder.build(None, None, &spec);
// sign the block with a keypair that is not the expected proposer
let keypair = Keypair::random();
let message = block.signed_root();
let epoch = block.slot.epoch(spec.slots_per_epoch);
let domain = spec.get_domain(epoch, Domain::BeaconBlock, &state.fork);
block.signature = Signature::new(&message, domain, &keypair.sk);
// process block with invalid block signature
let result = per_block_processing(&mut state, &block, &spec);
// should get a BadSignature error
assert_eq!(
result,
Err(BlockProcessingError::Invalid(BlockInvalid::BadSignature))
);
}
#[test]
fn invalid_randao_reveal_signature() {
let spec = FoundationEthSpec::spec();
let builder = get_builder(&spec);
// sign randao reveal with random keypair
let keypair = Keypair::random();
let (block, mut state) = builder.build(Some(keypair.sk), None, &spec);
let result = per_block_processing(&mut state, &block, &spec);
// should get a BadRandaoSignature error
assert_eq!(
result,
Err(BlockProcessingError::Invalid(
BlockInvalid::BadRandaoSignature
))
);
}
fn get_builder(spec: &ChainSpec) -> (BlockProcessingBuilder<FoundationEthSpec>) {
let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec);
// Set the state and block to be in the last slot of the 4th epoch.
let last_slot_of_epoch = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
builder.set_slot(last_slot_of_epoch, &spec);
builder.build_caches(&spec);
(builder)
}

View File

@@ -23,6 +23,11 @@ impl TestingBeaconBlockBuilder {
}
}
/// Set the previous block root
pub fn set_previous_block_root(&mut self, root: Hash256) {
self.block.previous_block_root = root;
}
/// Set the slot of the block.
pub fn set_slot(&mut self, slot: Slot) {
self.block.slot = slot;
@@ -48,6 +53,11 @@ impl TestingBeaconBlockBuilder {
self.block.body.randao_reveal = Signature::new(&message, domain, sk);
}
/// Has the randao reveal been set?
pub fn randao_reveal_not_set(&mut self) -> bool {
self.block.body.randao_reveal.is_empty()
}
/// Inserts a signed, valid `ProposerSlashing` for the validator.
pub fn insert_proposer_slashing(
&mut self,

View File

@@ -14,6 +14,7 @@ use tree_hash::tree_hash_ssz_encoding_as_vector;
#[derive(Debug, PartialEq, Clone, Eq)]
pub struct FakeSignature {
bytes: Vec<u8>,
is_empty: bool,
}
impl FakeSignature {
@@ -26,6 +27,7 @@ impl FakeSignature {
pub fn zero() -> Self {
Self {
bytes: vec![0; BLS_SIG_BYTE_SIZE],
is_empty: true,
}
}
@@ -59,6 +61,7 @@ impl FakeSignature {
} else {
Ok(Self {
bytes: bytes.to_vec(),
is_empty: false,
})
}
}
@@ -71,6 +74,11 @@ impl FakeSignature {
pub fn empty_signature() -> Self {
FakeSignature::zero()
}
// Check for empty Signature
pub fn is_empty(&self) -> bool {
self.is_empty
}
}
impl_ssz!(FakeSignature, BLS_SIG_BYTE_SIZE, "FakeSignature");