From b6f4d1c968c53c13df399aef20b0f3e0eaa5037c Mon Sep 17 00:00:00 2001 From: Age Date: Sat, 15 Sep 2018 22:53:45 +1000 Subject: [PATCH 1/6] add initial attestation validation structure --- lighthouse/state/mod.rs | 1 + .../validation/attestation_validation.rs | 66 +++++++++++++++++++ lighthouse/state/validation/mod.rs | 1 + lighthouse/utils/errors.rs | 12 ++++ lighthouse/utils/mod.rs | 1 + 5 files changed, 81 insertions(+) create mode 100644 lighthouse/state/validation/attestation_validation.rs create mode 100644 lighthouse/state/validation/mod.rs create mode 100644 lighthouse/utils/errors.rs diff --git a/lighthouse/state/mod.rs b/lighthouse/state/mod.rs index d10acf8fd..2c938cf29 100644 --- a/lighthouse/state/mod.rs +++ b/lighthouse/state/mod.rs @@ -15,3 +15,4 @@ pub mod crosslink_record; pub mod shard_and_committee; pub mod transition; pub mod validator_record; +pub mod validation; diff --git a/lighthouse/state/validation/attestation_validation.rs b/lighthouse/state/validation/attestation_validation.rs new file mode 100644 index 000000000..483fef55a --- /dev/null +++ b/lighthouse/state/validation/attestation_validation.rs @@ -0,0 +1,66 @@ +use super::super::crystallized_state::CrystallizedState; +use super::super::active_state::ActiveState; +use super::super::attestation_record::AttestationRecord; +use super::super::block::Block; +use super::super::chain_config::ChainConfig; + +use ::utils::errors::AttestationValidationError; + +// implementation of validate_attestation in the v2.1 python reference implementation +// see: https://github.com/ethereum/beacon_chain/blob/a79ab2c6f03cbdabf2b6d9d435c26e2b216e09a5/beacon_chain/state/state_transition.py#L61 +pub fn validate_attestation( + crystallized_state: &CrystallizedState, + active_state: &ActiveState, + attestation: &AttestationRecord, + block: &Block, + chain_config: &ChainConfig) + -> Result { + + if !(attestation.slot < block.slot_number) { + return Err(AttestationValidationError::SlotTooHigh); + } + + if !(attestation.slot > (block.slot_number - chain_config.cycle_length as u64)) { + return Err(AttestationValidationError::SlotTooLow(format!("Attestation slot number too low\n\tFound: {:?}, Needed greater than: {:?}", attestation.slot, block.slot_number - chain_config.cycle_length as u64))); + } + + return Ok(true); + } + + +#[cfg(test)] +mod tests { + + use super::*; + // test helper functions + + fn generate_standard_state() -> ( + CrystallizedState, + ActiveState, + AttestationRecord, + Block, + ChainConfig) { + + let mut crystallized_state = CrystallizedState::zero(); + let mut active_state = ActiveState::zero(); + let mut attestation_record = AttestationRecord::zero(); + let mut block = Block::zero(); + let chain_config = ChainConfig::standard(); + + return (crystallized_state, active_state, attestation_record, block, chain_config); + + } + + + #[test] + fn test_attestation_validation_slot_high() { + // generate standard state + let (mut crystallized_state, mut active_state, mut attestation_record, mut block, mut chain_config) = generate_standard_state(); + // set slot too high + attestation_record.slot = 30; + block.slot_number = 10; + + let result = validate_attestation(&crystallized_state, &active_state, &attestation_record, &block, &chain_config); + assert_eq!(result, Err(AttestationValidationError::SlotTooHigh)); + } +} diff --git a/lighthouse/state/validation/mod.rs b/lighthouse/state/validation/mod.rs new file mode 100644 index 000000000..98db2cb66 --- /dev/null +++ b/lighthouse/state/validation/mod.rs @@ -0,0 +1 @@ +mod attestation_validation; diff --git a/lighthouse/utils/errors.rs b/lighthouse/utils/errors.rs new file mode 100644 index 000000000..4f12cfbdd --- /dev/null +++ b/lighthouse/utils/errors.rs @@ -0,0 +1,12 @@ +// Collection of custom errors + +#[derive(Debug,PartialEq)] +pub enum AttestationValidationError { + SlotTooHigh, + SlotTooLow(String), + IncorrectBitField, + NonZeroTrailingBits, + AggregateSignatureFail +} + + diff --git a/lighthouse/utils/mod.rs b/lighthouse/utils/mod.rs index d116422be..4cb6ddf38 100644 --- a/lighthouse/utils/mod.rs +++ b/lighthouse/utils/mod.rs @@ -7,3 +7,4 @@ pub mod types; pub mod bls; pub mod test_helpers; pub mod logging; +pub mod errors; From b8ca18f87bdcf6bdffe0047d2f0d57517beb0440 Mon Sep 17 00:00:00 2001 From: Age Date: Sat, 15 Sep 2018 23:22:05 +1000 Subject: [PATCH 2/6] correct attestation warnings, add unit test --- .../validation/attestation_validation.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lighthouse/state/validation/attestation_validation.rs b/lighthouse/state/validation/attestation_validation.rs index 483fef55a..4e0707dc3 100644 --- a/lighthouse/state/validation/attestation_validation.rs +++ b/lighthouse/state/validation/attestation_validation.rs @@ -41,21 +41,20 @@ mod tests { Block, ChainConfig) { - let mut crystallized_state = CrystallizedState::zero(); - let mut active_state = ActiveState::zero(); - let mut attestation_record = AttestationRecord::zero(); - let mut block = Block::zero(); + let crystallized_state = CrystallizedState::zero(); + let active_state = ActiveState::zero(); + let attestation_record = AttestationRecord::zero(); + let block = Block::zero(); let chain_config = ChainConfig::standard(); return (crystallized_state, active_state, attestation_record, block, chain_config); - } #[test] fn test_attestation_validation_slot_high() { // generate standard state - let (mut crystallized_state, mut active_state, mut attestation_record, mut block, mut chain_config) = generate_standard_state(); + let (crystallized_state, active_state, mut attestation_record, mut block, chain_config) = generate_standard_state(); // set slot too high attestation_record.slot = 30; block.slot_number = 10; @@ -63,4 +62,16 @@ mod tests { let result = validate_attestation(&crystallized_state, &active_state, &attestation_record, &block, &chain_config); assert_eq!(result, Err(AttestationValidationError::SlotTooHigh)); } + + #[test] + fn test_attestation_validation_slot_low() { + // generate standard state + let (crystallized_state, active_state, mut attestation_record, mut block, chain_config) = generate_standard_state(); + // set slot too high + attestation_record.slot = 2; + block.slot_number = 10; + + let result = validate_attestation(&crystallized_state, &active_state, &attestation_record, &block, &chain_config); + //assert_eq!(result, Err(AttestationValidationError::SlotTooLow)); + } } From 815180d88c338394d2e9af455a9fac9e388f6d85 Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 19 Sep 2018 14:00:35 +1000 Subject: [PATCH 3/6] Adds assert_error macro --- lighthouse/main.rs | 3 ++- lighthouse/utils/macros.rs | 10 ++++++++++ lighthouse/utils/mod.rs | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 lighthouse/utils/macros.rs diff --git a/lighthouse/main.rs b/lighthouse/main.rs index 0a9f35288..7f5e4f7ea 100644 --- a/lighthouse/main.rs +++ b/lighthouse/main.rs @@ -6,11 +6,12 @@ extern crate clap; extern crate network_libp2p; extern crate futures; +#[macro_use] +pub mod utils; pub mod db; pub mod client; pub mod state; pub mod sync; -pub mod utils; pub mod config; use std::path::PathBuf; diff --git a/lighthouse/utils/macros.rs b/lighthouse/utils/macros.rs new file mode 100644 index 000000000..e6e3be01e --- /dev/null +++ b/lighthouse/utils/macros.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! assert_error { + ($exp: expr, $err: expr) => { + if ( !$exp ) { + return Err($err); + } + } +} + + diff --git a/lighthouse/utils/mod.rs b/lighthouse/utils/mod.rs index 4cb6ddf38..4d2ae3942 100644 --- a/lighthouse/utils/mod.rs +++ b/lighthouse/utils/mod.rs @@ -3,8 +3,12 @@ extern crate blake2; extern crate crypto_mac; extern crate boolean_bitfield; +#[macro_use] +pub mod macros; pub mod types; pub mod bls; pub mod test_helpers; pub mod logging; pub mod errors; + + From 27581c0ff4e191313af8257a402c7ac65b9a642c Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 19 Sep 2018 16:25:39 +1000 Subject: [PATCH 4/6] Implement generalised error ParameterError --- .../state/transition/attestation_parent_hashes.rs | 14 +++++++------- lighthouse/state/transition/mod.rs | 7 +------ lighthouse/utils/errors.rs | 11 ++++++++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lighthouse/state/transition/attestation_parent_hashes.rs b/lighthouse/state/transition/attestation_parent_hashes.rs index 624d8c443..f635972b2 100644 --- a/lighthouse/state/transition/attestation_parent_hashes.rs +++ b/lighthouse/state/transition/attestation_parent_hashes.rs @@ -1,5 +1,5 @@ use super::Hash256; -use super::TransitionError; +use super::ParameterError; /// This function is used to select the hashes used in /// the signing of an AttestationRecord. @@ -18,22 +18,22 @@ pub fn attestation_parent_hashes( attestation_slot: &u64, current_hashes: &Vec, oblique_hashes: &Vec) - -> Result, TransitionError> + -> Result, ParameterError> { // This cast places a limit on cycle_length. If you change it, check math // for overflow. let cycle_length: u64 = *cycle_length as u64; if current_hashes.len() as u64 != (cycle_length * 2) { - return Err(TransitionError::InvalidInput(String::from( + return Err(ParameterError::InvalidInput(String::from( "current_hashes.len() must equal cycle_length * 2"))); } if attestation_slot >= block_slot { - return Err(TransitionError::InvalidInput(String::from( + return Err(ParameterError::InvalidInput(String::from( "attestation_slot must be less than block_slot"))); } if oblique_hashes.len() as u64 > cycle_length { - return Err(TransitionError::InvalidInput(String::from( + return Err(ParameterError::InvalidInput(String::from( "oblique_hashes.len() must be <= cycle_length * 2"))); } @@ -44,7 +44,7 @@ pub fn attestation_parent_hashes( let attestation_distance = block_slot - attestation_slot; if attestation_distance > cycle_length { - return Err(TransitionError::InvalidInput(String::from( + return Err(ParameterError::InvalidInput(String::from( "attestation_slot must be withing one cycle of block_slot"))); } @@ -63,7 +63,7 @@ pub fn attestation_parent_hashes( */ let end = start.checked_add(cycle_length) .and_then(|x| x.checked_sub(oblique_hashes.len() as u64)) - .ok_or(TransitionError::IntWrapping)?; + .ok_or(ParameterError::IntWrapping)?; let mut hashes = Vec::new(); diff --git a/lighthouse/state/transition/mod.rs b/lighthouse/state/transition/mod.rs index dd8967e65..f3da91027 100644 --- a/lighthouse/state/transition/mod.rs +++ b/lighthouse/state/transition/mod.rs @@ -1,4 +1,5 @@ use super::super::utils::types::Hash256; +use super::super::utils::errors::ParameterError; mod attestation_parent_hashes; mod shuffling; @@ -6,12 +7,6 @@ mod shuffling; pub use self::attestation_parent_hashes::attestation_parent_hashes; pub use self::shuffling::shuffle; -#[derive(Debug)] -pub enum TransitionError { - IntWrapping, - OutOfBounds, - InvalidInput(String), -} diff --git a/lighthouse/utils/errors.rs b/lighthouse/utils/errors.rs index 4f12cfbdd..2a25b29b8 100644 --- a/lighthouse/utils/errors.rs +++ b/lighthouse/utils/errors.rs @@ -1,7 +1,7 @@ -// Collection of custom errors +// Collection of custom errors #[derive(Debug,PartialEq)] -pub enum AttestationValidationError { +pub enum AttestationValidationError { SlotTooHigh, SlotTooLow(String), IncorrectBitField, @@ -9,4 +9,9 @@ pub enum AttestationValidationError { AggregateSignatureFail } - +#[derive(Debug,PartialEq)] +pub enum ParameterError { + IntWrapping, + OutOfBounds, + InvalidInput(String), +} From 7e1819f69367db601fd988b519ac21fa5bb88d35 Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 19 Sep 2018 16:27:19 +1000 Subject: [PATCH 5/6] add helpers - implement get_block_hash --- lighthouse/state/helpers.rs | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 lighthouse/state/helpers.rs diff --git a/lighthouse/state/helpers.rs b/lighthouse/state/helpers.rs new file mode 100644 index 000000000..388fedafb --- /dev/null +++ b/lighthouse/state/helpers.rs @@ -0,0 +1,71 @@ +/* + * Collection of helper functions used in the state transition modules + */ +use super::active_state::ActiveState; +use super::block::Block; +use super::chain_config::ChainConfig; +use super::utils::errors::ParameterError; +use super::utils::types::Hash256; + +/* + pub fn get_signed_parent_hashes( + active_state: &ActiveState, + block: &Block, + attestation: &AttestationRecord, + chain_config: &ChainConfig) + -> Vec { + } + */ + +pub fn get_block_hash( + active_state_recent_block_hashes: &Vec, + current_block_slot: &u64, + slot: &u64, + cycle_length: &u64, // convert from standard u8 +) -> Result { + // active_state must have at 2*cycle_length hashes + assert_error!( + active_state_recent_block_hashes.len() as u64 == cycle_length * 2, + ParameterError::InvalidInput(String::from( + "active state has incorrect number of block hashes" + )) + ); + + let state_start_slot = (*current_block_slot) + .checked_sub(cycle_length * 2) + .unwrap_or(0); + + assert_error!( + (state_start_slot <= *slot) && (*slot < *current_block_slot), + ParameterError::InvalidInput(String::from("incorrect slot number")) + ); + + let index = 2 * cycle_length + (*slot) - *current_block_slot; // should always be positive + Ok(active_state_recent_block_hashes[index as usize]) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_block_hash() { + let block_slot: u64 = 10; + let slot: u64 = 3; + let cycle_length: u64 = 8; + + let mut block_hashes: Vec = Vec::new(); + for _i in 0..2 * cycle_length { + block_hashes.push(Hash256::random()); + } + + let result = get_block_hash(&block_hashes, &block_slot, &slot, &cycle_length).unwrap(); + + assert_eq!( + result, + block_hashes[(2 * cycle_length + slot - block_slot) as usize] + ); + + println!("{:?}", result); + } +} From 048f8b6f0101f76823f727d08c814f439cd491ae Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 19 Sep 2018 16:29:29 +1000 Subject: [PATCH 6/6] slight corrections to attestation validation --- lighthouse/state/mod.rs | 1 + .../validation/attestation_validation.rs | 48 ++++++++++--------- lighthouse/state/validation/mod.rs | 6 +++ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/lighthouse/state/mod.rs b/lighthouse/state/mod.rs index 2c938cf29..a245056a1 100644 --- a/lighthouse/state/mod.rs +++ b/lighthouse/state/mod.rs @@ -16,3 +16,4 @@ pub mod shard_and_committee; pub mod transition; pub mod validator_record; pub mod validation; +pub mod helpers; diff --git a/lighthouse/state/validation/attestation_validation.rs b/lighthouse/state/validation/attestation_validation.rs index 4e0707dc3..470432063 100644 --- a/lighthouse/state/validation/attestation_validation.rs +++ b/lighthouse/state/validation/attestation_validation.rs @@ -1,20 +1,20 @@ -use super::super::crystallized_state::CrystallizedState; -use super::super::active_state::ActiveState; -use super::super::attestation_record::AttestationRecord; -use super::super::block::Block; -use super::super::chain_config::ChainConfig; +use super::CrystallizedState; +use super::ActiveState; +use super::AttestationRecord; +use super::Block; +use super::ChainConfig; use ::utils::errors::AttestationValidationError; // implementation of validate_attestation in the v2.1 python reference implementation // see: https://github.com/ethereum/beacon_chain/blob/a79ab2c6f03cbdabf2b6d9d435c26e2b216e09a5/beacon_chain/state/state_transition.py#L61 pub fn validate_attestation( - crystallized_state: &CrystallizedState, + crystallized_state: &CrystallizedState, active_state: &ActiveState, attestation: &AttestationRecord, block: &Block, - chain_config: &ChainConfig) - -> Result { + chain_config: &ChainConfig) + -> Result { if !(attestation.slot < block.slot_number) { return Err(AttestationValidationError::SlotTooHigh); @@ -24,24 +24,24 @@ pub fn validate_attestation( return Err(AttestationValidationError::SlotTooLow(format!("Attestation slot number too low\n\tFound: {:?}, Needed greater than: {:?}", attestation.slot, block.slot_number - chain_config.cycle_length as u64))); } - return Ok(true); + Ok(true) } #[cfg(test)] -mod tests { +mod tests { use super::*; // test helper functions - - fn generate_standard_state() -> ( - CrystallizedState, - ActiveState, - AttestationRecord, - Block, - ChainConfig) { - let crystallized_state = CrystallizedState::zero(); + fn generate_standard_state() -> ( + CrystallizedState, + ActiveState, + AttestationRecord, + Block, + ChainConfig) { + + let crystallized_state = CrystallizedState::zero(); let active_state = ActiveState::zero(); let attestation_record = AttestationRecord::zero(); let block = Block::zero(); @@ -49,10 +49,9 @@ mod tests { return (crystallized_state, active_state, attestation_record, block, chain_config); } - #[test] - fn test_attestation_validation_slot_high() { + fn test_attestation_validation_slot_high() { // generate standard state let (crystallized_state, active_state, mut attestation_record, mut block, chain_config) = generate_standard_state(); // set slot too high @@ -64,14 +63,19 @@ mod tests { } #[test] - fn test_attestation_validation_slot_low() { + fn test_attestation_validation_slot_low() { // generate standard state let (crystallized_state, active_state, mut attestation_record, mut block, chain_config) = generate_standard_state(); // set slot too high attestation_record.slot = 2; block.slot_number = 10; - let result = validate_attestation(&crystallized_state, &active_state, &attestation_record, &block, &chain_config); + let result = validate_attestation( + &crystallized_state, + &active_state, + &attestation_record, + &block, + &chain_config); //assert_eq!(result, Err(AttestationValidationError::SlotTooLow)); } } diff --git a/lighthouse/state/validation/mod.rs b/lighthouse/state/validation/mod.rs index 98db2cb66..c11b65261 100644 --- a/lighthouse/state/validation/mod.rs +++ b/lighthouse/state/validation/mod.rs @@ -1 +1,7 @@ +use super::crystallized_state::CrystallizedState; +use super::active_state::ActiveState; +use super::attestation_record::AttestationRecord; +use super::block::Block; +use super::chain_config::ChainConfig; + mod attestation_validation;