From 2a1433d329df8743fac83657134b7c364c05c3d8 Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 3 Oct 2018 00:02:53 +1000 Subject: [PATCH 01/12] moved code from Paul's get_new_shuffling branch --- .../types/src/common/delegation/mod.rs | 25 +++ .../types/src/common/delegation/validator.rs | 206 ++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 beacon_chain/types/src/common/delegation/validator.rs diff --git a/beacon_chain/types/src/common/delegation/mod.rs b/beacon_chain/types/src/common/delegation/mod.rs index da9746f63..da75da240 100644 --- a/beacon_chain/types/src/common/delegation/mod.rs +++ b/beacon_chain/types/src/common/delegation/mod.rs @@ -1,3 +1,28 @@ mod block_hash; +mod validator; use super::utils; + +/// Produce a vector of validators indicies where those +/// validators start and end dynasties are within the supplied +/// `dynasty`. +pub fn active_validator_indicies( + dynasty: &u64, + validators: &Vec) + -> Vec +{ + validators.iter() + .enumerate() + .filter_map(|(i, validator)| { + if (validator.start_dynasty >= *dynasty) & + (validator.end_dynasty < *dynasty) + { + Some(i) + } else { + None + } + }) + .collect() +} + + diff --git a/beacon_chain/types/src/common/delegation/validator.rs b/beacon_chain/types/src/common/delegation/validator.rs new file mode 100644 index 000000000..594186db5 --- /dev/null +++ b/beacon_chain/types/src/common/delegation/validator.rs @@ -0,0 +1,206 @@ +use super::active_validator_indicies; + +type DelegatedSlot = Vec; +type DelegatedCycle = Vec; + +/* + * Delegates active validators into slots for a given cycle, given a random seed. + * Returns a vector or ShardAndComitte vectors representing the shards and committiees for + * each slot. + * References get_new_shuffling (ethereum 2.1 specification) + */ +pub fn delegate_validators( + seed: &[u8], + validators: &Vec, + dynasty: &u64, + crosslinking_shard_start: &u16, + config: &ChainConfig) + -> Result +{ + let shuffled_validator_indices = { + let mut validator_indices = active_validator_indicies(dynasty, validators); + match shuffle(seed, validator_indices) { + Ok(shuffled) => shuffled, + _ => return Err(TransitionError::InvalidInput( + String::from("Shuffle list length exceed."))) + } + }; + let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect(); + let crosslinking_shard_start = *crosslinking_shard_start as usize; + let cycle_length = config.cycle_length as usize; + let min_committee_size = config.min_committee_size as usize; + generate_cycle( + &shuffled_validator_indices, + &shard_indices, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size) +} + +/* + * Given the validator list, delegates the validators into slots and comittees for a given cycle. + */ +fn generate_cycle( + validator_indices: &Vec, + shard_indices: &Vec, + crosslinking_shard_start: &usize, + cycle_length: &usize, + min_committee_size: &usize) + -> Result +{ + let validator_count = validator_indices.len(); + let shard_count = shard_indices.len(); + + let (committees_per_slot, slots_per_committee) = { + if validator_count >= cycle_length * min_committee_size { + let committees_per_slot = validator_count / cycle_length / (min_committee_size * 2) + 1; + let slots_per_committee = 1; + (committees_per_slot, slots_per_committee) + } else { + let committees_per_slot = 1; + let mut slots_per_committee = 1; + while (validator_count * slots_per_committee < cycle_length * min_committee_size) & + (slots_per_committee < *cycle_length) { + slots_per_committee = slots_per_committee * 2; + } + (committees_per_slot, slots_per_committee) + } + }; + + let cycle = validator_indices + .chunks(validator_indices.len() / *cycle_length) + .enumerate() + .map(|(i, slot_indices)| { + let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee; + return slot_indices + .chunks(slot_indices.len() / committees_per_slot) + .enumerate() + .map(|(j, shard_indices)| { + return ShardAndCommittee{ + shard_id: ((shard_id_start + j) % shard_count) as u16, + committee: shard_indices.to_vec(), + } + }) + .collect() + }) + .collect(); + Ok(cycle) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn generate_cycle_helper( + validator_count: &usize, + shard_count: &usize, + crosslinking_shard_start: &usize, + cycle_length: &usize, + min_committee_size: &usize) + -> (Vec, Vec, Result) + { + let validator_indices = (0_usize..*validator_count).into_iter().collect(); + let shard_indices = (0_usize..*shard_count).into_iter().collect(); + let result = generate_cycle( + &validator_indices, + &shard_indices, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size); + (validator_indices, shard_indices, result) + } + + #[allow(dead_code)] + fn print_cycle(cycle: &DelegatedCycle) { + cycle.iter() + .enumerate() + .for_each(|(i, slot)| { + println!("slot {:?}", &i); + slot.iter() + .enumerate() + .for_each(|(i, sac)| { + println!("#{:?}\tshard_id={}\tcommittee.len()={}", + &i, &sac.shard_id, &sac.committee.len()) + }) + }); + } + + fn flatten_validators(cycle: &DelegatedCycle) + -> Vec + { + let mut flattened = vec![]; + for slot in cycle.iter() { + for sac in slot.iter() { + for validator in sac.committee.iter() { + flattened.push(*validator); + } + } + } + flattened + } + + fn flatten_and_dedup_shards(cycle: &DelegatedCycle) + -> Vec + { + let mut flattened = vec![]; + for slot in cycle.iter() { + for sac in slot.iter() { + flattened.push(sac.shard_id as usize); + } + } + flattened.dedup(); + flattened + } + + fn flatten_shards_in_slots(cycle: &DelegatedCycle) + -> Vec> + { + let mut shards_in_slots: Vec> = vec![]; + for slot in cycle.iter() { + let mut shards: Vec = vec![]; + for sac in slot.iter() { + shards.push(sac.shard_id as usize); + } + shards_in_slots.push(shards); + } + shards_in_slots + } + + + #[test] + fn test_generate_cycle() { + let validator_count: usize = 100; + let shard_count: usize = 10; + let crosslinking_shard_start: usize = 0; + let cycle_length: usize = 20; + let min_committee_size: usize = 10; + let (validators, shards, result) = generate_cycle_helper( + &validator_count, + &shard_count, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size); + let cycle = result.unwrap(); + + let assigned_validators = flatten_validators(&cycle); + let assigned_shards = flatten_and_dedup_shards(&cycle); + let shards_in_slots = flatten_shards_in_slots(&cycle); + assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); + assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); + + let expected_shards_in_slots: Vec> = vec![ + vec![0], vec![0], // Each line is 2 slots.. + vec![1], vec![1], + vec![2], vec![2], + vec![3], vec![3], + vec![4], vec![4], + vec![5], vec![5], + vec![6], vec![6], + vec![7], vec![7], + vec![8], vec![8], + vec![9], vec![9], + ]; + // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots)); + assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.") + } +} From d15b1d066dd9d98b6342ff8024dc934830ed1c4a Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 3 Oct 2018 15:25:15 +1000 Subject: [PATCH 02/12] Create transition crate --- Cargo.toml | 1 + beacon_chain/transition/Cargo.toml | 8 + beacon_chain/transition/src/lib.rs | 9 + .../types/src/common/delegation/block_hash.rs | 62 ------ .../types/src/common/delegation/mod.rs | 28 --- .../types/src/common/delegation/validator.rs | 206 ------------------ 6 files changed, 18 insertions(+), 296 deletions(-) create mode 100644 beacon_chain/transition/Cargo.toml create mode 100644 beacon_chain/transition/src/lib.rs delete mode 100644 beacon_chain/types/src/common/delegation/block_hash.rs delete mode 100644 beacon_chain/types/src/common/delegation/mod.rs delete mode 100644 beacon_chain/types/src/common/delegation/validator.rs diff --git a/Cargo.toml b/Cargo.toml index de69506de..9f328191a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ name = "lighthouse" [workspace] members = [ "beacon_chain/types", + "beacon_chain/transition", "beacon_chain/utils/bls", "beacon_chain/utils/boolean-bitfield", "beacon_chain/utils/hashing", diff --git a/beacon_chain/transition/Cargo.toml b/beacon_chain/transition/Cargo.toml new file mode 100644 index 000000000..abf1fe6dc --- /dev/null +++ b/beacon_chain/transition/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "transition" +version = "0.1.0" +authors = ["Age Manning "] + +[dependencies] +types = { path = "../types" } +shuffling = { path = "../utils/shuffling" } diff --git a/beacon_chain/transition/src/lib.rs b/beacon_chain/transition/src/lib.rs new file mode 100644 index 000000000..a86777e9b --- /dev/null +++ b/beacon_chain/transition/src/lib.rs @@ -0,0 +1,9 @@ +extern crate types; +extern crate shuffling; + +pub mod delegation; + +#[derive(Debug)] +pub enum TransitionError { + InvalidInput(String), +} diff --git a/beacon_chain/types/src/common/delegation/block_hash.rs b/beacon_chain/types/src/common/delegation/block_hash.rs deleted file mode 100644 index 3d0939d29..000000000 --- a/beacon_chain/types/src/common/delegation/block_hash.rs +++ /dev/null @@ -1,62 +0,0 @@ -use super::utils::errors::ParameterError; -use super::utils::types::Hash256; - -/* - * Work-in-progress function: not ready for review. - */ - -pub fn get_block_hash( - active_state_recent_block_hashes: &[Hash256], - 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] - ); - } -} diff --git a/beacon_chain/types/src/common/delegation/mod.rs b/beacon_chain/types/src/common/delegation/mod.rs deleted file mode 100644 index da75da240..000000000 --- a/beacon_chain/types/src/common/delegation/mod.rs +++ /dev/null @@ -1,28 +0,0 @@ -mod block_hash; -mod validator; - -use super::utils; - -/// Produce a vector of validators indicies where those -/// validators start and end dynasties are within the supplied -/// `dynasty`. -pub fn active_validator_indicies( - dynasty: &u64, - validators: &Vec) - -> Vec -{ - validators.iter() - .enumerate() - .filter_map(|(i, validator)| { - if (validator.start_dynasty >= *dynasty) & - (validator.end_dynasty < *dynasty) - { - Some(i) - } else { - None - } - }) - .collect() -} - - diff --git a/beacon_chain/types/src/common/delegation/validator.rs b/beacon_chain/types/src/common/delegation/validator.rs deleted file mode 100644 index 594186db5..000000000 --- a/beacon_chain/types/src/common/delegation/validator.rs +++ /dev/null @@ -1,206 +0,0 @@ -use super::active_validator_indicies; - -type DelegatedSlot = Vec; -type DelegatedCycle = Vec; - -/* - * Delegates active validators into slots for a given cycle, given a random seed. - * Returns a vector or ShardAndComitte vectors representing the shards and committiees for - * each slot. - * References get_new_shuffling (ethereum 2.1 specification) - */ -pub fn delegate_validators( - seed: &[u8], - validators: &Vec, - dynasty: &u64, - crosslinking_shard_start: &u16, - config: &ChainConfig) - -> Result -{ - let shuffled_validator_indices = { - let mut validator_indices = active_validator_indicies(dynasty, validators); - match shuffle(seed, validator_indices) { - Ok(shuffled) => shuffled, - _ => return Err(TransitionError::InvalidInput( - String::from("Shuffle list length exceed."))) - } - }; - let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect(); - let crosslinking_shard_start = *crosslinking_shard_start as usize; - let cycle_length = config.cycle_length as usize; - let min_committee_size = config.min_committee_size as usize; - generate_cycle( - &shuffled_validator_indices, - &shard_indices, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size) -} - -/* - * Given the validator list, delegates the validators into slots and comittees for a given cycle. - */ -fn generate_cycle( - validator_indices: &Vec, - shard_indices: &Vec, - crosslinking_shard_start: &usize, - cycle_length: &usize, - min_committee_size: &usize) - -> Result -{ - let validator_count = validator_indices.len(); - let shard_count = shard_indices.len(); - - let (committees_per_slot, slots_per_committee) = { - if validator_count >= cycle_length * min_committee_size { - let committees_per_slot = validator_count / cycle_length / (min_committee_size * 2) + 1; - let slots_per_committee = 1; - (committees_per_slot, slots_per_committee) - } else { - let committees_per_slot = 1; - let mut slots_per_committee = 1; - while (validator_count * slots_per_committee < cycle_length * min_committee_size) & - (slots_per_committee < *cycle_length) { - slots_per_committee = slots_per_committee * 2; - } - (committees_per_slot, slots_per_committee) - } - }; - - let cycle = validator_indices - .chunks(validator_indices.len() / *cycle_length) - .enumerate() - .map(|(i, slot_indices)| { - let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee; - return slot_indices - .chunks(slot_indices.len() / committees_per_slot) - .enumerate() - .map(|(j, shard_indices)| { - return ShardAndCommittee{ - shard_id: ((shard_id_start + j) % shard_count) as u16, - committee: shard_indices.to_vec(), - } - }) - .collect() - }) - .collect(); - Ok(cycle) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn generate_cycle_helper( - validator_count: &usize, - shard_count: &usize, - crosslinking_shard_start: &usize, - cycle_length: &usize, - min_committee_size: &usize) - -> (Vec, Vec, Result) - { - let validator_indices = (0_usize..*validator_count).into_iter().collect(); - let shard_indices = (0_usize..*shard_count).into_iter().collect(); - let result = generate_cycle( - &validator_indices, - &shard_indices, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size); - (validator_indices, shard_indices, result) - } - - #[allow(dead_code)] - fn print_cycle(cycle: &DelegatedCycle) { - cycle.iter() - .enumerate() - .for_each(|(i, slot)| { - println!("slot {:?}", &i); - slot.iter() - .enumerate() - .for_each(|(i, sac)| { - println!("#{:?}\tshard_id={}\tcommittee.len()={}", - &i, &sac.shard_id, &sac.committee.len()) - }) - }); - } - - fn flatten_validators(cycle: &DelegatedCycle) - -> Vec - { - let mut flattened = vec![]; - for slot in cycle.iter() { - for sac in slot.iter() { - for validator in sac.committee.iter() { - flattened.push(*validator); - } - } - } - flattened - } - - fn flatten_and_dedup_shards(cycle: &DelegatedCycle) - -> Vec - { - let mut flattened = vec![]; - for slot in cycle.iter() { - for sac in slot.iter() { - flattened.push(sac.shard_id as usize); - } - } - flattened.dedup(); - flattened - } - - fn flatten_shards_in_slots(cycle: &DelegatedCycle) - -> Vec> - { - let mut shards_in_slots: Vec> = vec![]; - for slot in cycle.iter() { - let mut shards: Vec = vec![]; - for sac in slot.iter() { - shards.push(sac.shard_id as usize); - } - shards_in_slots.push(shards); - } - shards_in_slots - } - - - #[test] - fn test_generate_cycle() { - let validator_count: usize = 100; - let shard_count: usize = 10; - let crosslinking_shard_start: usize = 0; - let cycle_length: usize = 20; - let min_committee_size: usize = 10; - let (validators, shards, result) = generate_cycle_helper( - &validator_count, - &shard_count, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size); - let cycle = result.unwrap(); - - let assigned_validators = flatten_validators(&cycle); - let assigned_shards = flatten_and_dedup_shards(&cycle); - let shards_in_slots = flatten_shards_in_slots(&cycle); - assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); - assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); - - let expected_shards_in_slots: Vec> = vec![ - vec![0], vec![0], // Each line is 2 slots.. - vec![1], vec![1], - vec![2], vec![2], - vec![3], vec![3], - vec![4], vec![4], - vec![5], vec![5], - vec![6], vec![6], - vec![7], vec![7], - vec![8], vec![8], - vec![9], vec![9], - ]; - // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots)); - assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.") - } -} From e79a1341e9c1ae4c4a1faa86b6932e4e0882aee2 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 3 Oct 2018 15:26:41 +1000 Subject: [PATCH 03/12] add delegation logic to transition crate --- .../transition/src/delegation/block_hash.rs | 62 +++++ beacon_chain/transition/src/delegation/mod.rs | 6 + .../transition/src/delegation/validator.rs | 232 ++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 beacon_chain/transition/src/delegation/block_hash.rs create mode 100644 beacon_chain/transition/src/delegation/mod.rs create mode 100644 beacon_chain/transition/src/delegation/validator.rs diff --git a/beacon_chain/transition/src/delegation/block_hash.rs b/beacon_chain/transition/src/delegation/block_hash.rs new file mode 100644 index 000000000..3d0939d29 --- /dev/null +++ b/beacon_chain/transition/src/delegation/block_hash.rs @@ -0,0 +1,62 @@ +use super::utils::errors::ParameterError; +use super::utils::types::Hash256; + +/* + * Work-in-progress function: not ready for review. + */ + +pub fn get_block_hash( + active_state_recent_block_hashes: &[Hash256], + 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] + ); + } +} diff --git a/beacon_chain/transition/src/delegation/mod.rs b/beacon_chain/transition/src/delegation/mod.rs new file mode 100644 index 000000000..2bc9bccd2 --- /dev/null +++ b/beacon_chain/transition/src/delegation/mod.rs @@ -0,0 +1,6 @@ +use super::types; +use super::TransitionError; +use super::shuffling::shuffle; + +// mod block_hash; +pub mod validator; diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs new file mode 100644 index 000000000..426b1a5e3 --- /dev/null +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -0,0 +1,232 @@ +use super::types::{ShardAndCommittee, ValidatorRecord, ChainConfig}; +use super::TransitionError; +use super::shuffle; + +type DelegatedSlot = Vec; +type DelegatedCycle = Vec; + + +/* Produce a vector of validators indicies where those validators start and end + * dynasties are within the supplied `dynasty`. +*/ +fn active_validator_indicies( + dynasty: &u64, + validators: &Vec) + -> Vec +{ + validators.iter() + .enumerate() + .filter_map(|(i, validator)| { + if (validator.start_dynasty >= *dynasty) & + (validator.end_dynasty < *dynasty) + { + Some(i) + } else { + None + } + }) + .collect() +} + + +/* + * Delegates active validators into slots for a given cycle, given a random seed. + * Returns a vector or ShardAndComitte vectors representing the shards and committiees for + * each slot. + * References get_new_shuffling (ethereum 2.1 specification) + */ +pub fn delegate_validators( + seed: &[u8], + validators: &Vec, + dynasty: &u64, + crosslinking_shard_start: &u16, + config: &ChainConfig) + -> Result +{ + let shuffled_validator_indices = { + let mut validator_indices = active_validator_indicies(dynasty, validators); + match shuffle(seed, validator_indices) { + Ok(shuffled) => shuffled, + _ => return Err(TransitionError::InvalidInput( + String::from("Shuffle list length exceed."))) + } + }; + let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect(); + let crosslinking_shard_start = *crosslinking_shard_start as usize; + let cycle_length = config.cycle_length as usize; + let min_committee_size = config.min_committee_size as usize; + generate_cycle( + &shuffled_validator_indices, + &shard_indices, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size) +} + +/* + * Given the validator list, delegates the validators into slots and comittees for a given cycle. + */ +fn generate_cycle( + validator_indices: &Vec, + shard_indices: &Vec, + crosslinking_shard_start: &usize, + cycle_length: &usize, + min_committee_size: &usize) + -> Result +{ + let validator_count = validator_indices.len(); + let shard_count = shard_indices.len(); + + let (committees_per_slot, slots_per_committee) = { + if validator_count >= cycle_length * min_committee_size { + let committees_per_slot = validator_count / cycle_length / (min_committee_size * 2) + 1; + let slots_per_committee = 1; + (committees_per_slot, slots_per_committee) + } else { + let committees_per_slot = 1; + let mut slots_per_committee = 1; + while (validator_count * slots_per_committee < cycle_length * min_committee_size) & + (slots_per_committee < *cycle_length) { + slots_per_committee = slots_per_committee * 2; + } + (committees_per_slot, slots_per_committee) + } + }; + + let cycle = validator_indices + .chunks(validator_indices.len() / *cycle_length) + .enumerate() + .map(|(i, slot_indices)| { + let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee; + return slot_indices + .chunks(slot_indices.len() / committees_per_slot) + .enumerate() + .map(|(j, shard_indices)| { + return ShardAndCommittee{ + shard_id: ((shard_id_start + j) % shard_count) as u16, + committee: shard_indices.to_vec(), + } + }) + .collect() + }) + .collect(); + Ok(cycle) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn generate_cycle_helper( + validator_count: &usize, + shard_count: &usize, + crosslinking_shard_start: &usize, + cycle_length: &usize, + min_committee_size: &usize) + -> (Vec, Vec, Result) + { + let validator_indices = (0_usize..*validator_count).into_iter().collect(); + let shard_indices = (0_usize..*shard_count).into_iter().collect(); + let result = generate_cycle( + &validator_indices, + &shard_indices, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size); + (validator_indices, shard_indices, result) + } + + #[allow(dead_code)] + fn print_cycle(cycle: &DelegatedCycle) { + cycle.iter() + .enumerate() + .for_each(|(i, slot)| { + println!("slot {:?}", &i); + slot.iter() + .enumerate() + .for_each(|(i, sac)| { + println!("#{:?}\tshard_id={}\tcommittee.len()={}", + &i, &sac.shard_id, &sac.committee.len()) + }) + }); + } + + fn flatten_validators(cycle: &DelegatedCycle) + -> Vec + { + let mut flattened = vec![]; + for slot in cycle.iter() { + for sac in slot.iter() { + for validator in sac.committee.iter() { + flattened.push(*validator); + } + } + } + flattened + } + + fn flatten_and_dedup_shards(cycle: &DelegatedCycle) + -> Vec + { + let mut flattened = vec![]; + for slot in cycle.iter() { + for sac in slot.iter() { + flattened.push(sac.shard_id as usize); + } + } + flattened.dedup(); + flattened + } + + fn flatten_shards_in_slots(cycle: &DelegatedCycle) + -> Vec> + { + let mut shards_in_slots: Vec> = vec![]; + for slot in cycle.iter() { + let mut shards: Vec = vec![]; + for sac in slot.iter() { + shards.push(sac.shard_id as usize); + } + shards_in_slots.push(shards); + } + shards_in_slots + } + + + #[test] + fn test_generate_cycle() { + let validator_count: usize = 100; + let shard_count: usize = 10; + let crosslinking_shard_start: usize = 0; + let cycle_length: usize = 20; + let min_committee_size: usize = 10; + let (validators, shards, result) = generate_cycle_helper( + &validator_count, + &shard_count, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size); + let cycle = result.unwrap(); + + let assigned_validators = flatten_validators(&cycle); + let assigned_shards = flatten_and_dedup_shards(&cycle); + let shards_in_slots = flatten_shards_in_slots(&cycle); + assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); + assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); + + let expected_shards_in_slots: Vec> = vec![ + vec![0], vec![0], // Each line is 2 slots.. + vec![1], vec![1], + vec![2], vec![2], + vec![3], vec![3], + vec![4], vec![4], + vec![5], vec![5], + vec![6], vec![6], + vec![7], vec![7], + vec![8], vec![8], + vec![9], vec![9], + ]; + // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots)); + assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.") + } +} From 57e3f8c4653a9ba2f334d59d41de219b7cb86fec Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 3 Oct 2018 15:41:04 +1000 Subject: [PATCH 04/12] Correct get_new_shuffling. Closes #25 --- beacon_chain/transition/src/delegation/validator.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 426b1a5e3..760b6bab7 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -1,6 +1,7 @@ use super::types::{ShardAndCommittee, ValidatorRecord, ChainConfig}; use super::TransitionError; use super::shuffle; +use std::cmp::min; type DelegatedSlot = Vec; type DelegatedCycle = Vec; @@ -79,7 +80,9 @@ fn generate_cycle( let (committees_per_slot, slots_per_committee) = { if validator_count >= cycle_length * min_committee_size { - let committees_per_slot = validator_count / cycle_length / (min_committee_size * 2) + 1; + let committees_per_slot = min(validator_count / cycle_length / + (min_committee_size * 2) + 1, shard_count / + cycle_length); let slots_per_committee = 1; (committees_per_slot, slots_per_committee) } else { From 229351b38ec8988d8289d5dcdfa43d8d82d35e17 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 3 Oct 2018 18:47:18 +1000 Subject: [PATCH 05/12] Adds list splitting function and begins delegation testing --- .../transition/src/delegation/validator.rs | 61 +++++++++++++++++++ beacon_chain/types/src/chain_config.rs | 14 +++++ 2 files changed, 75 insertions(+) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 760b6bab7..0dc0d5f16 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -29,6 +29,19 @@ fn active_validator_indicies( .collect() } +/* + * splits a vector into chunks of size n. All postive n values are applicable, + * hence the honey_badger prefix. + */ +fn honey_badger_split(list: &Vec, n: usize) -> Vec> { + let mut split_list: Vec> = vec![]; + let list_length = list.len(); + for i in 0..n { + let partition = list.get(list_length*i/n..list_length*(i+1)/n).unwrap(); // cannot go out of bounds + split_list.push(partition.to_vec()); + } + split_list +} /* * Delegates active validators into slots for a given cycle, given a random seed. @@ -75,9 +88,17 @@ fn generate_cycle( min_committee_size: &usize) -> Result { + let validator_count = validator_indices.len(); let shard_count = shard_indices.len(); + if shard_count / cycle_length == 0 { + return Err(TransitionError::InvalidInput(String::from("Number of + shards needs to be greater than + cycle length"))); + + } + let (committees_per_slot, slots_per_committee) = { if validator_count >= cycle_length * min_committee_size { let committees_per_slot = min(validator_count / cycle_length / @@ -217,6 +238,46 @@ mod tests { assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); + let expected_shards_in_slots: Vec> = vec![ + vec![0], vec![0], // Each line is 2 slots.. + vec![1], vec![1], + vec![2], vec![2], + vec![3], vec![3], + vec![4], vec![4], + vec![5], vec![5], + vec![6], vec![6], + vec![7], vec![7], + vec![8], vec![8], + vec![9], vec![9], + ]; + // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots)); + assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.") + } + + #[test] + // Check that the committees per slot is upper bounded by shard count + fn test_generate_cycle_committees_bounded() { + let validator_count: usize = 101; + let shard_count: usize = 15; + let crosslinking_shard_start: usize = 0; + let cycle_length: usize = 10; + let min_committee_size: usize = 10; + let (validators, shards, result) = generate_cycle_helper( + &validator_count, + &shard_count, + &crosslinking_shard_start, + &cycle_length, + &min_committee_size); + let cycle = result.unwrap(); + + let assigned_validators = flatten_validators(&cycle); + let assigned_shards = flatten_and_dedup_shards(&cycle); + let shards_in_slots = flatten_shards_in_slots(&cycle); + print_cycle(&cycle); + assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); + assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); + + let expected_shards_in_slots: Vec> = vec![ vec![0], vec![0], // Each line is 2 slots.. vec![1], vec![1], diff --git a/beacon_chain/types/src/chain_config.rs b/beacon_chain/types/src/chain_config.rs index 750081aad..4cdc91a6d 100644 --- a/beacon_chain/types/src/chain_config.rs +++ b/beacon_chain/types/src/chain_config.rs @@ -20,6 +20,20 @@ impl ChainConfig { } } + pub fn validate(&self) -> bool { + // criteria that ensure the config is valid + + // shard_count / cycle_length > 0 otherwise validator delegation + // will fail. + if self.shard_count / self.cycle_length as u16 == 0 { + return false; + } + + true + } + + + #[cfg(test)] pub fn super_fast_tests() -> Self { Self { From c8d5f00d7cad7b11ce1d17479f290b8016471f25 Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 3 Oct 2018 21:57:21 +1000 Subject: [PATCH 06/12] Improve split function --- beacon_chain/transition/src/delegation/validator.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 0dc0d5f16..9c6019d72 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -37,7 +37,10 @@ fn honey_badger_split(list: &Vec, n: usize) -> Vec> { let mut split_list: Vec> = vec![]; let list_length = list.len(); for i in 0..n { - let partition = list.get(list_length*i/n..list_length*(i+1)/n).unwrap(); // cannot go out of bounds + let partition = match list.get(list_length*i/n..list_length*(i+1)/n) { + Some(v) => v, + None => unreachable!(), + }; split_list.push(partition.to_vec()); } split_list From 874a0babbb0f48717344e9bb9759bf54e7c10991 Mon Sep 17 00:00:00 2001 From: Age Date: Wed, 3 Oct 2018 23:37:54 +1000 Subject: [PATCH 07/12] Converts split function into an iterable trait --- .../transition/src/delegation/validator.rs | 76 +++++++++++++------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 9c6019d72..95f1a47df 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -6,6 +6,54 @@ use std::cmp::min; type DelegatedSlot = Vec; type DelegatedCycle = Vec; +/* + * Iterator for the honey_badger_split function + */ +struct Split<'a, T: 'a> { + n: usize, + current_pos: usize, + list: &'a [T], + list_length: usize +} + +impl<'a,T> Iterator for Split<'a, T> { + type Item = &'a [T]; + + fn next(&mut self) -> Option { + self.current_pos +=1; + if self.current_pos <= self.n { + match self.list.get(self.list_length*(self.current_pos-1)/self.n..self.list_length*self.current_pos/self.n) { + Some(v) => Some(v), + None => unreachable!() + } + } + else { + None + } + } +} + +/* + * splits a slice into chunks of size n. All postive n values are applicable, + * hence the honey_badger prefix. + * Returns an iterator over the original list. + */ +trait SplitExt { + fn honey_badger_split(&self, n: usize) -> Split; +} + +impl SplitExt for [T] { + + fn honey_badger_split(&self, n: usize) -> Split { + Split { + n: n, + current_pos: 0, + list: &self, + list_length: self.len(), + } + } +} + /* Produce a vector of validators indicies where those validators start and end * dynasties are within the supplied `dynasty`. @@ -29,23 +77,6 @@ fn active_validator_indicies( .collect() } -/* - * splits a vector into chunks of size n. All postive n values are applicable, - * hence the honey_badger prefix. - */ -fn honey_badger_split(list: &Vec, n: usize) -> Vec> { - let mut split_list: Vec> = vec![]; - let list_length = list.len(); - for i in 0..n { - let partition = match list.get(list_length*i/n..list_length*(i+1)/n) { - Some(v) => v, - None => unreachable!(), - }; - split_list.push(partition.to_vec()); - } - split_list -} - /* * Delegates active validators into slots for a given cycle, given a random seed. * Returns a vector or ShardAndComitte vectors representing the shards and committiees for @@ -120,13 +151,11 @@ fn generate_cycle( } }; - let cycle = validator_indices - .chunks(validator_indices.len() / *cycle_length) + let cycle = validator_indices.honey_badger_split(*cycle_length) .enumerate() .map(|(i, slot_indices)| { let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee; - return slot_indices - .chunks(slot_indices.len() / committees_per_slot) + return slot_indices.honey_badger_split(committees_per_slot) .enumerate() .map(|(j, shard_indices)| { return ShardAndCommittee{ @@ -260,7 +289,7 @@ mod tests { #[test] // Check that the committees per slot is upper bounded by shard count fn test_generate_cycle_committees_bounded() { - let validator_count: usize = 101; + let validator_count: usize = 1001; let shard_count: usize = 15; let crosslinking_shard_start: usize = 0; let cycle_length: usize = 10; @@ -272,11 +301,10 @@ mod tests { &cycle_length, &min_committee_size); let cycle = result.unwrap(); - + print_cycle(&cycle); let assigned_validators = flatten_validators(&cycle); let assigned_shards = flatten_and_dedup_shards(&cycle); let shards_in_slots = flatten_shards_in_slots(&cycle); - print_cycle(&cycle); assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); From 1858b2d32bcdd040948912f37f8b5d45e0c52635 Mon Sep 17 00:00:00 2001 From: Age Date: Thu, 4 Oct 2018 13:21:16 +1000 Subject: [PATCH 08/12] Corrects cycle tests --- .../transition/src/delegation/validator.rs | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 95f1a47df..45331c4c8 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -248,11 +248,11 @@ mod tests { shards_in_slots } - + // TODO: Improve these tests to check committee lengths #[test] fn test_generate_cycle() { let validator_count: usize = 100; - let shard_count: usize = 10; + let shard_count: usize = 20; let crosslinking_shard_start: usize = 0; let cycle_length: usize = 20; let min_committee_size: usize = 10; @@ -267,8 +267,9 @@ mod tests { let assigned_validators = flatten_validators(&cycle); let assigned_shards = flatten_and_dedup_shards(&cycle); let shards_in_slots = flatten_shards_in_slots(&cycle); + let expected_shards = shards.get(0..10).unwrap(); assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); - assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); + assert_eq!(assigned_shards, expected_shards, "Shard assignment incorrect"); let expected_shards_in_slots: Vec> = vec![ vec![0], vec![0], // Each line is 2 slots.. @@ -289,11 +290,11 @@ mod tests { #[test] // Check that the committees per slot is upper bounded by shard count fn test_generate_cycle_committees_bounded() { - let validator_count: usize = 1001; - let shard_count: usize = 15; + let validator_count: usize = 523; + let shard_count: usize = 31; let crosslinking_shard_start: usize = 0; - let cycle_length: usize = 10; - let min_committee_size: usize = 10; + let cycle_length: usize = 11; + let min_committee_size: usize = 5; let (validators, shards, result) = generate_cycle_helper( &validator_count, &shard_count, @@ -301,26 +302,14 @@ mod tests { &cycle_length, &min_committee_size); let cycle = result.unwrap(); - print_cycle(&cycle); let assigned_validators = flatten_validators(&cycle); let assigned_shards = flatten_and_dedup_shards(&cycle); let shards_in_slots = flatten_shards_in_slots(&cycle); + let expected_shards = shards.get(0..22).unwrap(); + let expected_shards_in_slots: Vec> = + (0_usize..11_usize) .map(|x| vec![2*x,2*x+1]).collect(); assert_eq!(assigned_validators, validators, "Validator assignment incorrect"); - assert_eq!(assigned_shards, shards, "Shard assignment incorrect"); - - - let expected_shards_in_slots: Vec> = vec![ - vec![0], vec![0], // Each line is 2 slots.. - vec![1], vec![1], - vec![2], vec![2], - vec![3], vec![3], - vec![4], vec![4], - vec![5], vec![5], - vec![6], vec![6], - vec![7], vec![7], - vec![8], vec![8], - vec![9], vec![9], - ]; + assert_eq!(assigned_shards, expected_shards, "Shard assignment incorrect"); // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots)); assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.") } From fd01ffc2a1922a9979e09b868cfe8171666959f2 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 5 Oct 2018 14:51:16 +1000 Subject: [PATCH 09/12] Removes block_hash.rs and adds minor clippy fixes --- .../transition/src/delegation/block_hash.rs | 62 ------------------- beacon_chain/transition/src/delegation/mod.rs | 1 - .../transition/src/delegation/validator.rs | 62 +++++++++---------- 3 files changed, 29 insertions(+), 96 deletions(-) delete mode 100644 beacon_chain/transition/src/delegation/block_hash.rs diff --git a/beacon_chain/transition/src/delegation/block_hash.rs b/beacon_chain/transition/src/delegation/block_hash.rs deleted file mode 100644 index 3d0939d29..000000000 --- a/beacon_chain/transition/src/delegation/block_hash.rs +++ /dev/null @@ -1,62 +0,0 @@ -use super::utils::errors::ParameterError; -use super::utils::types::Hash256; - -/* - * Work-in-progress function: not ready for review. - */ - -pub fn get_block_hash( - active_state_recent_block_hashes: &[Hash256], - 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] - ); - } -} diff --git a/beacon_chain/transition/src/delegation/mod.rs b/beacon_chain/transition/src/delegation/mod.rs index 2bc9bccd2..265b3e9b6 100644 --- a/beacon_chain/transition/src/delegation/mod.rs +++ b/beacon_chain/transition/src/delegation/mod.rs @@ -2,5 +2,4 @@ use super::types; use super::TransitionError; use super::shuffling::shuffle; -// mod block_hash; pub mod validator; diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 45331c4c8..41c4c0e4d 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -3,12 +3,9 @@ use super::TransitionError; use super::shuffle; use std::cmp::min; -type DelegatedSlot = Vec; -type DelegatedCycle = Vec; +type DelegatedCycle = Vec>; -/* - * Iterator for the honey_badger_split function - */ +/// Iterator for the honey_badger_split function struct Split<'a, T: 'a> { n: usize, current_pos: usize, @@ -33,11 +30,10 @@ impl<'a,T> Iterator for Split<'a, T> { } } -/* - * splits a slice into chunks of size n. All postive n values are applicable, - * hence the honey_badger prefix. - * Returns an iterator over the original list. - */ + +/// splits a slice into chunks of size n. All postive n values are applicable, +/// hence the honey_badger prefix. +/// Returns an iterator over the original list. trait SplitExt { fn honey_badger_split(&self, n: usize) -> Split; } @@ -46,7 +42,7 @@ impl SplitExt for [T] { fn honey_badger_split(&self, n: usize) -> Split { Split { - n: n, + n, current_pos: 0, list: &self, list_length: self.len(), @@ -59,15 +55,15 @@ impl SplitExt for [T] { * dynasties are within the supplied `dynasty`. */ fn active_validator_indicies( - dynasty: &u64, - validators: &Vec) + dynasty: u64, + validators: &[ValidatorRecord]) -> Vec { validators.iter() .enumerate() .filter_map(|(i, validator)| { - if (validator.start_dynasty >= *dynasty) & - (validator.end_dynasty < *dynasty) + if (validator.start_dynasty >= dynasty) & + (validator.end_dynasty < dynasty) { Some(i) } else { @@ -85,9 +81,9 @@ fn active_validator_indicies( */ pub fn delegate_validators( seed: &[u8], - validators: &Vec, - dynasty: &u64, - crosslinking_shard_start: &u16, + validators: &[ValidatorRecord], + dynasty: u64, + crosslinking_shard_start: u16, config: &ChainConfig) -> Result { @@ -99,27 +95,27 @@ pub fn delegate_validators( String::from("Shuffle list length exceed."))) } }; - let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect(); - let crosslinking_shard_start = *crosslinking_shard_start as usize; + let shard_indices: Vec = (0_usize..config.shard_count as usize).into_iter().collect(); + let crosslinking_shard_start = crosslinking_shard_start as usize; let cycle_length = config.cycle_length as usize; let min_committee_size = config.min_committee_size as usize; generate_cycle( &shuffled_validator_indices, &shard_indices, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size) + crosslinking_shard_start, + cycle_length, + min_committee_size) } /* * Given the validator list, delegates the validators into slots and comittees for a given cycle. */ fn generate_cycle( - validator_indices: &Vec, - shard_indices: &Vec, - crosslinking_shard_start: &usize, - cycle_length: &usize, - min_committee_size: &usize) + validator_indices: &[usize], + shard_indices: &[usize], + crosslinking_shard_start: usize, + cycle_length: usize, + min_committee_size: usize) -> Result { @@ -144,21 +140,21 @@ fn generate_cycle( let committees_per_slot = 1; let mut slots_per_committee = 1; while (validator_count * slots_per_committee < cycle_length * min_committee_size) & - (slots_per_committee < *cycle_length) { - slots_per_committee = slots_per_committee * 2; + (slots_per_committee < cycle_length) { + slots_per_committee *= 2; } (committees_per_slot, slots_per_committee) } }; - let cycle = validator_indices.honey_badger_split(*cycle_length) + let cycle = validator_indices.honey_badger_split(cycle_length) .enumerate() .map(|(i, slot_indices)| { let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee; - return slot_indices.honey_badger_split(committees_per_slot) + slot_indices.honey_badger_split(committees_per_slot) .enumerate() .map(|(j, shard_indices)| { - return ShardAndCommittee{ + ShardAndCommittee{ shard_id: ((shard_id_start + j) % shard_count) as u16, committee: shard_indices.to_vec(), } From 14e12db374f3ae6b4741f4c79239302686351b09 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 5 Oct 2018 14:53:21 +1000 Subject: [PATCH 10/12] Updates validation tests for clippy modifications --- .../transition/src/delegation/validator.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 41c4c0e4d..b745fa3f4 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -172,19 +172,19 @@ mod tests { fn generate_cycle_helper( validator_count: &usize, shard_count: &usize, - crosslinking_shard_start: &usize, - cycle_length: &usize, - min_committee_size: &usize) + crosslinking_shard_start: usize, + cycle_length: usize, + min_committee_size: usize) -> (Vec, Vec, Result) { - let validator_indices = (0_usize..*validator_count).into_iter().collect(); - let shard_indices = (0_usize..*shard_count).into_iter().collect(); + let validator_indices: Vec = (0_usize..*validator_count).into_iter().collect(); + let shard_indices: Vec = (0_usize..*shard_count).into_iter().collect(); let result = generate_cycle( &validator_indices, &shard_indices, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size); + crosslinking_shard_start, + cycle_length, + min_committee_size); (validator_indices, shard_indices, result) } @@ -255,9 +255,9 @@ mod tests { let (validators, shards, result) = generate_cycle_helper( &validator_count, &shard_count, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size); + crosslinking_shard_start, + cycle_length, + min_committee_size); let cycle = result.unwrap(); let assigned_validators = flatten_validators(&cycle); @@ -294,9 +294,9 @@ mod tests { let (validators, shards, result) = generate_cycle_helper( &validator_count, &shard_count, - &crosslinking_shard_start, - &cycle_length, - &min_committee_size); + crosslinking_shard_start, + cycle_length, + min_committee_size); let cycle = result.unwrap(); let assigned_validators = flatten_validators(&cycle); let assigned_shards = flatten_and_dedup_shards(&cycle); From 6417ecd464914a28200bb8d94131ec81ea789d12 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 10 Oct 2018 14:04:42 +1100 Subject: [PATCH 11/12] Correct comments for rust docs --- .../transition/src/delegation/validator.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index b745fa3f4..15dca2278 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -31,7 +31,7 @@ impl<'a,T> Iterator for Split<'a, T> { } -/// splits a slice into chunks of size n. All postive n values are applicable, +/// Splits a slice into chunks of size n. All postive n values are applicable, /// hence the honey_badger prefix. /// Returns an iterator over the original list. trait SplitExt { @@ -51,9 +51,8 @@ impl SplitExt for [T] { } -/* Produce a vector of validators indicies where those validators start and end - * dynasties are within the supplied `dynasty`. -*/ +/// Produce a vector of validators indicies where those validators start and end +/// dynasties are within the supplied `dynasty`. fn active_validator_indicies( dynasty: u64, validators: &[ValidatorRecord]) @@ -73,12 +72,11 @@ fn active_validator_indicies( .collect() } -/* - * Delegates active validators into slots for a given cycle, given a random seed. - * Returns a vector or ShardAndComitte vectors representing the shards and committiees for - * each slot. - * References get_new_shuffling (ethereum 2.1 specification) - */ + +/// Delegates active validators into slots for a given cycle, given a random seed. +/// Returns a vector or ShardAndComitte vectors representing the shards and committiees for +/// each slot. +/// References get_new_shuffling (ethereum 2.1 specification) pub fn delegate_validators( seed: &[u8], validators: &[ValidatorRecord], @@ -107,9 +105,7 @@ pub fn delegate_validators( min_committee_size) } -/* - * Given the validator list, delegates the validators into slots and comittees for a given cycle. - */ +/// Given the validator list, delegates the validators into slots and comittees for a given cycle. fn generate_cycle( validator_indices: &[usize], shard_indices: &[usize], From 9717698f7b894b08fba5ce788022017773d2d086 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 10 Oct 2018 16:09:00 +1100 Subject: [PATCH 12/12] Break split function into its own crate. - Added tests - Remove it from the delegation dir - Added it as a crate in utils --- Cargo.toml | 1 + beacon_chain/transition/Cargo.toml | 1 + beacon_chain/transition/src/delegation/mod.rs | 1 + .../transition/src/delegation/validator.rs | 47 +--------- beacon_chain/transition/src/lib.rs | 1 + .../utils/honey-badger-split/Cargo.toml | 6 ++ .../utils/honey-badger-split/src/lib.rs | 85 +++++++++++++++++++ 7 files changed, 96 insertions(+), 46 deletions(-) create mode 100644 beacon_chain/utils/honey-badger-split/Cargo.toml create mode 100644 beacon_chain/utils/honey-badger-split/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 53f3fd00d..58e91040c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ members = [ "beacon_chain/utils/bls", "beacon_chain/utils/boolean-bitfield", "beacon_chain/utils/hashing", + "beacon_chain/utils/honey-badger-split", "beacon_chain/utils/shuffling", "beacon_chain/utils/ssz", "beacon_chain/utils/ssz_helpers", diff --git a/beacon_chain/transition/Cargo.toml b/beacon_chain/transition/Cargo.toml index abf1fe6dc..c17d6994f 100644 --- a/beacon_chain/transition/Cargo.toml +++ b/beacon_chain/transition/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" authors = ["Age Manning "] [dependencies] +honey-badger-split = { path = "../utils/honey-badger-split" } types = { path = "../types" } shuffling = { path = "../utils/shuffling" } diff --git a/beacon_chain/transition/src/delegation/mod.rs b/beacon_chain/transition/src/delegation/mod.rs index 265b3e9b6..66f3304f3 100644 --- a/beacon_chain/transition/src/delegation/mod.rs +++ b/beacon_chain/transition/src/delegation/mod.rs @@ -1,3 +1,4 @@ +use super::honey_badger_split; use super::types; use super::TransitionError; use super::shuffling::shuffle; diff --git a/beacon_chain/transition/src/delegation/validator.rs b/beacon_chain/transition/src/delegation/validator.rs index 15dca2278..4c33d0081 100644 --- a/beacon_chain/transition/src/delegation/validator.rs +++ b/beacon_chain/transition/src/delegation/validator.rs @@ -1,3 +1,4 @@ +use super::honey_badger_split::SplitExt; use super::types::{ShardAndCommittee, ValidatorRecord, ChainConfig}; use super::TransitionError; use super::shuffle; @@ -5,52 +6,6 @@ use std::cmp::min; type DelegatedCycle = Vec>; -/// Iterator for the honey_badger_split function -struct Split<'a, T: 'a> { - n: usize, - current_pos: usize, - list: &'a [T], - list_length: usize -} - -impl<'a,T> Iterator for Split<'a, T> { - type Item = &'a [T]; - - fn next(&mut self) -> Option { - self.current_pos +=1; - if self.current_pos <= self.n { - match self.list.get(self.list_length*(self.current_pos-1)/self.n..self.list_length*self.current_pos/self.n) { - Some(v) => Some(v), - None => unreachable!() - } - } - else { - None - } - } -} - - -/// Splits a slice into chunks of size n. All postive n values are applicable, -/// hence the honey_badger prefix. -/// Returns an iterator over the original list. -trait SplitExt { - fn honey_badger_split(&self, n: usize) -> Split; -} - -impl SplitExt for [T] { - - fn honey_badger_split(&self, n: usize) -> Split { - Split { - n, - current_pos: 0, - list: &self, - list_length: self.len(), - } - } -} - - /// Produce a vector of validators indicies where those validators start and end /// dynasties are within the supplied `dynasty`. fn active_validator_indicies( diff --git a/beacon_chain/transition/src/lib.rs b/beacon_chain/transition/src/lib.rs index a86777e9b..ccac52529 100644 --- a/beacon_chain/transition/src/lib.rs +++ b/beacon_chain/transition/src/lib.rs @@ -1,3 +1,4 @@ +extern crate honey_badger_split; extern crate types; extern crate shuffling; diff --git a/beacon_chain/utils/honey-badger-split/Cargo.toml b/beacon_chain/utils/honey-badger-split/Cargo.toml new file mode 100644 index 000000000..e9721efd4 --- /dev/null +++ b/beacon_chain/utils/honey-badger-split/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "honey-badger-split" +version = "0.1.0" +authors = ["Paul Hauner "] + +[dependencies] diff --git a/beacon_chain/utils/honey-badger-split/src/lib.rs b/beacon_chain/utils/honey-badger-split/src/lib.rs new file mode 100644 index 000000000..890391036 --- /dev/null +++ b/beacon_chain/utils/honey-badger-split/src/lib.rs @@ -0,0 +1,85 @@ +/// A function for splitting a list into N pieces. +/// +/// We have titled it the "honey badger split" because of its robustness. It don't care. + + +/// Iterator for the honey_badger_split function +pub struct Split<'a, T: 'a> { + n: usize, + current_pos: usize, + list: &'a [T], + list_length: usize +} + +impl<'a,T> Iterator for Split<'a, T> { + type Item = &'a [T]; + + fn next(&mut self) -> Option { + self.current_pos +=1; + if self.current_pos <= self.n { + match self.list.get(self.list_length*(self.current_pos-1)/self.n..self.list_length*self.current_pos/self.n) { + Some(v) => Some(v), + None => unreachable!() + } + } + else { + None + } + } +} + +/// Splits a slice into chunks of size n. All postive n values are applicable, +/// hence the honey_badger prefix. +/// +/// Returns an iterator over the original list. +pub trait SplitExt { + fn honey_badger_split(&self, n: usize) -> Split; +} + +impl SplitExt for [T] { + + fn honey_badger_split(&self, n: usize) -> Split { + Split { + n, + current_pos: 0, + list: &self, + list_length: self.len(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_honey_badger_split() { + /* + * These test cases are generated from the eth2.0 spec `split()` + * function at commit cbd254a. + */ + let input: Vec = vec![0, 1, 2, 3]; + let output: Vec<&[usize]> = input.honey_badger_split(2).collect(); + assert_eq!(output, vec![&[0, 1], &[2, 3]]); + + let input: Vec = vec![0, 1, 2, 3]; + let output: Vec<&[usize]> = input.honey_badger_split(6).collect(); + let expected: Vec<&[usize]> = vec![&[], &[0], &[1], &[], &[2], &[3]]; + assert_eq!(output, expected); + + let input: Vec = vec![0, 1, 2, 3]; + let output: Vec<&[usize]> = input.honey_badger_split(10).collect(); + let expected: Vec<&[usize]> = vec![&[], &[], &[0], &[], &[1], &[], &[], &[2], &[], &[3]]; + assert_eq!(output, expected); + + let input: Vec = vec![0]; + let output: Vec<&[usize]> = input.honey_badger_split(5).collect(); + let expected: Vec<&[usize]> = vec![&[], &[], &[], &[], &[0]]; + assert_eq!(output, expected); + + let input: Vec = vec![0, 1, 2]; + let output: Vec<&[usize]> = input.honey_badger_split(2).collect(); + let expected: Vec<&[usize]> = vec![&[0], &[1, 2]]; + assert_eq!(output, expected); + } +}