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); + } +}