Merge pull request #6 from sigp/v2.1-helpers

[WIP] v2.1 helpers
This commit is contained in:
Mehdi Zerouali 2018-09-02 16:13:50 +01:00 committed by GitHub
commit 071041a03a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 272 additions and 24 deletions

View File

@ -8,7 +8,6 @@ extern crate futures;
pub mod db; pub mod db;
pub mod client; pub mod client;
pub mod shuffling;
pub mod state; pub mod state;
pub mod sync; pub mod sync;
pub mod utils; pub mod utils;

View File

@ -0,0 +1,15 @@
pub struct ChainConfig {
pub cycle_length: u8,
pub shard_count: u16,
pub min_committee_size: u64,
}
impl ChainConfig {
pub fn standard() -> Self {
Self {
cycle_length: 8,
shard_count: 1024,
min_committee_size: 128,
}
}
}

View File

@ -1,11 +0,0 @@
pub struct Config {
pub cycle_length: u8,
}
impl Config {
pub fn standard() -> Self {
Self {
cycle_length: 8,
}
}
}

View File

@ -9,8 +9,9 @@ use super::utils;
pub mod active_state; pub mod active_state;
pub mod attestation_record; pub mod attestation_record;
pub mod crystallized_state; pub mod crystallized_state;
pub mod config; pub mod chain_config;
pub mod block; pub mod block;
pub mod crosslink_record; pub mod crosslink_record;
pub mod shard_and_committee; pub mod shard_and_committee;
pub mod transition;
pub mod validator_record; pub mod validator_record;

View File

@ -1,6 +1,8 @@
#[derive(Clone,Debug)]
pub struct ShardAndCommittee { pub struct ShardAndCommittee {
pub shard_id: u16, pub shard_id: u16,
pub committee: Vec<u32> pub committee: Vec<usize>
} }
impl ShardAndCommittee { impl ShardAndCommittee {

View File

@ -0,0 +1,223 @@
use super::Hash256;
use super::TransitionError;
/// This function is used to select the hashes used in
/// the signing of an AttestationRecord.
///
/// It either returns Result with a vector of length `cycle_length,` or
/// returns an Error.
///
/// This function corresponds to the `get_signed_parent_hashes` function
/// in the Python reference implentation.
///
/// See this slide for more information:
/// https://tinyurl.com/ybzn2spw
pub fn attestation_parent_hashes(
cycle_length: &u8,
block_slot: &u64,
attestation_slot: &u64,
current_hashes: &Vec<Hash256>,
oblique_hashes: &Vec<Hash256>)
-> Result<Vec<Hash256>, TransitionError>
{
// This cast places a limit on cycle_length. If you change it, check math
// for overflow.
let cycle_length: u64 = *cycle_length as u64;
if current_hashes.len() as u64 != (cycle_length * 2) {
return Err(TransitionError::InvalidInput(String::from(
"current_hashes.len() must equal cycle_length * 2")));
}
if attestation_slot >= block_slot {
return Err(TransitionError::InvalidInput(String::from(
"attestation_slot must be less than block_slot")));
}
if oblique_hashes.len() as u64 > cycle_length {
return Err(TransitionError::InvalidInput(String::from(
"oblique_hashes.len() must be <= cycle_length * 2")));
}
/*
* Cannot underflow as block_slot cannot be less
* than attestation_slot.
*/
let attestation_distance = block_slot - attestation_slot;
if attestation_distance > cycle_length {
return Err(TransitionError::InvalidInput(String::from(
"attestation_slot must be withing one cycle of block_slot")));
}
/*
* Cannot underflow because attestation_distance cannot
* be larger than cycle_length.
*/
let start = cycle_length - attestation_distance;
/*
* Overflow is potentially impossible, but proof is complicated
* enough to just use checked math.
*
* Arithmetic is:
* start + cycle_length - oblique_hashes.len()
*/
let end = start.checked_add(cycle_length)
.and_then(|x| x.checked_sub(oblique_hashes.len() as u64))
.ok_or(TransitionError::IntWrapping)?;
let mut hashes = Vec::new();
hashes.extend_from_slice(
&current_hashes[(start as usize)..(end as usize)]);
hashes.append(&mut oblique_hashes.clone());
Ok(hashes)
}
#[cfg(test)]
mod tests {
use super::*;
fn get_range_of_hashes(from: usize, to: usize) -> Vec<Hash256> {
(from..to).map(|i| get_hash(&vec![i as u8])).collect()
}
fn get_hash(value: &[u8]) -> Hash256 {
Hash256::from_slice(value)
}
#[test]
fn test_get_signed_hashes_oblique_scenario_1() {
/*
* Two oblique hashes.
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 19;
let attestation_slot: u64 = 15;
let current_hashes = get_range_of_hashes(3, 19);
let oblique_hashes = get_range_of_hashes(100, 102);
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.len(), cycle_length as usize);
let mut expected_result = get_range_of_hashes(7, 13);
expected_result.append(&mut get_range_of_hashes(100, 102));
assert_eq!(result, expected_result);
}
#[test]
fn test_get_signed_hashes_oblique_scenario_2() {
/*
* All oblique hashes.
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 19;
let attestation_slot: u64 = 15;
let current_hashes = get_range_of_hashes(3, 19);
let oblique_hashes = get_range_of_hashes(100, 108);
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.len(), cycle_length as usize);
let expected_result = get_range_of_hashes(100, 108);
assert_eq!(result, expected_result);
}
#[test]
fn test_get_signed_hashes_scenario_1() {
/*
* Google Slides example.
* https://tinyurl.com/ybzn2spw
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 19;
let attestation_slot: u64 = 15;
let current_hashes = get_range_of_hashes(3, 19);
let oblique_hashes = vec![];
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.len(), cycle_length as usize);
let expected_result = get_range_of_hashes(7, 15);
assert_eq!(result, expected_result);
}
#[test]
fn test_get_signed_hashes_scenario_2() {
/*
* Block 1, attestation 0.
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 1;
let attestation_slot: u64 = 0;
let current_hashes = get_range_of_hashes(0, 16);
let oblique_hashes = vec![];
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result.len(), cycle_length as usize);
let expected_result = get_range_of_hashes(7, 15);
assert_eq!(result, expected_result);
}
#[test]
fn test_get_signed_hashes_scenario_3() {
/*
* attestation_slot too large
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 100;
let attestation_slot: u64 = 100;
let current_hashes = get_range_of_hashes(0, 16);
let oblique_hashes = vec![];
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_err());
}
#[test]
fn test_get_signed_hashes_scenario_4() {
/*
* Current hashes too small
*/
let cycle_length: u8 = 8;
let block_slot: u64 = 100;
let attestation_slot: u64 = 99;
let current_hashes = get_range_of_hashes(0, 15);
let oblique_hashes = vec![];
let result = attestation_parent_hashes(
&cycle_length,
&block_slot,
&attestation_slot,
&current_hashes,
&oblique_hashes);
assert!(result.is_err());
}
}

View File

@ -0,0 +1,17 @@
use super::super::utils::types::Hash256;
mod attestation_parent_hashes;
mod shuffling;
pub use self::attestation_parent_hashes::attestation_parent_hashes;
pub use self::shuffling::shuffle;
#[derive(Debug)]
pub enum TransitionError {
IntWrapping,
OutOfBounds,
InvalidInput(String),
}

View File

@ -0,0 +1,2 @@
This module includes the fundamental shuffling function. It does not do the
full validator delegation amongst slots.