diff --git a/lighthouse/state/block/validation/validate_ssz_block.rs b/lighthouse/state/block/validation/block_validation.rs similarity index 100% rename from lighthouse/state/block/validation/validate_ssz_block.rs rename to lighthouse/state/block/validation/block_validation.rs diff --git a/lighthouse/state/block/validation/mod.rs b/lighthouse/state/block/validation/mod.rs index faf3ad096..d9c67fbcb 100644 --- a/lighthouse/state/block/validation/mod.rs +++ b/lighthouse/state/block/validation/mod.rs @@ -1,4 +1,4 @@ -mod validate_ssz_block; +mod block_validation; #[cfg(test)] mod tests; #[cfg(test)] @@ -18,7 +18,7 @@ use super::common::maps::{ AttesterMap, ProposerMap, }; -pub use self::validate_ssz_block::{ +pub use self::block_validation::{ BlockValidationContext, SszBlockValidationError, BlockStatus, diff --git a/lighthouse/state/block/validation/tests.rs b/lighthouse/state/block/validation/tests/helpers.rs similarity index 52% rename from lighthouse/state/block/validation/tests.rs rename to lighthouse/state/block/validation/tests/helpers.rs index e0fa153c2..3b2dda9e3 100644 --- a/lighthouse/state/block/validation/tests.rs +++ b/lighthouse/state/block/validation/tests/helpers.rs @@ -1,8 +1,3 @@ -extern crate ssz; - -use self::ssz::{ - SszStream, -}; use std::sync::Arc; use super::{ BlockValidationContext, @@ -10,27 +5,21 @@ use super::{ BlockStatus, AttesterMap, ProposerMap, -}; -use super::db::stores::{ - BlockStore, - PoWChainStore, - ValidatorStore, -}; -use super::db::{ MemoryDB, -}; -use super::utils::hash::canonical_hash; -use super::utils::types::{ + canonical_hash, Hash256, Bitfield, -}; -use super::SszBlock; -use super::super::Block; -use super::super::attestation_record::AttestationRecord; -use super::super::super::bls::{ Keypair, Signature, AggregateSignature, + BlockStore, + PoWChainStore, + ValidatorStore, + SszStream, + SszBlock, + Block, + AttestationRecord, + TestParams, }; pub struct TestStore { @@ -55,20 +44,6 @@ impl TestStore { } } -#[derive(Debug)] -pub struct TestParams { - pub total_validators: usize, - pub cycle_length: u8, - pub shard_count: u16, - pub shards_per_slot: u16, - pub validators_per_shard: usize, - pub block_slot: u64, - pub attestations_justified_slot: u64, - pub parent_proposer_index: usize, - pub validation_context_slot: u64, - pub validation_context_justified_slot: u64, - pub validation_context_finalized_slot: u64, -} type ParentHashes = Vec; /// Setup for a block validation function, without actually executing the @@ -263,221 +238,3 @@ pub fn run_block_validation_scenario( }; validation_status } - -fn get_simple_params() -> TestParams { - let validators_per_shard: usize = 5; - let cycle_length: u8 = 2; - let shard_count: u16 = 4; - let shards_per_slot: u16 = shard_count / u16::from(cycle_length); - let total_validators: usize = validators_per_shard * shard_count as usize; - let block_slot = u64::from(cycle_length) * 10000; - let attestations_justified_slot = block_slot - u64::from(cycle_length); - let parent_proposer_index = 0; - - let validation_context_slot = block_slot; - let validation_context_justified_slot = attestations_justified_slot; - let validation_context_finalized_slot = 0; - - TestParams { - total_validators, - cycle_length, - shard_count, - shards_per_slot, - validators_per_shard, - parent_proposer_index, - block_slot, - attestations_justified_slot, - validation_context_slot, - validation_context_justified_slot, - validation_context_finalized_slot, - } -} - -// TODO: test bad ssz serialization - -#[test] -fn test_block_validation_valid() { - let params = get_simple_params(); - - let mutator = |block: Block, attester_map, proposer_map, stores| { - /* - * Do not mutate - */ - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status.unwrap().0, BlockStatus::NewBlock); -} - -#[test] -fn test_block_validation_valid_known_block() { - let params = get_simple_params(); - - let mutator = |block: Block, attester_map, proposer_map, stores: TestStore| { - /* - * Pre-store the block in the database - */ - let block_ssz = serialize_block(&block); - let block_hash = canonical_hash(&block_ssz); - stores.block.put_serialized_block(&block_hash, &block_ssz).unwrap(); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status.unwrap(), (BlockStatus::KnownBlock, None)); -} - -#[test] -fn test_block_validation_invalid_future_slot() { - let params = get_simple_params(); - - let mutator = |mut block: Block, attester_map, proposer_map, stores| { - block.slot_number = block.slot_number + 1; - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::FutureSlot)); -} - -#[test] -fn test_block_validation_invalid_slot_already_finalized() { - let mut params = get_simple_params(); - - params.validation_context_finalized_slot = params.block_slot; - params.validation_context_justified_slot = params.validation_context_finalized_slot + - u64::from(params.cycle_length); - - let mutator = |block, attester_map, proposer_map, stores| { - /* - * Do not mutate - */ - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::SlotAlreadyFinalized)); -} - -#[test] -fn test_block_validation_invalid_unknown_pow_hash() { - let params = get_simple_params(); - - let mutator = |mut block: Block, attester_map, proposer_map, stores| { - block.pow_chain_ref = Hash256::from("unknown pow hash".as_bytes()); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::UnknownPoWChainRef)); -} - -#[test] -fn test_block_validation_invalid_unknown_parent_hash() { - let params = get_simple_params(); - - let mutator = |mut block: Block, attester_map, proposer_map, stores| { - block.parent_hash = Hash256::from("unknown parent block".as_bytes()); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::UnknownParentHash)); -} - -#[test] -fn test_block_validation_invalid_1st_attestation_signature() { - let params = get_simple_params(); - - let mutator = |mut block: Block, attester_map, proposer_map, stores| { - /* - * Set the second attestaion record to have an invalid signature. - */ - block.attestations[0].aggregate_sig = AggregateSignature::new(); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::FirstAttestationSignatureFailed)); -} - -#[test] -fn test_block_validation_invalid_no_parent_proposer_signature() { - let params = get_simple_params(); - - let mutator = |block: Block, attester_map, mut proposer_map: ProposerMap, stores: TestStore| { - /* - * Set the proposer for this slot to be a validator that does not exist. - */ - let ssz = stores.block.get_serialized_block(&block.parent_hash.as_ref()).unwrap().unwrap(); - let parent_block_slot = SszBlock::from_slice(&ssz[..]).unwrap().slot_number(); - proposer_map.insert(parent_block_slot, params.total_validators + 1); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::NoProposerSignature)); -} - -#[test] -fn test_block_validation_invalid_bad_proposer_map() { - let params = get_simple_params(); - - let mutator = |block, attester_map, _, stores| { - /* - * Initialize a new, empty proposer map - */ - let proposer_map = ProposerMap::new(); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::BadProposerMap)); -} - -#[test] -fn test_block_validation_invalid_2nd_attestation_signature() { - let params = get_simple_params(); - - let mutator = |mut block: Block, attester_map, proposer_map, stores| { - /* - * Set the second attestaion record to have an invalid signature. - */ - block.attestations[1].aggregate_sig = AggregateSignature::new(); - (block, attester_map, proposer_map, stores) - }; - - let status = run_block_validation_scenario( - ¶ms, - mutator); - - assert_eq!(status, Err(SszBlockValidationError::AttestationSignatureFailed)); -} diff --git a/lighthouse/state/block/validation/tests/mod.rs b/lighthouse/state/block/validation/tests/mod.rs new file mode 100644 index 000000000..02398dbe0 --- /dev/null +++ b/lighthouse/state/block/validation/tests/mod.rs @@ -0,0 +1,275 @@ +extern crate ssz; + +mod helpers; + +pub use self::helpers::{ + TestStore, + setup_block_validation_scenario, + run_block_validation_scenario, + serialize_block, +}; + +use self::ssz::{ + SszStream, +}; +use super::{ + BlockValidationContext, + SszBlockValidationError, + BlockStatus, + AttesterMap, + ProposerMap, +}; +use super::db::stores::{ + BlockStore, + PoWChainStore, + ValidatorStore, +}; +use super::db::{ + MemoryDB, +}; +use super::utils::hash::canonical_hash; +use super::utils::types::{ + Hash256, + Bitfield, +}; +use super::SszBlock; +use super::super::Block; +use super::super::attestation_record::AttestationRecord; +use super::super::super::bls::{ + Keypair, + Signature, + AggregateSignature, +}; + +#[derive(Debug)] +pub struct TestParams { + pub total_validators: usize, + pub cycle_length: u8, + pub shard_count: u16, + pub shards_per_slot: u16, + pub validators_per_shard: usize, + pub block_slot: u64, + pub attestations_justified_slot: u64, + pub parent_proposer_index: usize, + pub validation_context_slot: u64, + pub validation_context_justified_slot: u64, + pub validation_context_finalized_slot: u64, +} + +fn get_simple_params() -> TestParams { + let validators_per_shard: usize = 5; + let cycle_length: u8 = 2; + let shard_count: u16 = 4; + let shards_per_slot: u16 = shard_count / u16::from(cycle_length); + let total_validators: usize = validators_per_shard * shard_count as usize; + let block_slot = u64::from(cycle_length) * 10000; + let attestations_justified_slot = block_slot - u64::from(cycle_length); + let parent_proposer_index = 0; + + let validation_context_slot = block_slot; + let validation_context_justified_slot = attestations_justified_slot; + let validation_context_finalized_slot = 0; + + TestParams { + total_validators, + cycle_length, + shard_count, + shards_per_slot, + validators_per_shard, + parent_proposer_index, + block_slot, + attestations_justified_slot, + validation_context_slot, + validation_context_justified_slot, + validation_context_finalized_slot, + } +} + +// TODO: test bad ssz serialization + +#[test] +fn test_block_validation_valid() { + let params = get_simple_params(); + + let mutator = |block: Block, attester_map, proposer_map, stores| { + /* + * Do not mutate + */ + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status.unwrap().0, BlockStatus::NewBlock); +} + +#[test] +fn test_block_validation_valid_known_block() { + let params = get_simple_params(); + + let mutator = |block: Block, attester_map, proposer_map, stores: TestStore| { + /* + * Pre-store the block in the database + */ + let block_ssz = serialize_block(&block); + let block_hash = canonical_hash(&block_ssz); + stores.block.put_serialized_block(&block_hash, &block_ssz).unwrap(); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status.unwrap(), (BlockStatus::KnownBlock, None)); +} + +#[test] +fn test_block_validation_invalid_future_slot() { + let params = get_simple_params(); + + let mutator = |mut block: Block, attester_map, proposer_map, stores| { + block.slot_number = block.slot_number + 1; + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::FutureSlot)); +} + +#[test] +fn test_block_validation_invalid_slot_already_finalized() { + let mut params = get_simple_params(); + + params.validation_context_finalized_slot = params.block_slot; + params.validation_context_justified_slot = params.validation_context_finalized_slot + + u64::from(params.cycle_length); + + let mutator = |block, attester_map, proposer_map, stores| { + /* + * Do not mutate + */ + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::SlotAlreadyFinalized)); +} + +#[test] +fn test_block_validation_invalid_unknown_pow_hash() { + let params = get_simple_params(); + + let mutator = |mut block: Block, attester_map, proposer_map, stores| { + block.pow_chain_ref = Hash256::from("unknown pow hash".as_bytes()); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::UnknownPoWChainRef)); +} + +#[test] +fn test_block_validation_invalid_unknown_parent_hash() { + let params = get_simple_params(); + + let mutator = |mut block: Block, attester_map, proposer_map, stores| { + block.parent_hash = Hash256::from("unknown parent block".as_bytes()); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::UnknownParentHash)); +} + +#[test] +fn test_block_validation_invalid_1st_attestation_signature() { + let params = get_simple_params(); + + let mutator = |mut block: Block, attester_map, proposer_map, stores| { + /* + * Set the second attestaion record to have an invalid signature. + */ + block.attestations[0].aggregate_sig = AggregateSignature::new(); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::FirstAttestationSignatureFailed)); +} + +#[test] +fn test_block_validation_invalid_no_parent_proposer_signature() { + let params = get_simple_params(); + + let mutator = |block: Block, attester_map, mut proposer_map: ProposerMap, stores: TestStore| { + /* + * Set the proposer for this slot to be a validator that does not exist. + */ + let ssz = stores.block.get_serialized_block(&block.parent_hash.as_ref()).unwrap().unwrap(); + let parent_block_slot = SszBlock::from_slice(&ssz[..]).unwrap().slot_number(); + proposer_map.insert(parent_block_slot, params.total_validators + 1); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::NoProposerSignature)); +} + +#[test] +fn test_block_validation_invalid_bad_proposer_map() { + let params = get_simple_params(); + + let mutator = |block, attester_map, _, stores| { + /* + * Initialize a new, empty proposer map + */ + let proposer_map = ProposerMap::new(); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::BadProposerMap)); +} + +#[test] +fn test_block_validation_invalid_2nd_attestation_signature() { + let params = get_simple_params(); + + let mutator = |mut block: Block, attester_map, proposer_map, stores| { + /* + * Set the second attestaion record to have an invalid signature. + */ + block.attestations[1].aggregate_sig = AggregateSignature::new(); + (block, attester_map, proposer_map, stores) + }; + + let status = run_block_validation_scenario( + ¶ms, + mutator); + + assert_eq!(status, Err(SszBlockValidationError::AttestationSignatureFailed)); +}