From 3e030c78a870c1402eeb3b08671728280ff58c94 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Wed, 10 Apr 2019 14:42:31 +1000 Subject: [PATCH 1/9] copied builder and setup tests --- .../block_processing_builder.rs | 175 ++++++++++++++++++ .../src/per_block_processing/tests.rs | 23 +++ 2 files changed, 198 insertions(+) create mode 100644 eth2/state_processing/src/per_block_processing/block_processing_builder.rs create mode 100644 eth2/state_processing/src/per_block_processing/tests.rs diff --git a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs new file mode 100644 index 000000000..99bbf0944 --- /dev/null +++ b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs @@ -0,0 +1,175 @@ +use log::info; +use types::test_utils::{TestingBeaconBlockBuilder, TestingBeaconStateBuilder}; +use types::*; + +pub struct BlockProcessingBuilder { + pub state_builder: TestingBeaconStateBuilder, + pub block_builder: TestingBeaconBlockBuilder, + + pub num_validators: usize, + pub num_proposer_slashings: usize, + pub num_attester_slashings: usize, + pub num_indices_per_slashable_vote: usize, + pub num_attestations: usize, + pub num_deposits: usize, + pub num_exits: usize, + pub num_transfers: usize, +} + +impl BlockProcessingBuilder { + 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, + num_proposer_slashings: 0, + num_attester_slashings: 0, + num_indices_per_slashable_vote: spec.max_indices_per_slashable_vote as usize, + num_attestations: 0, + num_deposits: 0, + num_exits: 0, + num_transfers: 0, + } + } + + pub fn maximize_block_operations(&mut self, spec: &ChainSpec) { + self.num_proposer_slashings = spec.max_proposer_slashings as usize; + self.num_attester_slashings = spec.max_attester_slashings as usize; + self.num_indices_per_slashable_vote = spec.max_indices_per_slashable_vote as usize; + self.num_attestations = spec.max_attestations as usize; + self.num_deposits = spec.max_deposits as usize; + self.num_exits = spec.max_voluntary_exits as usize; + self.num_transfers = spec.max_transfers as usize; + } + + 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, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { + let (mut state, keypairs) = self.state_builder.build(); + let builder = &mut self.block_builder; + + builder.set_slot(state.slot); + + let proposer_index = state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec).unwrap(); + let keypair = &keypairs[proposer_index]; + + builder.set_randao_reveal(&keypair.sk, &state.fork, spec); + + // Used as a stream of validator indices for use in slashings, exits, etc. + let mut validators_iter = (0..keypairs.len() as u64).into_iter(); + + // Insert `ProposerSlashing` objects. + for _ in 0..self.num_proposer_slashings { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + builder.insert_proposer_slashing( + validator_index, + &keypairs[validator_index as usize].sk, + &state.fork, + spec, + ); + } + info!( + "Inserted {} proposer slashings.", + builder.block.body.proposer_slashings.len() + ); + + // Insert `AttesterSlashing` objects + for _ in 0..self.num_attester_slashings { + let mut attesters: Vec = vec![]; + let mut secret_keys: Vec<&SecretKey> = vec![]; + + for _ in 0..self.num_indices_per_slashable_vote { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + attesters.push(validator_index); + secret_keys.push(&keypairs[validator_index as usize].sk); + } + + builder.insert_attester_slashing(&attesters, &secret_keys, &state.fork, spec); + } + info!( + "Inserted {} attester slashings.", + builder.block.body.attester_slashings.len() + ); + + // Insert `Attestation` objects. + let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect(); + builder + .insert_attestations( + &state, + &all_secret_keys, + self.num_attestations as usize, + spec, + ) + .unwrap(); + info!( + "Inserted {} attestations.", + builder.block.body.attestations.len() + ); + + // Insert `Deposit` objects. + for i in 0..self.num_deposits { + builder.insert_deposit( + 32_000_000_000, + state.deposit_index + (i as u64), + &state, + spec, + ); + } + info!("Inserted {} deposits.", builder.block.body.deposits.len()); + + // Insert the maximum possible number of `Exit` objects. + for _ in 0..self.num_exits { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + builder.insert_exit( + &state, + validator_index, + &keypairs[validator_index as usize].sk, + spec, + ); + } + info!( + "Inserted {} exits.", + builder.block.body.voluntary_exits.len() + ); + + // Insert the maximum possible number of `Transfer` objects. + for _ in 0..self.num_transfers { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + // Manually set the validator to be withdrawn. + state.validator_registry[validator_index as usize].withdrawable_epoch = + state.previous_epoch(spec); + + builder.insert_transfer( + &state, + validator_index, + validator_index, + 1, + keypairs[validator_index as usize].clone(), + spec, + ); + } + info!("Inserted {} transfers.", builder.block.body.transfers.len()); + + let mut block = self.block_builder.build(&keypair.sk, &state.fork, spec); + + // Set the eth1 data to be different from the state. + block.body.eth1_data.block_hash = Hash256::from_slice(&vec![42; 32]); + + (block, state) + } +} diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs new file mode 100644 index 000000000..004f84805 --- /dev/null +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -0,0 +1,23 @@ +#![cfg(test)] +use crate::per_block_processing; +use super::block_processing_builder::BlockProcessingBuilder; +use types::*; + +pub const VALIDATOR_COUNT: usize = 10; + +#[test] +fn runs_without_error() { + let spec = ChainSpec::foundation(); + 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); + + let (block, mut state) = builder.build(&spec); + + per_block_processing(&mut state, &block, &spec).unwrap(); +} + From e1c08b1d02dd23f42c1179b72b4b2d10ef0afb09 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Wed, 10 Apr 2019 21:06:25 +1000 Subject: [PATCH 2/9] mapped out invalid states... 59 --- .../src/per_block_processing/tests.rs | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index 004f84805..c9318bc63 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -13,7 +13,7 @@ fn runs_without_error() { // 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); let (block, mut state) = builder.build(&spec); @@ -21,3 +21,76 @@ fn runs_without_error() { per_block_processing(&mut state, &block, &spec).unwrap(); } +// process_block_header +// Invalid::StateSlotMismatch +// Invalid::ParentBlockRootMismatch + +// verify_block_signature +// Invalid::BadSignature + +// process_randao +// Invalid::BadRandaoSignature + +// process_proposer_slashings +// Invalid::MaxProposerSlashingsExceeded +// verify_proposer_slashing +// Invalid::ProposerUnknown +// Invalid::ProposalSlotMismatch +// Invalid::ProposalsIdentical +// Invalid::ProposerAlreadySlashed +// Invalid::ProposerAlreadyWithdrawn +// Invalid::BadProposal1Signature +// Invalid::BadProposal2Signature + +// process_attester_slashings +// Invalid::MaxAttesterSlashingsExceed +// verify_attester_slashing +// Invalid::AttestationDataIdentical +// Invalid::NotSlashable +// Invalid::SlashableAttestation1Invalid +// Invalid::SlashableAttestation2Invalid + +// process_attestations +// Invalid::MaxAttestationsExceeded +// validate_attestation +// Invalid::PreGenesis +// Invalid::IncludedTooLate +// Invalid::IncludedTooEarly +// Invalid::BadPreviousCrosslink +// Invalid::AggregationBitfieldIsEmpty +// Invalid::CustodyBitfieldHasSetBits +// Invalid::NoCommitteeForShard +// Invalid::BadCustodyBitfieldLength +// Invalid::BadAggregationBitfieldLength +// Invalid::ShardBlockRootNotZero +// verify_justified_epoch_and_root +// Invalid::WrongJustifiedEpoch (current) +// Invalid::WrongJustifiedRoot (current) +// Invalid::WrongJustifiedEpoch (previous) +// Invalid::WrongJustifiedRoot (previous) +// verify_attestation_signature +// Invalid::BadAggregationBitfieldLength +// Invalid::BadCustodyBitfieldLength +// BeaconStateError::UnknownValidator +// Invalid::BadSignature + +// process_deposits +// Invalid::MaxDepositsExceeded +// verify_deposit +// Invalid::BadProofOfPossession +// Invalid::BadMerkleProof +// verify_deposit_index +// Invalid::BadIndex + +// process_exits +// Invalid::MaxExitsExceeded +// verify_exit +// Invalid::ValidatorUnknown +// Invalid::AlreadyExited +// Invalid::AlreadyInitiatedExited +// Invalid::FutureEpoch +// Invalid::TooYoungToLeave +// Invalid::BadSignature + + + From 8366352aaabca7a9f8e0c811353b64fc9d52d018 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Wed, 10 Apr 2019 21:07:56 +1000 Subject: [PATCH 3/9] mapped out invalid states... 59 --- .../src/per_block_processing/tests.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index c9318bc63..28dbc2c55 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -92,5 +92,20 @@ fn runs_without_error() { // Invalid::TooYoungToLeave // Invalid::BadSignature +// process_transfers +// Invalid::MaxTransfersExceed +// verify_transfer +// Invalid::FromValidatorUnknown +// Invalid::FeeOverflow +// Invalid::FromBalanceInsufficient (amount) +// Invalid::FromBalanceInsufficient (fee) +// Invalid::InvalidResultingFromBalance +// Invalid::TransferSlotInPast +// Invalid::StateSlotMismatch +// Invalid::FromValidatorUnknown (???) +// Invalid::FromValidatorIneligableForTransfer +// Invalid::WithdrawalCredentialsMismatch +// Invalid::BadSignature + From f9c1800c00c399594b17323676dded9ac608b843 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Wed, 10 Apr 2019 21:56:31 +1000 Subject: [PATCH 4/9] process_block_header tests --- .../src/per_block_processing/tests.rs | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index 28dbc2c55..ac294de69 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -1,6 +1,7 @@ #![cfg(test)] use crate::per_block_processing; use super::block_processing_builder::BlockProcessingBuilder; +use super::errors::*; use types::*; pub const VALIDATOR_COUNT: usize = 10; @@ -8,23 +9,43 @@ pub const VALIDATOR_COUNT: usize = 10; #[test] fn runs_without_error() { let spec = ChainSpec::foundation(); + let (block, mut state) = get_block_state(&spec); + + per_block_processing(&mut state, &block, &spec).unwrap(); +} + +#[test] +fn process_block_header_invalid_state_slot() { + let spec = ChainSpec::foundation(); + let (mut block, mut state) = get_block_state(&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] +#[ignore] +fn process_block_header_invalid_parent_block_root() { + // this will be changed in spec 0.5.1 to use signed root +} + +fn get_block_state(spec: &ChainSpec) -> (BeaconBlock, BeaconState) { 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); - - let (block, mut state) = builder.build(&spec); - per_block_processing(&mut state, &block, &spec).unwrap(); + let (block, state) = builder.build(&spec); + + (block, state) } -// process_block_header -// Invalid::StateSlotMismatch -// Invalid::ParentBlockRootMismatch - // verify_block_signature // Invalid::BadSignature From bb0500f11d7f8bbffbe0feec7c4f2ea3c1e07e9a Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Wed, 10 Apr 2019 21:58:27 +1000 Subject: [PATCH 5/9] process_block_header tests --- eth2/state_processing/src/per_block_processing.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 6c52a2676..aac94d55c 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -21,6 +21,8 @@ pub use verify_transfer::{ }; pub mod errors; +pub mod tests; +pub mod block_processing_builder; mod validate_attestation; mod verify_attester_slashing; mod verify_deposit; From d76246e6009a4d21f0a8a0447a6860b3fb6deadf Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Mon, 15 Apr 2019 10:38:13 +1000 Subject: [PATCH 6/9] invalid block signature test --- .../src/per_block_processing.rs | 2 +- .../block_processing_builder.rs | 135 +---------------- .../src/per_block_processing/tests.rs | 142 ++++++------------ eth2/utils/bls/src/lib.rs | 12 -- 4 files changed, 50 insertions(+), 241 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index aac94d55c..ac874d95e 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -20,9 +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; -pub mod block_processing_builder; mod validate_attestation; mod verify_attester_slashing; mod verify_deposit; diff --git a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs index 99bbf0944..489684523 100644 --- a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs +++ b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs @@ -1,4 +1,3 @@ -use log::info; use types::test_utils::{TestingBeaconBlockBuilder, TestingBeaconStateBuilder}; use types::*; @@ -7,13 +6,6 @@ pub struct BlockProcessingBuilder { pub block_builder: TestingBeaconBlockBuilder, pub num_validators: usize, - pub num_proposer_slashings: usize, - pub num_attester_slashings: usize, - pub num_indices_per_slashable_vote: usize, - pub num_attestations: usize, - pub num_deposits: usize, - pub num_exits: usize, - pub num_transfers: usize, } impl BlockProcessingBuilder { @@ -26,26 +18,9 @@ impl BlockProcessingBuilder { state_builder, block_builder, num_validators: 0, - num_proposer_slashings: 0, - num_attester_slashings: 0, - num_indices_per_slashable_vote: spec.max_indices_per_slashable_vote as usize, - num_attestations: 0, - num_deposits: 0, - num_exits: 0, - num_transfers: 0, } } - pub fn maximize_block_operations(&mut self, spec: &ChainSpec) { - self.num_proposer_slashings = spec.max_proposer_slashings as usize; - self.num_attester_slashings = spec.max_attester_slashings as usize; - self.num_indices_per_slashable_vote = spec.max_indices_per_slashable_vote as usize; - self.num_attestations = spec.max_attestations as usize; - self.num_deposits = spec.max_deposits as usize; - self.num_exits = spec.max_voluntary_exits as usize; - self.num_transfers = spec.max_transfers as usize; - } - pub fn set_slot(&mut self, slot: Slot, spec: &ChainSpec) { self.state_builder.teleport_to_slot(slot, &spec); } @@ -56,119 +31,19 @@ impl BlockProcessingBuilder { } pub fn build(mut self, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { - let (mut state, keypairs) = self.state_builder.build(); + let (state, keypairs) = self.state_builder.build(); let builder = &mut self.block_builder; builder.set_slot(state.slot); - let proposer_index = state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec).unwrap(); + let proposer_index = state + .get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec) + .unwrap(); let keypair = &keypairs[proposer_index]; builder.set_randao_reveal(&keypair.sk, &state.fork, spec); - // Used as a stream of validator indices for use in slashings, exits, etc. - let mut validators_iter = (0..keypairs.len() as u64).into_iter(); - - // Insert `ProposerSlashing` objects. - for _ in 0..self.num_proposer_slashings { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - builder.insert_proposer_slashing( - validator_index, - &keypairs[validator_index as usize].sk, - &state.fork, - spec, - ); - } - info!( - "Inserted {} proposer slashings.", - builder.block.body.proposer_slashings.len() - ); - - // Insert `AttesterSlashing` objects - for _ in 0..self.num_attester_slashings { - let mut attesters: Vec = vec![]; - let mut secret_keys: Vec<&SecretKey> = vec![]; - - for _ in 0..self.num_indices_per_slashable_vote { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - attesters.push(validator_index); - secret_keys.push(&keypairs[validator_index as usize].sk); - } - - builder.insert_attester_slashing(&attesters, &secret_keys, &state.fork, spec); - } - info!( - "Inserted {} attester slashings.", - builder.block.body.attester_slashings.len() - ); - - // Insert `Attestation` objects. - let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect(); - builder - .insert_attestations( - &state, - &all_secret_keys, - self.num_attestations as usize, - spec, - ) - .unwrap(); - info!( - "Inserted {} attestations.", - builder.block.body.attestations.len() - ); - - // Insert `Deposit` objects. - for i in 0..self.num_deposits { - builder.insert_deposit( - 32_000_000_000, - state.deposit_index + (i as u64), - &state, - spec, - ); - } - info!("Inserted {} deposits.", builder.block.body.deposits.len()); - - // Insert the maximum possible number of `Exit` objects. - for _ in 0..self.num_exits { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - builder.insert_exit( - &state, - validator_index, - &keypairs[validator_index as usize].sk, - spec, - ); - } - info!( - "Inserted {} exits.", - builder.block.body.voluntary_exits.len() - ); - - // Insert the maximum possible number of `Transfer` objects. - for _ in 0..self.num_transfers { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - // Manually set the validator to be withdrawn. - state.validator_registry[validator_index as usize].withdrawable_epoch = - state.previous_epoch(spec); - - builder.insert_transfer( - &state, - validator_index, - validator_index, - 1, - keypairs[validator_index as usize].clone(), - spec, - ); - } - info!("Inserted {} transfers.", builder.block.body.transfers.len()); - - let mut block = self.block_builder.build(&keypair.sk, &state.fork, spec); - - // Set the eth1 data to be different from the state. - block.body.eth1_data.block_hash = Hash256::from_slice(&vec![42; 32]); + let block = self.block_builder.build(&keypair.sk, &state.fork, spec); (block, state) } diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index ac294de69..6fe7e40d2 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -1,39 +1,72 @@ #![cfg(test)] -use crate::per_block_processing; use super::block_processing_builder::BlockProcessingBuilder; use super::errors::*; -use types::*; +use crate::per_block_processing; +use ssz::SignedRoot; +use types::{ChainSpec, Domain, Keypair, Signature, Slot}; pub const VALIDATOR_COUNT: usize = 10; #[test] -fn runs_without_error() { +fn valid_block_ok() { let spec = ChainSpec::foundation(); - let (block, mut state) = get_block_state(&spec); + let builder = get_builder(&spec); + let (block, mut state) = builder.build(&spec); - per_block_processing(&mut state, &block, &spec).unwrap(); + let result = per_block_processing(&mut state, &block, &spec); + + assert_eq!(result, Ok(())); } #[test] -fn process_block_header_invalid_state_slot() { +fn invalid_block_header_state_slot() { let spec = ChainSpec::foundation(); - let (mut block, mut state) = get_block_state(&spec); + let builder = get_builder(&spec); + let (mut block, mut state) = builder.build(&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))); + assert_eq!( + result, + Err(BlockProcessingError::Invalid( + BlockInvalid::StateSlotMismatch + )) + ); } #[test] #[ignore] -fn process_block_header_invalid_parent_block_root() { +fn invalid_parent_block_root() { // this will be changed in spec 0.5.1 to use signed root } -fn get_block_state(spec: &ChainSpec) -> (BeaconBlock, BeaconState) { +#[test] +fn invalid_block_signature() { + let spec = ChainSpec::foundation(); + let builder = get_builder(&spec); + let (mut block, mut state) = builder.build(&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)) + ); +} + +fn get_builder(spec: &ChainSpec) -> (BlockProcessingBuilder) { let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec); // Set the state and block to be in the last slot of the 4th epoch. @@ -41,92 +74,5 @@ fn get_block_state(spec: &ChainSpec) -> (BeaconBlock, BeaconState) { builder.set_slot(last_slot_of_epoch, &spec); builder.build_caches(&spec); - let (block, state) = builder.build(&spec); - - (block, state) + (builder) } - -// verify_block_signature -// Invalid::BadSignature - -// process_randao -// Invalid::BadRandaoSignature - -// process_proposer_slashings -// Invalid::MaxProposerSlashingsExceeded -// verify_proposer_slashing -// Invalid::ProposerUnknown -// Invalid::ProposalSlotMismatch -// Invalid::ProposalsIdentical -// Invalid::ProposerAlreadySlashed -// Invalid::ProposerAlreadyWithdrawn -// Invalid::BadProposal1Signature -// Invalid::BadProposal2Signature - -// process_attester_slashings -// Invalid::MaxAttesterSlashingsExceed -// verify_attester_slashing -// Invalid::AttestationDataIdentical -// Invalid::NotSlashable -// Invalid::SlashableAttestation1Invalid -// Invalid::SlashableAttestation2Invalid - -// process_attestations -// Invalid::MaxAttestationsExceeded -// validate_attestation -// Invalid::PreGenesis -// Invalid::IncludedTooLate -// Invalid::IncludedTooEarly -// Invalid::BadPreviousCrosslink -// Invalid::AggregationBitfieldIsEmpty -// Invalid::CustodyBitfieldHasSetBits -// Invalid::NoCommitteeForShard -// Invalid::BadCustodyBitfieldLength -// Invalid::BadAggregationBitfieldLength -// Invalid::ShardBlockRootNotZero -// verify_justified_epoch_and_root -// Invalid::WrongJustifiedEpoch (current) -// Invalid::WrongJustifiedRoot (current) -// Invalid::WrongJustifiedEpoch (previous) -// Invalid::WrongJustifiedRoot (previous) -// verify_attestation_signature -// Invalid::BadAggregationBitfieldLength -// Invalid::BadCustodyBitfieldLength -// BeaconStateError::UnknownValidator -// Invalid::BadSignature - -// process_deposits -// Invalid::MaxDepositsExceeded -// verify_deposit -// Invalid::BadProofOfPossession -// Invalid::BadMerkleProof -// verify_deposit_index -// Invalid::BadIndex - -// process_exits -// Invalid::MaxExitsExceeded -// verify_exit -// Invalid::ValidatorUnknown -// Invalid::AlreadyExited -// Invalid::AlreadyInitiatedExited -// Invalid::FutureEpoch -// Invalid::TooYoungToLeave -// Invalid::BadSignature - -// process_transfers -// Invalid::MaxTransfersExceed -// verify_transfer -// Invalid::FromValidatorUnknown -// Invalid::FeeOverflow -// Invalid::FromBalanceInsufficient (amount) -// Invalid::FromBalanceInsufficient (fee) -// Invalid::InvalidResultingFromBalance -// Invalid::TransferSlotInPast -// Invalid::StateSlotMismatch -// Invalid::FromValidatorUnknown (???) -// Invalid::FromValidatorIneligableForTransfer -// Invalid::WithdrawalCredentialsMismatch -// Invalid::BadSignature - - - diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index b9a4d5c1d..caf56ae74 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -6,23 +6,11 @@ mod keypair; mod public_key; mod secret_key; -#[cfg(not(debug_assertions))] mod aggregate_signature; -#[cfg(not(debug_assertions))] mod signature; -#[cfg(not(debug_assertions))] pub use crate::aggregate_signature::AggregateSignature; -#[cfg(not(debug_assertions))] pub use crate::signature::Signature; -#[cfg(debug_assertions)] -mod fake_aggregate_signature; -#[cfg(debug_assertions)] -mod fake_signature; -#[cfg(debug_assertions)] -pub use crate::fake_aggregate_signature::FakeAggregateSignature as AggregateSignature; -#[cfg(debug_assertions)] -pub use crate::fake_signature::FakeSignature as Signature; pub use crate::aggregate_public_key::AggregatePublicKey; pub use crate::keypair::Keypair; From 010d319fdf9cd94d0ebebd0211fe433cfb5a5183 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Thu, 18 Apr 2019 07:00:40 +1000 Subject: [PATCH 7/9] invalid randao signature test implemented --- .../src/per_block_processing.rs | 2 ++ .../block_processing_builder.rs | 8 +++++-- .../src/per_block_processing/tests.rs | 24 ++++++++++++++++--- .../testing_beacon_block_builder.rs | 6 +++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index ac874d95e..331069d44 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -139,6 +139,8 @@ pub fn verify_block_signature( &state.fork, ); + println!("verify {:?}", &block); + verify!( block .signature diff --git a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs index 489684523..fb9dbd153 100644 --- a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs +++ b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs @@ -30,7 +30,7 @@ impl BlockProcessingBuilder { self.state_builder.build_caches(&spec).unwrap(); } - pub fn build(mut self, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { + pub fn build(mut self, randao_sk: Option, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { let (state, keypairs) = self.state_builder.build(); let builder = &mut self.block_builder; @@ -41,10 +41,14 @@ impl BlockProcessingBuilder { .unwrap(); let keypair = &keypairs[proposer_index]; - builder.set_randao_reveal(&keypair.sk, &state.fork, spec); + 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) } + } diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index 6fe7e40d2..6ae7fd872 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -11,7 +11,7 @@ pub const VALIDATOR_COUNT: usize = 10; fn valid_block_ok() { let spec = ChainSpec::foundation(); let builder = get_builder(&spec); - let (block, mut state) = builder.build(&spec); + let (block, mut state) = builder.build(None, &spec); let result = per_block_processing(&mut state, &block, &spec); @@ -22,7 +22,7 @@ fn valid_block_ok() { fn invalid_block_header_state_slot() { let spec = ChainSpec::foundation(); let builder = get_builder(&spec); - let (mut block, mut state) = builder.build(&spec); + let (mut block, mut state) = builder.build(None, &spec); state.slot = Slot::new(133713); block.slot = Slot::new(424242); @@ -47,7 +47,7 @@ fn invalid_parent_block_root() { fn invalid_block_signature() { let spec = ChainSpec::foundation(); let builder = get_builder(&spec); - let (mut block, mut state) = builder.build(&spec); + let (mut block, mut state) = builder.build(None, &spec); // sign the block with a keypair that is not the expected proposer let keypair = Keypair::random(); @@ -66,6 +66,24 @@ fn invalid_block_signature() { ); } +#[test] +fn invalid_randao_reveal_signature() { + let spec = ChainSpec::foundation(); + let builder = get_builder(&spec); + + // sign randao reveal with random keypair + let keypair = Keypair::random(); + let (block, mut state) = builder.build(Some(keypair.sk), &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) { let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec); diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index c5cd22ed4..c8c32d931 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -33,6 +33,7 @@ impl TestingBeaconBlockBuilder { /// Modifying the block after signing may invalidate the signature. pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) { let message = self.block.signed_root(); + println!("block set {:?}", self.block); let epoch = self.block.slot.epoch(spec.slots_per_epoch); let domain = spec.get_domain(epoch, Domain::BeaconBlock, fork); self.block.signature = Signature::new(&message, domain, sk); @@ -48,6 +49,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, From 773227d627104ffbc1c0c119c8143725d8aeef15 Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Fri, 19 Apr 2019 07:09:20 +1000 Subject: [PATCH 8/9] removed printlns --- eth2/state_processing/src/per_block_processing.rs | 2 -- eth2/types/src/test_utils/testing_beacon_block_builder.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 331069d44..ac874d95e 100644 --- a/eth2/state_processing/src/per_block_processing.rs +++ b/eth2/state_processing/src/per_block_processing.rs @@ -139,8 +139,6 @@ pub fn verify_block_signature( &state.fork, ); - println!("verify {:?}", &block); - verify!( block .signature diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index c8c32d931..c28311002 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -33,7 +33,6 @@ impl TestingBeaconBlockBuilder { /// Modifying the block after signing may invalidate the signature. pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) { let message = self.block.signed_root(); - println!("block set {:?}", self.block); let epoch = self.block.slot.epoch(spec.slots_per_epoch); let domain = spec.get_domain(epoch, Domain::BeaconBlock, fork); self.block.signature = Signature::new(&message, domain, sk); From b9ab3b25236863e8aac3fe4fe706180a7b25a07a Mon Sep 17 00:00:00 2001 From: Darren Langley Date: Thu, 16 May 2019 23:06:41 +1000 Subject: [PATCH 9/9] fake sig back, merge, and fixed up yml checkin issue --- eth2/state_processing/Cargo.toml | 3 ++ .../block_processing_builder.rs | 14 +++++-- .../src/per_block_processing/tests.rs | 42 ++++++++++++------- .../testing_beacon_block_builder.rs | 5 +++ eth2/utils/bls/src/fake_signature.rs | 8 ++++ 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/eth2/state_processing/Cargo.toml b/eth2/state_processing/Cargo.toml index 4b031022a..0fc7910c8 100644 --- a/eth2/state_processing/Cargo.toml +++ b/eth2/state_processing/Cargo.toml @@ -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"] \ No newline at end of file diff --git a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs index fb9dbd153..307fc4a3d 100644 --- a/eth2/state_processing/src/per_block_processing/block_processing_builder.rs +++ b/eth2/state_processing/src/per_block_processing/block_processing_builder.rs @@ -1,14 +1,15 @@ use types::test_utils::{TestingBeaconBlockBuilder, TestingBeaconStateBuilder}; use types::*; +use tree_hash::SignedRoot; -pub struct BlockProcessingBuilder { - pub state_builder: TestingBeaconStateBuilder, +pub struct BlockProcessingBuilder { + pub state_builder: TestingBeaconStateBuilder, pub block_builder: TestingBeaconBlockBuilder, pub num_validators: usize, } -impl BlockProcessingBuilder { +impl BlockProcessingBuilder { pub fn new(num_validators: usize, spec: &ChainSpec) -> Self { let state_builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, &spec); @@ -30,12 +31,17 @@ impl BlockProcessingBuilder { self.state_builder.build_caches(&spec).unwrap(); } - pub fn build(mut self, randao_sk: Option, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { + pub fn build(mut self, randao_sk: Option, previous_block_root: Option, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { 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(); diff --git a/eth2/state_processing/src/per_block_processing/tests.rs b/eth2/state_processing/src/per_block_processing/tests.rs index 6ae7fd872..715c3e852 100644 --- a/eth2/state_processing/src/per_block_processing/tests.rs +++ b/eth2/state_processing/src/per_block_processing/tests.rs @@ -1,17 +1,17 @@ -#![cfg(test)] +#![cfg(all(test, not(feature = "fake_crypto")))] use super::block_processing_builder::BlockProcessingBuilder; use super::errors::*; use crate::per_block_processing; -use ssz::SignedRoot; -use types::{ChainSpec, Domain, Keypair, Signature, Slot}; +use tree_hash::SignedRoot; +use types::*; pub const VALIDATOR_COUNT: usize = 10; #[test] fn valid_block_ok() { - let spec = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); let builder = get_builder(&spec); - let (block, mut state) = builder.build(None, &spec); + let (block, mut state) = builder.build(None, None, &spec); let result = per_block_processing(&mut state, &block, &spec); @@ -20,9 +20,9 @@ fn valid_block_ok() { #[test] fn invalid_block_header_state_slot() { - let spec = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); let builder = get_builder(&spec); - let (mut block, mut state) = builder.build(None, &spec); + let (mut block, mut state) = builder.build(None, None, &spec); state.slot = Slot::new(133713); block.slot = Slot::new(424242); @@ -38,16 +38,30 @@ fn invalid_block_header_state_slot() { } #[test] -#[ignore] fn invalid_parent_block_root() { - // this will be changed in spec 0.5.1 to use signed 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 = ChainSpec::foundation(); + let spec = FoundationEthSpec::spec(); let builder = get_builder(&spec); - let (mut block, mut state) = builder.build(None, &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(); @@ -68,12 +82,12 @@ fn invalid_block_signature() { #[test] fn invalid_randao_reveal_signature() { - let spec = ChainSpec::foundation(); + 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), &spec); + let (block, mut state) = builder.build(Some(keypair.sk), None, &spec); let result = per_block_processing(&mut state, &block, &spec); @@ -84,7 +98,7 @@ fn invalid_randao_reveal_signature() { ); } -fn get_builder(spec: &ChainSpec) -> (BlockProcessingBuilder) { +fn get_builder(spec: &ChainSpec) -> (BlockProcessingBuilder) { let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec); // Set the state and block to be in the last slot of the 4th epoch. diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index 9c75bde0e..9dca6222a 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -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; diff --git a/eth2/utils/bls/src/fake_signature.rs b/eth2/utils/bls/src/fake_signature.rs index 0bf3d0a25..de16a05f3 100644 --- a/eth2/utils/bls/src/fake_signature.rs +++ b/eth2/utils/bls/src/fake_signature.rs @@ -14,6 +14,7 @@ use tree_hash::tree_hash_ssz_encoding_as_vector; #[derive(Debug, PartialEq, Clone, Eq)] pub struct FakeSignature { bytes: Vec, + 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");