Merge pull request #347 from darrenlangley/block-processing-tests
block processing regression tests
This commit is contained in:
commit
f7519096a6
@ -29,3 +29,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"]
|
@ -20,7 +20,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;
|
||||
|
@ -0,0 +1,60 @@
|
||||
use types::test_utils::{TestingBeaconBlockBuilder, TestingBeaconStateBuilder};
|
||||
use types::*;
|
||||
use tree_hash::SignedRoot;
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
110
eth2/state_processing/src/per_block_processing/tests.rs
Normal file
110
eth2/state_processing/src/per_block_processing/tests.rs
Normal file
@ -0,0 +1,110 @@
|
||||
#![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)
|
||||
}
|
@ -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,
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user