From c41b743d2d38ab5b57294b8ccea7b5fb1c89257a Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Thu, 14 Feb 2019 14:57:29 +1100 Subject: [PATCH 1/7] Rename `vec_shuffle` to `fisher_yates_shuffle` We're adding another shuffler so it's nice to be specific --- Cargo.toml | 2 +- eth2/types/Cargo.toml | 2 +- eth2/types/src/beacon_state.rs | 2 +- eth2/utils/{vec_shuffle => fisher_yates_shuffle}/Cargo.toml | 2 +- eth2/utils/{vec_shuffle => fisher_yates_shuffle}/src/lib.rs | 0 eth2/utils/{vec_shuffle => fisher_yates_shuffle}/src/rng.rs | 0 .../src/specs/shuffle_test_vectors.yaml | 0 7 files changed, 4 insertions(+), 4 deletions(-) rename eth2/utils/{vec_shuffle => fisher_yates_shuffle}/Cargo.toml (85%) rename eth2/utils/{vec_shuffle => fisher_yates_shuffle}/src/lib.rs (100%) rename eth2/utils/{vec_shuffle => fisher_yates_shuffle}/src/rng.rs (100%) rename eth2/utils/{vec_shuffle => fisher_yates_shuffle}/src/specs/shuffle_test_vectors.yaml (100%) diff --git a/Cargo.toml b/Cargo.toml index a2c464366..7d545c885 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ members = [ "eth2/utils/honey-badger-split", "eth2/utils/slot_clock", "eth2/utils/ssz", - "eth2/utils/vec_shuffle", + "eth2/utils/fisher_yates_shuffle", "beacon_node", "beacon_node/db", "beacon_node/beacon_chain", diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index 24aabf148..9ae5d0090 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -18,4 +18,4 @@ serde_derive = "1.0" serde_json = "1.0" slog = "^2.2.3" ssz = { path = "../utils/ssz" } -vec_shuffle = { path = "../utils/vec_shuffle" } +fisher_yates_shuffle = { path = "../utils/fisher_yates_shuffle" } diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index ed53bfea9..a0f8c5e2c 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -5,12 +5,12 @@ use crate::{ PendingAttestation, PublicKey, Signature, Slot, Validator, }; use bls::verify_proof_of_possession; +use fisher_yates_shuffle::shuffle; use honey_badger_split::SplitExt; use rand::RngCore; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use std::ops::Range; -use vec_shuffle::shuffle; pub enum Error { InsufficientValidators, diff --git a/eth2/utils/vec_shuffle/Cargo.toml b/eth2/utils/fisher_yates_shuffle/Cargo.toml similarity index 85% rename from eth2/utils/vec_shuffle/Cargo.toml rename to eth2/utils/fisher_yates_shuffle/Cargo.toml index aaeb50074..7d33c2e91 100644 --- a/eth2/utils/vec_shuffle/Cargo.toml +++ b/eth2/utils/fisher_yates_shuffle/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "vec_shuffle" +name = "fisher_yates_shuffle" version = "0.1.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/vec_shuffle/src/lib.rs b/eth2/utils/fisher_yates_shuffle/src/lib.rs similarity index 100% rename from eth2/utils/vec_shuffle/src/lib.rs rename to eth2/utils/fisher_yates_shuffle/src/lib.rs diff --git a/eth2/utils/vec_shuffle/src/rng.rs b/eth2/utils/fisher_yates_shuffle/src/rng.rs similarity index 100% rename from eth2/utils/vec_shuffle/src/rng.rs rename to eth2/utils/fisher_yates_shuffle/src/rng.rs diff --git a/eth2/utils/vec_shuffle/src/specs/shuffle_test_vectors.yaml b/eth2/utils/fisher_yates_shuffle/src/specs/shuffle_test_vectors.yaml similarity index 100% rename from eth2/utils/vec_shuffle/src/specs/shuffle_test_vectors.yaml rename to eth2/utils/fisher_yates_shuffle/src/specs/shuffle_test_vectors.yaml From 18e85a3cf8032acf5c7a65fcd86cbaef65f8977e Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Thu, 14 Feb 2019 18:22:55 +1100 Subject: [PATCH 2/7] Add swap_or_not_shuffle and tests. The implementation is not matching the EF implementation at this point. --- Cargo.toml | 1 + eth2/utils/swap_or_not_shuffle/Cargo.toml | 13 ++ eth2/utils/swap_or_not_shuffle/src/lib.rs | 115 ++++++++++++++++++ .../specs/permutated_index_test_vectors.yaml | 74 +++++++++++ 4 files changed, 203 insertions(+) create mode 100644 eth2/utils/swap_or_not_shuffle/Cargo.toml create mode 100644 eth2/utils/swap_or_not_shuffle/src/lib.rs create mode 100644 eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml diff --git a/Cargo.toml b/Cargo.toml index 7d545c885..f0488b33d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "eth2/utils/honey-badger-split", "eth2/utils/slot_clock", "eth2/utils/ssz", + "eth2/utils/swap_or_not_shuffle", "eth2/utils/fisher_yates_shuffle", "beacon_node", "beacon_node/db", diff --git a/eth2/utils/swap_or_not_shuffle/Cargo.toml b/eth2/utils/swap_or_not_shuffle/Cargo.toml new file mode 100644 index 000000000..1c898f7b1 --- /dev/null +++ b/eth2/utils/swap_or_not_shuffle/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "swap_or_not_shuffle" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dependencies] +bytes = "0.4" +hashing = { path = "../hashing" } + +[dev-dependencies] +yaml-rust = "0.4.2" +hex = "0.3" diff --git a/eth2/utils/swap_or_not_shuffle/src/lib.rs b/eth2/utils/swap_or_not_shuffle/src/lib.rs new file mode 100644 index 000000000..957372a89 --- /dev/null +++ b/eth2/utils/swap_or_not_shuffle/src/lib.rs @@ -0,0 +1,115 @@ +use bytes::{Buf, BufMut, BytesMut}; +use hashing::hash; +use std::cmp::max; +use std::io::Cursor; + +pub fn get_permutated_index( + index: usize, + list_size: usize, + seed: &[u8], + shuffle_round_count: usize, +) -> usize { + let mut index = index; + for round in 0..shuffle_round_count { + let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size; + let flip = (pivot - index) % list_size; + let position = max(index, flip); + let source = hash_with_round_and_position(seed, round, position); + let byte = source[(position % 256) / 8]; + let bit = (byte >> (position % 8)) % 2; + index = if bit == 1 { flip } else { index } + } + index +} + +fn hash_with_round_and_position(seed: &[u8], round: usize, position: usize) -> Vec { + let mut seed = seed.to_vec(); + seed.append(&mut int_to_bytes1(round as u64)); + seed.append(&mut int_to_bytes4(position as u64 / 256)); + hash(&seed[..]) +} + +fn hash_with_round(seed: &[u8], round: usize) -> Vec { + let mut seed = seed.to_vec(); + seed.append(&mut int_to_bytes1(round as u64)); + hash(&seed[..]) +} + +fn int_to_bytes1(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(8); + bytes.put_u64_le(int); + vec![bytes[0]] +} + +fn int_to_bytes4(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(8); + bytes.put_u64_le(int); + bytes[0..4].to_vec() +} + +fn bytes_to_int64(bytes: &[u8]) -> u64 { + let mut cursor = Cursor::new(bytes); + cursor.get_u64_le() +} + +#[cfg(test)] +mod tests { + use super::*; + use hex; + use std::{fs::File, io::prelude::*, path::PathBuf}; + use yaml_rust::yaml; + + #[test] + fn test_shuffling() { + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("src/specs/permutated_index_test_vectors.yaml"); + + File::open(file_path_buf).unwrap() + }; + + let mut yaml_str = String::new(); + + file.read_to_string(&mut yaml_str).unwrap(); + + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + let test_cases = doc["test_cases"].as_vec().unwrap(); + + for (i, test_case) in test_cases.iter().enumerate() { + let index = test_case["index"].as_i64().unwrap() as usize; + let list_size = test_case["list_size"].as_i64().unwrap() as usize; + let permutated_index = test_case["permutated_index"].as_i64().unwrap() as usize; + let shuffle_round_count = test_case["shuffle_round_count"].as_i64().unwrap() as usize; + let seed_string = test_case["seed"].clone().into_string().unwrap(); + let seed = hex::decode(seed_string.replace("0x", "")).unwrap(); + + println!("case: {}", i); + + assert_eq!( + permutated_index, + get_permutated_index(index, list_size, &seed[..], shuffle_round_count), + "Failure on case #{} index: {}, list_size: {}, round_count: {}, seed: {}", + i, + index, + list_size, + shuffle_round_count, + seed_string, + ); + + /* + let input = test_case["input"].clone().into_vec().unwrap(); + let output = test_case["output"].clone().into_vec().unwrap(); + let seed_bytes = test_case["seed"].as_str().unwrap().as_bytes(); + + let seed = if seed_bytes.len() > 0 { + hash(seed_bytes) + } else { + vec![] + }; + + assert_eq!(shuffle(&seed, input).unwrap(), output); + */ + } + } +} diff --git a/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml b/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml new file mode 100644 index 000000000..f753976f7 --- /dev/null +++ b/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml @@ -0,0 +1,74 @@ +fork: tchaikovsky +summary: Test vectors for list shuffling using `get_permutated_index` +test_suite: permutated_index +title: Permutated Index Tests +version: 1.0 +test_cases: +- {index: 0, list_size: 1024, permutated_index: 216, seed: '0xc0c7f226fbd574a8c63dc26864c27833ea931e7c70b34409ba765f3d2031633d', + shuffle_round_count: 90} +- {index: 1024, list_size: 1024, permutated_index: 433, seed: '0xb20420b2b7b1c64600cbe962544052d0bbe13da403950d198d4f4ea28762953f', + shuffle_round_count: 90} +- {index: 806, list_size: 704, permutated_index: 584, seed: '0x3a4cfce20efb7d7eca50291470043d6e8a2c62956e687571607d3f0e5bd0af3f', + shuffle_round_count: 90} +- {index: 1681, list_size: 2154, permutated_index: 1628, seed: '0xbb99b3ecc0ea15a403456ce708c05ceeeddc0a4205caf072ba06ff9bde03f37e', + shuffle_round_count: 90} +- {index: 3253, list_size: 621, permutated_index: 31, seed: '0x1a51109676d549c1bea3b81edd82df68cc03a97ff58a8970c63ca86dd3b8b8a6', + shuffle_round_count: 90} +- {index: 749, list_size: 3081, permutated_index: 1221, seed: '0x6cddea1279bf4a2725c781ce6aba348d383556e23fcb9e73c23ad33cfb50f4c0', + shuffle_round_count: 90} +- {index: 2415, list_size: 2184, permutated_index: 394, seed: '0xa84b128c2885960e5f1b39822ee5dab30ad1580cdabb175a4b1512cac5566866', + shuffle_round_count: 90} +- {index: 339, list_size: 3728, permutated_index: 427, seed: '0xe22c8444f460c9dcfc34a3c13f211e63c56e9e1187f31a56a4230d8d5bf5e584', + shuffle_round_count: 90} +- {index: 4073, list_size: 2365, permutated_index: 2089, seed: '0x946af91cce976e1346e3970815107154b58b1eff411bfca3342ea0d8282a8630', + shuffle_round_count: 90} +- {index: 3438, list_size: 720, permutated_index: 559, seed: '0x5f3c5270d20810c104b75e25bf89c0066deebc3461937fc0e72ae04ee74f2456', + shuffle_round_count: 90} +- {index: 1394, list_size: 388, permutated_index: 311, seed: '0xdf6fdc34adb35f3fc2880d220e520120a032bbaa0f4bd7a5fcf1c2269de21075', + shuffle_round_count: 90} +- {index: 1604, list_size: 1816, permutated_index: 863, seed: '0xc9b0c76e11f4c3c3c38b447aca5352d93132ad5678da420ca2e69d92588e0fba', + shuffle_round_count: 90} +- {index: 671, list_size: 798, permutated_index: 318, seed: '0x45c31aeb3eb29ccdf3327d0f3dd4592cdfb2fad3703229c6c2e720dc792f9f77', + shuffle_round_count: 90} +- {index: 3161, list_size: 4020, permutated_index: 1590, seed: '0xb2a397fd8ea36dbfcec0d733d0af7ec3a03d789a66231f3bc7cafa5e966e5657', + shuffle_round_count: 90} +- {index: 3414, list_size: 3557, permutated_index: 2643, seed: '0x524e6dee54d1b8b5882ad8e55c18a30462ac02c4bb86c27d26cbe52951395b1a', + shuffle_round_count: 90} +- {index: 2693, list_size: 3414, permutated_index: 2230, seed: '0x3b776c7fc8bdad6030de943c4e3f938202ac553f44381dc67a74aac23523cb45', + shuffle_round_count: 90} +- {index: 1319, list_size: 3413, permutated_index: 2830, seed: '0xd2f7b2d24ebc6bf2d63ef189efccabc4a16bb17cd80e4be4083e61b31931bad6', + shuffle_round_count: 90} +- {index: 637, list_size: 1421, permutated_index: 370, seed: '0xe8bc30a4ce7b26b6897c2221a3358f25fdc1d82baa8089c1f242aa48c6611180', + shuffle_round_count: 90} +- {index: 3101, list_size: 525, permutated_index: 157, seed: '0xe930adeecaf3084b2b85f9b1dfebe34f6300047fda0ab6a746b6b0206febb825', + shuffle_round_count: 90} +- {index: 3596, list_size: 3688, permutated_index: 3621, seed: '0xf88bf52143b20d6c78caf7caf8e7b3453287b210d000b5f57e9834388d4bc2b8', + shuffle_round_count: 90} +- {index: 2866, list_size: 307, permutated_index: 191, seed: '0x83fa10a34b029546c2ebabb8075f0670a78b38e0419aaead5d1cc8f40f58044b', + shuffle_round_count: 90} +- {index: 3307, list_size: 3458, permutated_index: 3099, seed: '0x193c08b580dd95a1355574dbf78665190a6133191e91ab35b1106e8984dfc0df', + shuffle_round_count: 90} +- {index: 399, list_size: 3, permutated_index: 1, seed: '0x4f880b431c2a14f66354bf0192292ffae0bf39b39f12e0540b97591af0a2980d', + shuffle_round_count: 90} +- {index: 1912, list_size: 3028, permutated_index: 1139, seed: '0x33201395d301ee43054417c6056404c586c907dfc5fceb66ebef541d143b00a3', + shuffle_round_count: 90} +- {index: 3902, list_size: 3079, permutated_index: 790, seed: '0xfbf4c5f45eabf289fdcfe0a3aba33a185fb1a4ae2f2b6f78daf61f5d356971e0', + shuffle_round_count: 90} +- {index: 38, list_size: 115, permutated_index: 109, seed: '0x7aca86322db56927d727101e31c93f616f746317d29aa10d88f371592963de92', + shuffle_round_count: 90} +- {index: 3295, list_size: 960, permutated_index: 14, seed: '0xfe274230a112bc68614882645339fda2f134501a042079d620ec65cf8d3fa675', + shuffle_round_count: 90} +- {index: 1535, list_size: 3974, permutated_index: 2568, seed: '0xa848af32d85c6d37c26e61a57e96780fcebc350ad1845e83fe5e4679ac820440', + shuffle_round_count: 90} +- {index: 2623, list_size: 431, permutated_index: 236, seed: '0x49c2391e025ec272c812510cb07c055f6201e84479499326330628888e31a0de', + shuffle_round_count: 90} +- {index: 3164, list_size: 3981, permutated_index: 233, seed: '0x09f413b7a36ec680ee8b19bbb9a39c4e207326155864bc8be5d6dd92f30d8556', + shuffle_round_count: 90} +- {index: 1826, list_size: 2643, permutated_index: 1395, seed: '0x797db811486e7a213e0145d6c946e5121aa6a8f761d1647d093fb976f2497361', + shuffle_round_count: 90} +- {index: 290, list_size: 3570, permutated_index: 361, seed: '0xa6dc019009eda2e48bbeb4b7c56d4aa5da7d5f8721b3a79b35beacbe48c662d6', + shuffle_round_count: 90} +- {index: 3192, list_size: 67, permutated_index: 61, seed: '0x040024c55ab879e5f61521013c5f45eb3b705c02c53c9c6ddf259716ff02e49a', + shuffle_round_count: 90} +- {index: 2984, list_size: 822, permutated_index: 57, seed: '0xe4ad255d7e90dbefdbc991adf603e5a4a5a4c57c5705ec697a74e6c7161191b1', + shuffle_round_count: 90} From c98a9fdf3e2b8093baf70a0327b7326318abe732 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Thu, 14 Feb 2019 23:55:05 +1100 Subject: [PATCH 3/7] Update test vectors, align to test vectors. --- eth2/utils/swap_or_not_shuffle/src/lib.rs | 42 +++++---- .../specs/permutated_index_test_vectors.yaml | 74 ---------------- .../specs/test_vector_permutated_index.yml | 86 +++++++++++++++++++ 3 files changed, 106 insertions(+), 96 deletions(-) delete mode 100644 eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml create mode 100644 eth2/utils/swap_or_not_shuffle/src/specs/test_vector_permutated_index.yml diff --git a/eth2/utils/swap_or_not_shuffle/src/lib.rs b/eth2/utils/swap_or_not_shuffle/src/lib.rs index 957372a89..88f846e0c 100644 --- a/eth2/utils/swap_or_not_shuffle/src/lib.rs +++ b/eth2/utils/swap_or_not_shuffle/src/lib.rs @@ -8,18 +8,22 @@ pub fn get_permutated_index( list_size: usize, seed: &[u8], shuffle_round_count: usize, -) -> usize { +) -> Option { + if list_size == 0 || index >= list_size { + return None; + } + let mut index = index; for round in 0..shuffle_round_count { let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size; - let flip = (pivot - index) % list_size; + let flip = (pivot + list_size - index) % list_size; let position = max(index, flip); let source = hash_with_round_and_position(seed, round, position); let byte = source[(position % 256) / 8]; let bit = (byte >> (position % 8)) % 2; index = if bit == 1 { flip } else { index } } - index + Some(index) } fn hash_with_round_and_position(seed: &[u8], round: usize, position: usize) -> Vec { @@ -60,10 +64,20 @@ mod tests { use yaml_rust::yaml; #[test] - fn test_shuffling() { + fn returns_none_for_zero_length_list() { + assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90)); + } + + #[test] + fn test_vectors() { + /* + * Test vectors are generated here: + * + * https://github.com/ethereum/eth2.0-test-generators + */ let mut file = { let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - file_path_buf.push("src/specs/permutated_index_test_vectors.yaml"); + file_path_buf.push("src/specs/test_vector_permutated_index.yml"); File::open(file_path_buf).unwrap() }; @@ -84,10 +98,8 @@ mod tests { let seed_string = test_case["seed"].clone().into_string().unwrap(); let seed = hex::decode(seed_string.replace("0x", "")).unwrap(); - println!("case: {}", i); - assert_eq!( - permutated_index, + Some(permutated_index), get_permutated_index(index, list_size, &seed[..], shuffle_round_count), "Failure on case #{} index: {}, list_size: {}, round_count: {}, seed: {}", i, @@ -96,20 +108,6 @@ mod tests { shuffle_round_count, seed_string, ); - - /* - let input = test_case["input"].clone().into_vec().unwrap(); - let output = test_case["output"].clone().into_vec().unwrap(); - let seed_bytes = test_case["seed"].as_str().unwrap().as_bytes(); - - let seed = if seed_bytes.len() > 0 { - hash(seed_bytes) - } else { - vec![] - }; - - assert_eq!(shuffle(&seed, input).unwrap(), output); - */ } } } diff --git a/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml b/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml deleted file mode 100644 index f753976f7..000000000 --- a/eth2/utils/swap_or_not_shuffle/src/specs/permutated_index_test_vectors.yaml +++ /dev/null @@ -1,74 +0,0 @@ -fork: tchaikovsky -summary: Test vectors for list shuffling using `get_permutated_index` -test_suite: permutated_index -title: Permutated Index Tests -version: 1.0 -test_cases: -- {index: 0, list_size: 1024, permutated_index: 216, seed: '0xc0c7f226fbd574a8c63dc26864c27833ea931e7c70b34409ba765f3d2031633d', - shuffle_round_count: 90} -- {index: 1024, list_size: 1024, permutated_index: 433, seed: '0xb20420b2b7b1c64600cbe962544052d0bbe13da403950d198d4f4ea28762953f', - shuffle_round_count: 90} -- {index: 806, list_size: 704, permutated_index: 584, seed: '0x3a4cfce20efb7d7eca50291470043d6e8a2c62956e687571607d3f0e5bd0af3f', - shuffle_round_count: 90} -- {index: 1681, list_size: 2154, permutated_index: 1628, seed: '0xbb99b3ecc0ea15a403456ce708c05ceeeddc0a4205caf072ba06ff9bde03f37e', - shuffle_round_count: 90} -- {index: 3253, list_size: 621, permutated_index: 31, seed: '0x1a51109676d549c1bea3b81edd82df68cc03a97ff58a8970c63ca86dd3b8b8a6', - shuffle_round_count: 90} -- {index: 749, list_size: 3081, permutated_index: 1221, seed: '0x6cddea1279bf4a2725c781ce6aba348d383556e23fcb9e73c23ad33cfb50f4c0', - shuffle_round_count: 90} -- {index: 2415, list_size: 2184, permutated_index: 394, seed: '0xa84b128c2885960e5f1b39822ee5dab30ad1580cdabb175a4b1512cac5566866', - shuffle_round_count: 90} -- {index: 339, list_size: 3728, permutated_index: 427, seed: '0xe22c8444f460c9dcfc34a3c13f211e63c56e9e1187f31a56a4230d8d5bf5e584', - shuffle_round_count: 90} -- {index: 4073, list_size: 2365, permutated_index: 2089, seed: '0x946af91cce976e1346e3970815107154b58b1eff411bfca3342ea0d8282a8630', - shuffle_round_count: 90} -- {index: 3438, list_size: 720, permutated_index: 559, seed: '0x5f3c5270d20810c104b75e25bf89c0066deebc3461937fc0e72ae04ee74f2456', - shuffle_round_count: 90} -- {index: 1394, list_size: 388, permutated_index: 311, seed: '0xdf6fdc34adb35f3fc2880d220e520120a032bbaa0f4bd7a5fcf1c2269de21075', - shuffle_round_count: 90} -- {index: 1604, list_size: 1816, permutated_index: 863, seed: '0xc9b0c76e11f4c3c3c38b447aca5352d93132ad5678da420ca2e69d92588e0fba', - shuffle_round_count: 90} -- {index: 671, list_size: 798, permutated_index: 318, seed: '0x45c31aeb3eb29ccdf3327d0f3dd4592cdfb2fad3703229c6c2e720dc792f9f77', - shuffle_round_count: 90} -- {index: 3161, list_size: 4020, permutated_index: 1590, seed: '0xb2a397fd8ea36dbfcec0d733d0af7ec3a03d789a66231f3bc7cafa5e966e5657', - shuffle_round_count: 90} -- {index: 3414, list_size: 3557, permutated_index: 2643, seed: '0x524e6dee54d1b8b5882ad8e55c18a30462ac02c4bb86c27d26cbe52951395b1a', - shuffle_round_count: 90} -- {index: 2693, list_size: 3414, permutated_index: 2230, seed: '0x3b776c7fc8bdad6030de943c4e3f938202ac553f44381dc67a74aac23523cb45', - shuffle_round_count: 90} -- {index: 1319, list_size: 3413, permutated_index: 2830, seed: '0xd2f7b2d24ebc6bf2d63ef189efccabc4a16bb17cd80e4be4083e61b31931bad6', - shuffle_round_count: 90} -- {index: 637, list_size: 1421, permutated_index: 370, seed: '0xe8bc30a4ce7b26b6897c2221a3358f25fdc1d82baa8089c1f242aa48c6611180', - shuffle_round_count: 90} -- {index: 3101, list_size: 525, permutated_index: 157, seed: '0xe930adeecaf3084b2b85f9b1dfebe34f6300047fda0ab6a746b6b0206febb825', - shuffle_round_count: 90} -- {index: 3596, list_size: 3688, permutated_index: 3621, seed: '0xf88bf52143b20d6c78caf7caf8e7b3453287b210d000b5f57e9834388d4bc2b8', - shuffle_round_count: 90} -- {index: 2866, list_size: 307, permutated_index: 191, seed: '0x83fa10a34b029546c2ebabb8075f0670a78b38e0419aaead5d1cc8f40f58044b', - shuffle_round_count: 90} -- {index: 3307, list_size: 3458, permutated_index: 3099, seed: '0x193c08b580dd95a1355574dbf78665190a6133191e91ab35b1106e8984dfc0df', - shuffle_round_count: 90} -- {index: 399, list_size: 3, permutated_index: 1, seed: '0x4f880b431c2a14f66354bf0192292ffae0bf39b39f12e0540b97591af0a2980d', - shuffle_round_count: 90} -- {index: 1912, list_size: 3028, permutated_index: 1139, seed: '0x33201395d301ee43054417c6056404c586c907dfc5fceb66ebef541d143b00a3', - shuffle_round_count: 90} -- {index: 3902, list_size: 3079, permutated_index: 790, seed: '0xfbf4c5f45eabf289fdcfe0a3aba33a185fb1a4ae2f2b6f78daf61f5d356971e0', - shuffle_round_count: 90} -- {index: 38, list_size: 115, permutated_index: 109, seed: '0x7aca86322db56927d727101e31c93f616f746317d29aa10d88f371592963de92', - shuffle_round_count: 90} -- {index: 3295, list_size: 960, permutated_index: 14, seed: '0xfe274230a112bc68614882645339fda2f134501a042079d620ec65cf8d3fa675', - shuffle_round_count: 90} -- {index: 1535, list_size: 3974, permutated_index: 2568, seed: '0xa848af32d85c6d37c26e61a57e96780fcebc350ad1845e83fe5e4679ac820440', - shuffle_round_count: 90} -- {index: 2623, list_size: 431, permutated_index: 236, seed: '0x49c2391e025ec272c812510cb07c055f6201e84479499326330628888e31a0de', - shuffle_round_count: 90} -- {index: 3164, list_size: 3981, permutated_index: 233, seed: '0x09f413b7a36ec680ee8b19bbb9a39c4e207326155864bc8be5d6dd92f30d8556', - shuffle_round_count: 90} -- {index: 1826, list_size: 2643, permutated_index: 1395, seed: '0x797db811486e7a213e0145d6c946e5121aa6a8f761d1647d093fb976f2497361', - shuffle_round_count: 90} -- {index: 290, list_size: 3570, permutated_index: 361, seed: '0xa6dc019009eda2e48bbeb4b7c56d4aa5da7d5f8721b3a79b35beacbe48c662d6', - shuffle_round_count: 90} -- {index: 3192, list_size: 67, permutated_index: 61, seed: '0x040024c55ab879e5f61521013c5f45eb3b705c02c53c9c6ddf259716ff02e49a', - shuffle_round_count: 90} -- {index: 2984, list_size: 822, permutated_index: 57, seed: '0xe4ad255d7e90dbefdbc991adf603e5a4a5a4c57c5705ec697a74e6c7161191b1', - shuffle_round_count: 90} diff --git a/eth2/utils/swap_or_not_shuffle/src/specs/test_vector_permutated_index.yml b/eth2/utils/swap_or_not_shuffle/src/specs/test_vector_permutated_index.yml new file mode 100644 index 000000000..61b117fa9 --- /dev/null +++ b/eth2/utils/swap_or_not_shuffle/src/specs/test_vector_permutated_index.yml @@ -0,0 +1,86 @@ +fork: tchaikovsky +summary: Test vectors for list shuffling using `get_permutated_index` +test_suite: permutated_index +title: Permutated Index Tests +version: 1.0 +test_cases: +- {index: 0, list_size: 1, permutated_index: 0, seed: '0xc0c7f226fbd574a8c63dc26864c27833ea931e7c70b34409ba765f3d2031633d', + shuffle_round_count: 90} +- {index: 0, list_size: 2, permutated_index: 0, seed: '0xb20420b2b7b1c64600cbe962544052d0bbe13da403950d198d4f4ea28762953f', + shuffle_round_count: 90} +- {index: 1, list_size: 2, permutated_index: 0, seed: '0x11f1322c3a4cfce20efb7d7eca50291470043d6e8a2c62956e687571607d3f0e', + shuffle_round_count: 90} +- {index: 0, list_size: 3, permutated_index: 2, seed: '0x5bd0af3f74fe6986bb99b3ecc0ea15a403456ce708c05ceeeddc0a4205caf072', + shuffle_round_count: 90} +- {index: 1, list_size: 3, permutated_index: 1, seed: '0xba06ff9bde03f37eddeacb261a51109676d549c1bea3b81edd82df68cc03a97f', + shuffle_round_count: 90} +- {index: 2, list_size: 3, permutated_index: 2, seed: '0xf58a8970c63ca86dd3b8b8a615302ec06cddea1279bf4a2725c781ce6aba348d', + shuffle_round_count: 90} +- {index: 0, list_size: 1024, permutated_index: 1005, seed: '0x383556e23fcb9e73c23ad33cfb50f4c098f49688a84b128c2885960e5f1b3982', + shuffle_round_count: 90} +- {index: 1023, list_size: 1024, permutated_index: 934, seed: '0x2ee5dab30ad1580cdabb175a4b1512cac5566866d65a15e9e22c8444f460c9dc', + shuffle_round_count: 90} +- {index: 3925, list_size: 4040, permutated_index: 32, seed: '0x34a3c13f211e63c56e9e1187f31a56a4230d8d5bf5e584f0e4fe93946af91cce', + shuffle_round_count: 90} +- {index: 885, list_size: 2417, permutated_index: 1822, seed: '0x1346e3970815107154b58b1eff411bfca3342ea0d8282a86304d79d62d5f3c52', + shuffle_round_count: 90} +- {index: 840, list_size: 1805, permutated_index: 808, seed: '0x0810c104b75e25bf89c0066deebc3461937fc0e72ae04ee74f245616c15718df', + shuffle_round_count: 90} +- {index: 881, list_size: 1788, permutated_index: 582, seed: '0x34adb35f3fc2880d220e520120a032bbaa0f4bd7a5fcf1c2269de21075e7a464', + shuffle_round_count: 90} +- {index: 1362, list_size: 1817, permutated_index: 1018, seed: '0xc9b0c76e11f4c3c3c38b447aca5352d93132ad5678da420ca2e69d92588e0fba', + shuffle_round_count: 90} +- {index: 28, list_size: 111, permutated_index: 0, seed: '0x293145c31aeb3eb29ccdf3327d0f3dd4592cdfb2fad3703229c6c2e720dc792f', + shuffle_round_count: 90} +- {index: 959, list_size: 2558, permutated_index: 2094, seed: '0xc9f4c5fbb2a397fd8ea36dbfcec0d733d0af7ec3a03d789a66231f3bc7cafa5e', + shuffle_round_count: 90} +- {index: 887, list_size: 2406, permutated_index: 831, seed: '0x565729e0d5de524e6dee54d1b8b5882ad8e55c18a30462ac02c4bb86c27d26cb', + shuffle_round_count: 90} +- {index: 3526, list_size: 3674, permutated_index: 3531, seed: '0x2951395b1a1bbda8d53b776c7fc8bdad6030de943c4e3f938202ac553f44381d', + shuffle_round_count: 90} +- {index: 978, list_size: 3175, permutated_index: 2257, seed: '0x74aac23523cb45b7ee52d5d2f7b2d24ebc6bf2d63ef189efccabc4a16bb17cd8', + shuffle_round_count: 90} +- {index: 37, list_size: 231, permutated_index: 48, seed: '0xe4083e61b31931bad662392758e8bc30a4ce7b26b6897c2221a3358f25fdc1d8', + shuffle_round_count: 90} +- {index: 340, list_size: 693, permutated_index: 234, seed: '0x8089c1f242aa48c6611180f221c120e930adeecaf3084b2b85f9b1dfebe34f63', + shuffle_round_count: 90} +- {index: 0, list_size: 9, permutated_index: 1, seed: '0x7fda0ab6a746b6b0206febb8259891e0e6f88bf52143b20d6c78caf7caf8e7b3', + shuffle_round_count: 90} +- {index: 200, list_size: 1108, permutated_index: 952, seed: '0x87b210d000b5f57e9834388d4bc2b86ae8b31383fa10a34b029546c2ebabb807', + shuffle_round_count: 90} +- {index: 1408, list_size: 1531, permutated_index: 584, seed: '0x0670a78b38e0419aaead5d1cc8f40f58044b7076ced8193c08b580dd95a13555', + shuffle_round_count: 90} +- {index: 1704, list_size: 1863, permutated_index: 1022, seed: '0xdbf78665190a6133191e91ab35b1106e8984dfc0dfa36018004f880b431c2a14', + shuffle_round_count: 90} +- {index: 793, list_size: 3938, permutated_index: 2607, seed: '0x54bf0192292ffae0bf39b39f12e0540b97591af0a2980d32f277bd33201395d3', + shuffle_round_count: 90} +- {index: 14, list_size: 28, permutated_index: 10, seed: '0x43054417c6056404c586c907dfc5fceb66ebef541d143b00a3b676f3c0fbf4c5', + shuffle_round_count: 90} +- {index: 2909, list_size: 3920, permutated_index: 726, seed: '0x5eabf289fdcfe0a3aba33a185fb1a4ae2f2b6f78daf61f5d356971e0cb270207', + shuffle_round_count: 90} +- {index: 1943, list_size: 1959, permutated_index: 1292, seed: '0xca86322db56927d727101e31c93f616f746317d29aa10d88f371592963de92aa', + shuffle_round_count: 90} +- {index: 1647, list_size: 2094, permutated_index: 1805, seed: '0x3cfe274230a112bc68614882645339fda2f134501a042079d620ec65cf8d3fa6', + shuffle_round_count: 90} +- {index: 1012, list_size: 1877, permutated_index: 216, seed: '0x7b5ff8a848af32d85c6d37c26e61a57e96780fcebc350ad1845e83fe5e4679ac', + shuffle_round_count: 90} +- {index: 35, list_size: 2081, permutated_index: 1458, seed: '0x40691aa31a49c2391e025ec272c812510cb07c055f6201e84479499326330628', + shuffle_round_count: 90} +- {index: 1136, list_size: 2189, permutated_index: 1579, seed: '0x31a0deb2c8c5f809f413b7a36ec680ee8b19bbb9a39c4e207326155864bc8be5', + shuffle_round_count: 90} +- {index: 1775, list_size: 3434, permutated_index: 707, seed: '0x92f30d8556382b72a5797db811486e7a213e0145d6c946e5121aa6a8f761d164', + shuffle_round_count: 90} +- {index: 1109, list_size: 2010, permutated_index: 433, seed: '0x093fb976f2497361897012dfa6dc019009eda2e48bbeb4b7c56d4aa5da7d5f87', + shuffle_round_count: 90} +- {index: 359, list_size: 538, permutated_index: 115, seed: '0xa79b35beacbe48c662d60884c704040024c55ab879e5f61521013c5f45eb3b70', + shuffle_round_count: 90} +- {index: 1259, list_size: 1473, permutated_index: 1351, seed: '0x02c53c9c6ddf259716ff02e49a294eba33e4ad255d7e90dbefdbc991adf603e5', + shuffle_round_count: 90} +- {index: 2087, list_size: 2634, permutated_index: 1497, seed: '0xa5a4c57c5705ec697a74e6c7161191b18f58ca882a0fcc18f68dc3b57a1aa5b6', + shuffle_round_count: 90} +- {index: 2069, list_size: 2511, permutated_index: 1837, seed: '0xe7051ebc07f2e7b4d4b28f48d1e42d7b9dcec31c240ca6e1a0c06139ccfc4b8f', + shuffle_round_count: 90} +- {index: 1660, list_size: 3932, permutated_index: 3046, seed: '0x8687c029ffc443879527a64c31b7acbb38ab6e343779d0b2c6e250046fdb9de8', + shuffle_round_count: 90} +- {index: 379, list_size: 646, permutated_index: 32, seed: '0x17e854f4e80401345e13f72af45b221c9f7a840f6a8c1328ddf9c9ca9a088379', + shuffle_round_count: 90} From 8c54e55d995df3f43c5c4ef7447a86d8bd18bf7f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 15 Feb 2019 00:28:24 +1100 Subject: [PATCH 4/7] Updates to permutated_index - Add comments. - Add more `None` conditions. - Add more tests. --- eth2/utils/swap_or_not_shuffle/src/lib.rs | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/eth2/utils/swap_or_not_shuffle/src/lib.rs b/eth2/utils/swap_or_not_shuffle/src/lib.rs index 88f846e0c..3566ac23a 100644 --- a/eth2/utils/swap_or_not_shuffle/src/lib.rs +++ b/eth2/utils/swap_or_not_shuffle/src/lib.rs @@ -3,13 +3,23 @@ use hashing::hash; use std::cmp::max; use std::io::Cursor; +/// Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy. +/// +/// Utilizes 'swap or not' shuffling found in +/// https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf +/// See the 'generalized domain' algorithm on page 3. +/// +/// Returns `None` under any of the following conditions: +/// - `list_size == 0` +/// - `index >= list_size` +/// - `list_size >= usize::max_value() / 2` pub fn get_permutated_index( index: usize, list_size: usize, seed: &[u8], shuffle_round_count: usize, ) -> Option { - if list_size == 0 || index >= list_size { + if list_size == 0 || index >= list_size || list_size >= usize::max_value() / 2 { return None; } @@ -68,6 +78,19 @@ mod tests { assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90)); } + #[test] + fn returns_none_for_out_of_bounds_index() { + assert_eq!(None, get_permutated_index(100, 100, &[42, 42], 90)); + } + + #[test] + fn returns_none_for_too_large_list() { + assert_eq!( + None, + get_permutated_index(100, usize::max_value() / 2, &[42, 42], 90) + ); + } + #[test] fn test_vectors() { /* From b16ac40fd51da6aac00418bb4547e03d0dbc6baf Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Feb 2019 14:16:45 +1100 Subject: [PATCH 5/7] Add tests to SlotHeight. --- eth2/types/src/slot_epoch.rs | 380 +--------------------------- eth2/types/src/slot_epoch_macros.rs | 356 ++++++++++++++++++++++++++ eth2/types/src/slot_height.rs | 10 + 3 files changed, 379 insertions(+), 367 deletions(-) diff --git a/eth2/types/src/slot_epoch.rs b/eth2/types/src/slot_epoch.rs index c1554034a..eb5a8dced 100644 --- a/eth2/types/src/slot_epoch.rs +++ b/eth2/types/src/slot_epoch.rs @@ -100,373 +100,19 @@ impl<'a> Iterator for SlotIter<'a> { } #[cfg(test)] -mod tests { +mod slot_tests { use super::*; + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use ssz::ssz_encode; - macro_rules! new_tests { - ($type: ident) => { - #[test] - fn new() { - assert_eq!($type(0), $type::new(0)); - assert_eq!($type(3), $type::new(3)); - assert_eq!($type(u64::max_value()), $type::new(u64::max_value())); - } - }; - } - - macro_rules! from_into_tests { - ($type: ident, $other: ident) => { - #[test] - fn into() { - let x: $other = $type(0).into(); - assert_eq!(x, 0); - - let x: $other = $type(3).into(); - assert_eq!(x, 3); - - let x: $other = $type(u64::max_value()).into(); - // Note: this will fail on 32 bit systems. This is expected as we don't have a proper - // 32-bit system strategy in place. - assert_eq!(x, $other::max_value()); - } - - #[test] - fn from() { - assert_eq!($type(0), $type::from(0_u64)); - assert_eq!($type(3), $type::from(3_u64)); - assert_eq!($type(u64::max_value()), $type::from($other::max_value())); - } - }; - } - - macro_rules! math_between_tests { - ($type: ident, $other: ident) => { - #[test] - fn partial_ord() { - let assert_partial_ord = |a: u64, partial_ord: Ordering, b: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a).partial_cmp(&other), Some(partial_ord)); - }; - - assert_partial_ord(1, Ordering::Less, 2); - assert_partial_ord(2, Ordering::Greater, 1); - assert_partial_ord(0, Ordering::Less, u64::max_value()); - assert_partial_ord(u64::max_value(), Ordering::Greater, 0); - } - - #[test] - fn partial_eq() { - let assert_partial_eq = |a: u64, b: u64, is_equal: bool| { - let other: $other = $type(b).into(); - assert_eq!($type(a).eq(&other), is_equal); - }; - - assert_partial_eq(0, 0, true); - assert_partial_eq(0, 1, false); - assert_partial_eq(1, 0, false); - assert_partial_eq(1, 1, true); - - assert_partial_eq(u64::max_value(), u64::max_value(), true); - assert_partial_eq(0, u64::max_value(), false); - assert_partial_eq(u64::max_value(), 0, false); - } - - #[test] - fn add_and_add_assign() { - let assert_add = |a: u64, b: u64, result: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a) + other, $type(result)); - - let mut add_assigned = $type(a); - add_assigned += other; - - assert_eq!(add_assigned, $type(result)); - }; - - assert_add(0, 1, 1); - assert_add(1, 0, 1); - assert_add(1, 2, 3); - assert_add(2, 1, 3); - assert_add(7, 7, 14); - - // Addition should be saturating. - assert_add(u64::max_value(), 1, u64::max_value()); - assert_add(u64::max_value(), u64::max_value(), u64::max_value()); - } - - #[test] - fn sub_and_sub_assign() { - let assert_sub = |a: u64, b: u64, result: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a) - other, $type(result)); - - let mut sub_assigned = $type(a); - sub_assigned -= other; - - assert_eq!(sub_assigned, $type(result)); - }; - - assert_sub(1, 0, 1); - assert_sub(2, 1, 1); - assert_sub(14, 7, 7); - assert_sub(u64::max_value(), 1, u64::max_value() - 1); - assert_sub(u64::max_value(), u64::max_value(), 0); - - // Subtraction should be saturating - assert_sub(0, 1, 0); - assert_sub(1, 2, 0); - } - - #[test] - fn mul_and_mul_assign() { - let assert_mul = |a: u64, b: u64, result: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a) * other, $type(result)); - - let mut mul_assigned = $type(a); - mul_assigned *= other; - - assert_eq!(mul_assigned, $type(result)); - }; - - assert_mul(2, 2, 4); - assert_mul(1, 2, 2); - assert_mul(0, 2, 0); - - // Multiplication should be saturating. - assert_mul(u64::max_value(), 2, u64::max_value()); - } - - #[test] - fn div_and_div_assign() { - let assert_div = |a: u64, b: u64, result: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a) / other, $type(result)); - - let mut div_assigned = $type(a); - div_assigned /= other; - - assert_eq!(div_assigned, $type(result)); - }; - - assert_div(0, 2, 0); - assert_div(2, 2, 1); - assert_div(100, 50, 2); - assert_div(128, 2, 64); - assert_div(u64::max_value(), 2, 2_u64.pow(63) - 1); - } - - #[test] - #[should_panic] - fn div_panics_with_divide_by_zero() { - let other: $other = $type(0).into(); - let _ = $type(2) / other; - } - - #[test] - #[should_panic] - fn div_assign_panics_with_divide_by_zero() { - let other: $other = $type(0).into(); - let mut assigned = $type(2); - assigned /= other; - } - - #[test] - fn rem() { - let assert_rem = |a: u64, b: u64, result: u64| { - let other: $other = $type(b).into(); - assert_eq!($type(a) % other, $type(result)); - }; - - assert_rem(3, 2, 1); - assert_rem(40, 2, 0); - assert_rem(10, 100, 10); - assert_rem(302042, 3293, 2379); - } - }; - } - - macro_rules! math_tests { - ($type: ident) => { - #[test] - fn saturating_sub() { - let assert_saturating_sub = |a: u64, b: u64, result: u64| { - assert_eq!($type(a).saturating_sub($type(b)), $type(result)); - }; - - assert_saturating_sub(1, 0, 1); - assert_saturating_sub(2, 1, 1); - assert_saturating_sub(14, 7, 7); - assert_saturating_sub(u64::max_value(), 1, u64::max_value() - 1); - assert_saturating_sub(u64::max_value(), u64::max_value(), 0); - - // Subtraction should be saturating - assert_saturating_sub(0, 1, 0); - assert_saturating_sub(1, 2, 0); - } - - #[test] - fn saturating_add() { - let assert_saturating_add = |a: u64, b: u64, result: u64| { - assert_eq!($type(a).saturating_add($type(b)), $type(result)); - }; - - assert_saturating_add(0, 1, 1); - assert_saturating_add(1, 0, 1); - assert_saturating_add(1, 2, 3); - assert_saturating_add(2, 1, 3); - assert_saturating_add(7, 7, 14); - - // Addition should be saturating. - assert_saturating_add(u64::max_value(), 1, u64::max_value()); - assert_saturating_add(u64::max_value(), u64::max_value(), u64::max_value()); - } - - #[test] - fn checked_div() { - let assert_checked_div = |a: u64, b: u64, result: Option| { - let division_result_as_u64 = match $type(a).checked_div($type(b)) { - None => None, - Some(val) => Some(val.as_u64()), - }; - assert_eq!(division_result_as_u64, result); - }; - - assert_checked_div(0, 2, Some(0)); - assert_checked_div(2, 2, Some(1)); - assert_checked_div(100, 50, Some(2)); - assert_checked_div(128, 2, Some(64)); - assert_checked_div(u64::max_value(), 2, Some(2_u64.pow(63) - 1)); - - assert_checked_div(2, 0, None); - assert_checked_div(0, 0, None); - assert_checked_div(u64::max_value(), 0, None); - } - - #[test] - fn is_power_of_two() { - let assert_is_power_of_two = |a: u64, result: bool| { - assert_eq!( - $type(a).is_power_of_two(), - result, - "{}.is_power_of_two() != {}", - a, - result - ); - }; - - assert_is_power_of_two(0, false); - assert_is_power_of_two(1, true); - assert_is_power_of_two(2, true); - assert_is_power_of_two(3, false); - assert_is_power_of_two(4, true); - - assert_is_power_of_two(2_u64.pow(4), true); - assert_is_power_of_two(u64::max_value(), false); - } - - #[test] - fn ord() { - let assert_ord = |a: u64, ord: Ordering, b: u64| { - assert_eq!($type(a).cmp(&$type(b)), ord); - }; - - assert_ord(1, Ordering::Less, 2); - assert_ord(2, Ordering::Greater, 1); - assert_ord(0, Ordering::Less, u64::max_value()); - assert_ord(u64::max_value(), Ordering::Greater, 0); - } - }; - } - - macro_rules! ssz_tests { - ($type: ident) => { - #[test] - pub fn test_ssz_round_trip() { - let mut rng = XorShiftRng::from_seed([42; 16]); - let original = $type::random_for_test(&mut rng); - - let bytes = ssz_encode(&original); - let (decoded, _) = $type::ssz_decode(&bytes, 0).unwrap(); - - assert_eq!(original, decoded); - } - - #[test] - pub fn test_hash_tree_root() { - let mut rng = XorShiftRng::from_seed([42; 16]); - let original = $type::random_for_test(&mut rng); - - let result = original.hash_tree_root(); - - assert_eq!(result.len(), 32); - // TODO: Add further tests - // https://github.com/sigp/lighthouse/issues/170 - } - }; - } - - macro_rules! all_tests { - ($type: ident) => { - new_tests!($type); - math_between_tests!($type, $type); - math_tests!($type); - ssz_tests!($type); - - mod u64_tests { - use super::*; - - from_into_tests!($type, u64); - math_between_tests!($type, u64); - - #[test] - pub fn as_64() { - let x = $type(0).as_u64(); - assert_eq!(x, 0); - - let x = $type(3).as_u64(); - assert_eq!(x, 3); - - let x = $type(u64::max_value()).as_u64(); - assert_eq!(x, u64::max_value()); - } - } - - mod usize_tests { - use super::*; - - from_into_tests!($type, usize); - - #[test] - pub fn as_usize() { - let x = $type(0).as_usize(); - assert_eq!(x, 0); - - let x = $type(3).as_usize(); - assert_eq!(x, 3); - - let x = $type(u64::max_value()).as_usize(); - assert_eq!(x, usize::max_value()); - } - } - }; - } - - #[cfg(test)] - mod slot_tests { - use super::*; - use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use ssz::ssz_encode; - - all_tests!(Slot); - } - - #[cfg(test)] - mod epoch_tests { - use super::*; - use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; - use ssz::ssz_encode; - - all_tests!(Epoch); - } + all_tests!(Slot); +} + +#[cfg(test)] +mod epoch_tests { + use super::*; + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use ssz::ssz_encode; + + all_tests!(Epoch); } diff --git a/eth2/types/src/slot_epoch_macros.rs b/eth2/types/src/slot_epoch_macros.rs index 6813bfeaf..48bc219da 100644 --- a/eth2/types/src/slot_epoch_macros.rs +++ b/eth2/types/src/slot_epoch_macros.rs @@ -263,3 +263,359 @@ macro_rules! impl_common { impl_hash!($type); }; } + +// test macros +#[allow(unused_macros)] +macro_rules! new_tests { + ($type: ident) => { + #[test] + fn new() { + assert_eq!($type(0), $type::new(0)); + assert_eq!($type(3), $type::new(3)); + assert_eq!($type(u64::max_value()), $type::new(u64::max_value())); + } + }; +} + +#[allow(unused_macros)] +macro_rules! from_into_tests { + ($type: ident, $other: ident) => { + #[test] + fn into() { + let x: $other = $type(0).into(); + assert_eq!(x, 0); + + let x: $other = $type(3).into(); + assert_eq!(x, 3); + + let x: $other = $type(u64::max_value()).into(); + // Note: this will fail on 32 bit systems. This is expected as we don't have a proper + // 32-bit system strategy in place. + assert_eq!(x, $other::max_value()); + } + + #[test] + fn from() { + assert_eq!($type(0), $type::from(0_u64)); + assert_eq!($type(3), $type::from(3_u64)); + assert_eq!($type(u64::max_value()), $type::from($other::max_value())); + } + }; +} + +#[allow(unused_macros)] +macro_rules! math_between_tests { + ($type: ident, $other: ident) => { + #[test] + fn partial_ord() { + let assert_partial_ord = |a: u64, partial_ord: Ordering, b: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a).partial_cmp(&other), Some(partial_ord)); + }; + + assert_partial_ord(1, Ordering::Less, 2); + assert_partial_ord(2, Ordering::Greater, 1); + assert_partial_ord(0, Ordering::Less, u64::max_value()); + assert_partial_ord(u64::max_value(), Ordering::Greater, 0); + } + + #[test] + fn partial_eq() { + let assert_partial_eq = |a: u64, b: u64, is_equal: bool| { + let other: $other = $type(b).into(); + assert_eq!($type(a).eq(&other), is_equal); + }; + + assert_partial_eq(0, 0, true); + assert_partial_eq(0, 1, false); + assert_partial_eq(1, 0, false); + assert_partial_eq(1, 1, true); + + assert_partial_eq(u64::max_value(), u64::max_value(), true); + assert_partial_eq(0, u64::max_value(), false); + assert_partial_eq(u64::max_value(), 0, false); + } + + #[test] + fn add_and_add_assign() { + let assert_add = |a: u64, b: u64, result: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a) + other, $type(result)); + + let mut add_assigned = $type(a); + add_assigned += other; + + assert_eq!(add_assigned, $type(result)); + }; + + assert_add(0, 1, 1); + assert_add(1, 0, 1); + assert_add(1, 2, 3); + assert_add(2, 1, 3); + assert_add(7, 7, 14); + + // Addition should be saturating. + assert_add(u64::max_value(), 1, u64::max_value()); + assert_add(u64::max_value(), u64::max_value(), u64::max_value()); + } + + #[test] + fn sub_and_sub_assign() { + let assert_sub = |a: u64, b: u64, result: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a) - other, $type(result)); + + let mut sub_assigned = $type(a); + sub_assigned -= other; + + assert_eq!(sub_assigned, $type(result)); + }; + + assert_sub(1, 0, 1); + assert_sub(2, 1, 1); + assert_sub(14, 7, 7); + assert_sub(u64::max_value(), 1, u64::max_value() - 1); + assert_sub(u64::max_value(), u64::max_value(), 0); + + // Subtraction should be saturating + assert_sub(0, 1, 0); + assert_sub(1, 2, 0); + } + + #[test] + fn mul_and_mul_assign() { + let assert_mul = |a: u64, b: u64, result: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a) * other, $type(result)); + + let mut mul_assigned = $type(a); + mul_assigned *= other; + + assert_eq!(mul_assigned, $type(result)); + }; + + assert_mul(2, 2, 4); + assert_mul(1, 2, 2); + assert_mul(0, 2, 0); + + // Multiplication should be saturating. + assert_mul(u64::max_value(), 2, u64::max_value()); + } + + #[test] + fn div_and_div_assign() { + let assert_div = |a: u64, b: u64, result: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a) / other, $type(result)); + + let mut div_assigned = $type(a); + div_assigned /= other; + + assert_eq!(div_assigned, $type(result)); + }; + + assert_div(0, 2, 0); + assert_div(2, 2, 1); + assert_div(100, 50, 2); + assert_div(128, 2, 64); + assert_div(u64::max_value(), 2, 2_u64.pow(63) - 1); + } + + #[test] + #[should_panic] + fn div_panics_with_divide_by_zero() { + let other: $other = $type(0).into(); + let _ = $type(2) / other; + } + + #[test] + #[should_panic] + fn div_assign_panics_with_divide_by_zero() { + let other: $other = $type(0).into(); + let mut assigned = $type(2); + assigned /= other; + } + + #[test] + fn rem() { + let assert_rem = |a: u64, b: u64, result: u64| { + let other: $other = $type(b).into(); + assert_eq!($type(a) % other, $type(result)); + }; + + assert_rem(3, 2, 1); + assert_rem(40, 2, 0); + assert_rem(10, 100, 10); + assert_rem(302042, 3293, 2379); + } + }; +} + +#[allow(unused_macros)] +macro_rules! math_tests { + ($type: ident) => { + #[test] + fn saturating_sub() { + let assert_saturating_sub = |a: u64, b: u64, result: u64| { + assert_eq!($type(a).saturating_sub($type(b)), $type(result)); + }; + + assert_saturating_sub(1, 0, 1); + assert_saturating_sub(2, 1, 1); + assert_saturating_sub(14, 7, 7); + assert_saturating_sub(u64::max_value(), 1, u64::max_value() - 1); + assert_saturating_sub(u64::max_value(), u64::max_value(), 0); + + // Subtraction should be saturating + assert_saturating_sub(0, 1, 0); + assert_saturating_sub(1, 2, 0); + } + + #[test] + fn saturating_add() { + let assert_saturating_add = |a: u64, b: u64, result: u64| { + assert_eq!($type(a).saturating_add($type(b)), $type(result)); + }; + + assert_saturating_add(0, 1, 1); + assert_saturating_add(1, 0, 1); + assert_saturating_add(1, 2, 3); + assert_saturating_add(2, 1, 3); + assert_saturating_add(7, 7, 14); + + // Addition should be saturating. + assert_saturating_add(u64::max_value(), 1, u64::max_value()); + assert_saturating_add(u64::max_value(), u64::max_value(), u64::max_value()); + } + + #[test] + fn checked_div() { + let assert_checked_div = |a: u64, b: u64, result: Option| { + let division_result_as_u64 = match $type(a).checked_div($type(b)) { + None => None, + Some(val) => Some(val.as_u64()), + }; + assert_eq!(division_result_as_u64, result); + }; + + assert_checked_div(0, 2, Some(0)); + assert_checked_div(2, 2, Some(1)); + assert_checked_div(100, 50, Some(2)); + assert_checked_div(128, 2, Some(64)); + assert_checked_div(u64::max_value(), 2, Some(2_u64.pow(63) - 1)); + + assert_checked_div(2, 0, None); + assert_checked_div(0, 0, None); + assert_checked_div(u64::max_value(), 0, None); + } + + #[test] + fn is_power_of_two() { + let assert_is_power_of_two = |a: u64, result: bool| { + assert_eq!( + $type(a).is_power_of_two(), + result, + "{}.is_power_of_two() != {}", + a, + result + ); + }; + + assert_is_power_of_two(0, false); + assert_is_power_of_two(1, true); + assert_is_power_of_two(2, true); + assert_is_power_of_two(3, false); + assert_is_power_of_two(4, true); + + assert_is_power_of_two(2_u64.pow(4), true); + assert_is_power_of_two(u64::max_value(), false); + } + + #[test] + fn ord() { + let assert_ord = |a: u64, ord: Ordering, b: u64| { + assert_eq!($type(a).cmp(&$type(b)), ord); + }; + + assert_ord(1, Ordering::Less, 2); + assert_ord(2, Ordering::Greater, 1); + assert_ord(0, Ordering::Less, u64::max_value()); + assert_ord(u64::max_value(), Ordering::Greater, 0); + } + }; +} + +#[allow(unused_macros)] +macro_rules! ssz_tests { + ($type: ident) => { + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = $type::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = $type::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } + + #[test] + pub fn test_hash_tree_root() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = $type::random_for_test(&mut rng); + + let result = original.hash_tree_root(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } + }; +} + +#[allow(unused_macros)] +macro_rules! all_tests { + ($type: ident) => { + new_tests!($type); + math_between_tests!($type, $type); + math_tests!($type); + ssz_tests!($type); + + mod u64_tests { + use super::*; + + from_into_tests!($type, u64); + math_between_tests!($type, u64); + + #[test] + pub fn as_64() { + let x = $type(0).as_u64(); + assert_eq!(x, 0); + + let x = $type(3).as_u64(); + assert_eq!(x, 3); + + let x = $type(u64::max_value()).as_u64(); + assert_eq!(x, u64::max_value()); + } + } + + mod usize_tests { + use super::*; + + from_into_tests!($type, usize); + + #[test] + pub fn as_usize() { + let x = $type(0).as_usize(); + assert_eq!(x, 0); + + let x = $type(3).as_usize(); + assert_eq!(x, 3); + + let x = $type(u64::max_value()).as_usize(); + assert_eq!(x, usize::max_value()); + } + } + }; +} diff --git a/eth2/types/src/slot_height.rs b/eth2/types/src/slot_height.rs index 3efd00cae..afa0ff775 100644 --- a/eth2/types/src/slot_height.rs +++ b/eth2/types/src/slot_height.rs @@ -32,3 +32,13 @@ impl SlotHeight { SlotHeight(u64::max_value()) } } + +#[cfg(test)] + +mod slot_height_tests { + use super::*; + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use ssz::ssz_encode; + + all_tests!(SlotHeight); +} From 94c87845236383e8506f257b4a2853b3e87e63b1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Feb 2019 14:17:22 +1100 Subject: [PATCH 6/7] Remove Slow LMD Ghost from test harness. --- .../beacon_chain/test_harness/src/beacon_chain_harness.rs | 2 +- .../beacon_chain/test_harness/src/validator_harness/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs index 09621268c..acba2e015 100644 --- a/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs +++ b/beacon_node/beacon_chain/test_harness/src/beacon_chain_harness.rs @@ -6,7 +6,7 @@ use db::{ stores::{BeaconBlockStore, BeaconStateStore}, MemoryDB, }; -use fork_choice::{optimised_lmd_ghost::OptimisedLMDGhost, slow_lmd_ghost::SlowLMDGhost}; // import all the algorithms +use fork_choice::OptimisedLMDGhost; use log::debug; use rayon::prelude::*; use slot_clock::TestingSlotClock; diff --git a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs index e22ea1a2e..3df32fa64 100644 --- a/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs +++ b/beacon_node/beacon_chain/test_harness/src/validator_harness/mod.rs @@ -10,7 +10,7 @@ use block_producer::{BlockProducer, Error as BlockPollError}; use db::MemoryDB; use direct_beacon_node::DirectBeaconNode; use direct_duties::DirectDuties; -use fork_choice::{optimised_lmd_ghost::OptimisedLMDGhost, slow_lmd_ghost::SlowLMDGhost}; +use fork_choice::OptimisedLMDGhost; use local_signer::LocalSigner; use slot_clock::TestingSlotClock; use std::sync::Arc; From e06c4796e41ce67fb2136bcbf48de7f2486c08c8 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Fri, 15 Feb 2019 14:21:33 +1100 Subject: [PATCH 7/7] Import Slot directly from types in fork-choice. --- eth2/fork_choice/src/optimised_lmd_ghost.rs | 4 ++-- eth2/fork_choice/src/slow_lmd_ghost.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eth2/fork_choice/src/optimised_lmd_ghost.rs b/eth2/fork_choice/src/optimised_lmd_ghost.rs index 40dc029be..6b21e39f8 100644 --- a/eth2/fork_choice/src/optimised_lmd_ghost.rs +++ b/eth2/fork_choice/src/optimised_lmd_ghost.rs @@ -30,8 +30,8 @@ use fast_math::log2_raw; use std::collections::HashMap; use std::sync::Arc; use types::{ - readers::BeaconBlockReader, slot_epoch::Slot, slot_height::SlotHeight, - validator_registry::get_active_validator_indices, BeaconBlock, Hash256, + readers::BeaconBlockReader, validator_registry::get_active_validator_indices, BeaconBlock, + Hash256, Slot, SlotHeight, }; //TODO: Pruning - Children diff --git a/eth2/fork_choice/src/slow_lmd_ghost.rs b/eth2/fork_choice/src/slow_lmd_ghost.rs index 609d28ab2..3184150fd 100644 --- a/eth2/fork_choice/src/slow_lmd_ghost.rs +++ b/eth2/fork_choice/src/slow_lmd_ghost.rs @@ -28,8 +28,8 @@ use db::{ use std::collections::HashMap; use std::sync::Arc; use types::{ - readers::BeaconBlockReader, slot_epoch::Slot, validator_registry::get_active_validator_indices, - BeaconBlock, Hash256, + readers::BeaconBlockReader, validator_registry::get_active_validator_indices, BeaconBlock, + Hash256, Slot, }; //TODO: Pruning and syncing