From 2256f52a447576d2baed2a9a3885ba860bbcbf0f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 15 Aug 2018 13:25:51 +1000 Subject: [PATCH] Remove old transition functions --- src/state/transition/attestors.rs | 211 ---------- src/state/transition/crosslinks.rs | 513 ----------------------- src/state/transition/deposits.rs | 177 -------- src/state/transition/epoch.rs | 203 --------- src/state/transition/ffg.rs | 192 --------- src/state/transition/mod.rs | 76 ---- src/state/transition/new_active_state.rs | 137 ------ src/state/transition/proposers.rs | 54 --- src/state/transition/shuffling.rs | 124 ------ src/state/transition/validators.rs | 182 -------- 10 files changed, 1869 deletions(-) delete mode 100644 src/state/transition/attestors.rs delete mode 100644 src/state/transition/crosslinks.rs delete mode 100644 src/state/transition/deposits.rs delete mode 100644 src/state/transition/epoch.rs delete mode 100644 src/state/transition/ffg.rs delete mode 100644 src/state/transition/mod.rs delete mode 100644 src/state/transition/new_active_state.rs delete mode 100644 src/state/transition/proposers.rs delete mode 100644 src/state/transition/shuffling.rs delete mode 100644 src/state/transition/validators.rs diff --git a/src/state/transition/attestors.rs b/src/state/transition/attestors.rs deleted file mode 100644 index ae8093285..000000000 --- a/src/state/transition/attestors.rs +++ /dev/null @@ -1,211 +0,0 @@ -use super::validator_record::ValidatorRecord; -use super::utils::types::Bitfield; -use super::utils::bls::{ AggregateSignature, PublicKey }; -use super::utils::logging::Logger; -use super::crystallized_state::CrystallizedState; -use super::active_state::ActiveState; -use super::config::Config; -use super::shuffling::get_shuffling; - -pub fn process_recent_attesters( - cry_state: &CrystallizedState, - recent_attesters: &Vec, - config: &Config) - -> Vec -{ - let mut deltas: Vec = vec![0; cry_state.num_active_validators()]; - for v in recent_attesters { - deltas[*v] += config.attester_reward; - } - deltas -} - -// For a given state set and skip_count, return a proposer and set -// of attestors. -pub fn get_attesters_and_proposer( - cry_state: &CrystallizedState, - act_state: &ActiveState, - skip_count: &u64, - config: &Config, - log:&Logger) - -> (Vec, usize) -{ - let active_validator_count = cry_state.num_active_validators(); - assert!(active_validator_count >= 2, "must be >=2 active validators"); - let shuffled_validator_indicies = get_shuffling( - &act_state.randao, - &active_validator_count, - config); - let proposer_count: usize = 1; - let ideal_validator_count: usize = (config.attester_count as usize) - + (*skip_count as usize) + proposer_count; - assert!(ideal_validator_count >= 2, - "ideal_validator_count must be >=2"); - /* - * If there are adequate validators to allocate a full set of assesters and - * a proposer, then do so. Otherwise, the amount of attesters will need to be - * validator_count - 1. - */ - match ideal_validator_count > active_validator_count { - true => { - /* - * The active validator count is too low. - */ - warn!(log, "active validator count is low"; - "active_validator_count" => active_validator_count, - "ideal_validator_count" => ideal_validator_count); - (shuffled_validator_indicies[0..active_validator_count - 1].to_vec(), - shuffled_validator_indicies[active_validator_count - 1]) - } - false => { - /* - * The active validator count is adequate. - */ - (shuffled_validator_indicies[0..ideal_validator_count - 1].to_vec(), - shuffled_validator_indicies[ideal_validator_count - 1]) - } - } -} - -#[allow(unused_variables)] -pub fn process_attestations( - validators: &Vec, - attestation_indicies: &Vec, - attestation_bitfield: &Bitfield, - msg: &Vec, - aggregate_sig: &AggregateSignature) - -> Option> -{ - let mut key_msg_tuples: Vec<(&PublicKey, &[u8])> = vec![]; - let mut attesters: Vec = vec![]; - - assert_eq!( - attestation_indicies.len(), attestation_bitfield.len(), - "Bitfield length does not match required attestors." - ); - for (bitfield_bit, validators_index) in attestation_indicies.iter().enumerate() { - if attestation_bitfield.get_bit(&bitfield_bit) { - key_msg_tuples.push( - (&validators[*validators_index].pubkey, - &msg) - ); - attesters.push(*validators_index); - } - } - // TODO: figure out why this assert exists in the Python impl. - assert!(attesters.len() <= 128, "Max attesters is 128."); - - /* - // TODO: ensure signature verification actually takes place. - // It is completely bypassed here. - match aggregate_sig.verify(&key_msg_tuples) { - false => None, - true => Some(attesters) - } - */ - Some(attesters) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::utils::logging::test_logger; - - #[test] - fn test_process_recent_attesters() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - let validator_count = 20; - - config.attester_reward = 12; - - let mut recent_attesters: Vec = vec![]; - - for i in 0..validator_count { - cry_state.active_validators - .push(ValidatorRecord::zero_with_thread_rand_pub_key()); - if i % 2 == 0 { - recent_attesters.push(i); - } - } - - let d = process_recent_attesters( - &cry_state, - &recent_attesters, - &config); - - for i in 0..validator_count { - if i % 2 == 0 { - assert_eq!(d[i], config.attester_reward); - } else { - assert_eq!(d[i], 0); - } - } - } - - #[test] - fn test_attester_and_proposer_selection() { - let mut cry_state = CrystallizedState::zero(); - - (0..10).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - let act_state = ActiveState::zero(); - let (attestors, proposer) = get_attesters_and_proposer( - &cry_state, - &act_state, - &0, - &Config::standard(), - &test_logger()); - assert_eq!(attestors, [0, 9, 7, 6, 4, 1, 8, 5, 2]); - assert_eq!(proposer, 3); - } - - #[test] - #[should_panic(expected = "must be >=2 active validators")] - fn test_attester_and_proposer_selection_with_zero_active_validators() { - let mut cry_state = CrystallizedState::zero(); - cry_state.active_validators = Vec::new(); - let act_state = ActiveState::zero(); - let (_attestors, _proposer) = get_attesters_and_proposer( - &cry_state, - &act_state, - &0, - &Config::standard(), - &test_logger()); - } - - #[test] - fn test_attestation_processing() { - let validator_count = 10; - let mut validators: Vec = vec![]; - let mut attestation_indicies: Vec = vec![]; - let mut bitfield = Bitfield::new(); - let mut agg_sig = AggregateSignature::new(); - let msg = "Message that's longer than 16 chars".as_bytes(); - - for i in 0..validator_count { - let (v, keypair) = - ValidatorRecord::zero_with_thread_rand_keypair(); - validators.push(v); - attestation_indicies.push(i); - bitfield.set_bit(&i, &true); - let sig = keypair.sign(&msg); - agg_sig.aggregate(&sig); - } - - let result = process_attestations( - &validators, - &attestation_indicies, - &bitfield, - &msg.to_vec(), - &agg_sig); - - match result { - None => panic!("Verification failed."), - Some(x) => println!("{:?}", x) - }; - } -} - diff --git a/src/state/transition/crosslinks.rs b/src/state/transition/crosslinks.rs deleted file mode 100644 index d94cfc195..000000000 --- a/src/state/transition/crosslinks.rs +++ /dev/null @@ -1,513 +0,0 @@ -use std::collections::HashMap; -use std::cmp::min; -use super::bytes::{ BytesMut, BufMut }; -use super::aggregate_vote::AggregateVote; - -use super::crystallized_state::CrystallizedState; -use super::crosslink_record::CrosslinkRecord; -use super::partial_crosslink_record::PartialCrosslinkRecord; -use super::config::Config; - -const AGG_VOTE_MSG_SIZE: i32 = 2 + 32 + 32 + 8 + 8; - -// Given an aggregate_vote and a crystallized_state, -// return a byte array for signing or verification. -pub fn get_crosslink_aggvote_msg( - agg_vote: &AggregateVote, - cry_state: &CrystallizedState) - -> Vec -{ - let mut buf = BytesMut::with_capacity(AGG_VOTE_MSG_SIZE as usize); - buf.put_u16_be(agg_vote.shard_id); - buf.extend_from_slice(&agg_vote.shard_block_hash.to_vec()); - buf.extend_from_slice(&cry_state.current_checkpoint.to_vec()); - buf.put_u64_be(cry_state.current_epoch); - buf.put_u64_be(cry_state.last_justified_epoch); - buf.to_vec() -} - -// Returns the maximum possible shards for a given validator_count -// and configuration. -pub fn get_crosslink_shards_count( - active_validator_count: &usize, - config: &Config) - -> u16 -{ - let system_shard_count: u16 = config.shard_count; - let notaries_per_crosslink: u16 = config.notaries_per_crosslink; - - assert!(notaries_per_crosslink > 0, "Shards must require > 0 notaries."); - - let notarisable_shard_count = - *active_validator_count as u64 / notaries_per_crosslink as u64; - - min(notarisable_shard_count, system_shard_count as u64) as u16 -} - -pub fn get_crosslink_shards( - cry_state: &CrystallizedState, - config: &Config) - -> Vec -{ - let max_shard_count: u16 = config.shard_count; - let first_shard: u16 = cry_state.next_shard; - assert!(first_shard < max_shard_count, "CrystallizedState.next_shard \ - must be less than Config.shard_count."); - - let shard_count = get_crosslink_shards_count( - &cry_state.num_active_validators(), - &config); - - let unwrapped_shards: u16 = min(first_shard + shard_count, max_shard_count); - let wrapped_shards: u16 = (first_shard + shard_count) % max_shard_count; - let mut crosslink_shards: Vec = (first_shard..unwrapped_shards).collect(); - crosslink_shards.append(&mut (0_u16..wrapped_shards).collect()); - crosslink_shards -} - -pub fn get_crosslink_notaries( - cry_state: &CrystallizedState, - shard_id: &u16, - crosslink_shards: &Vec) - -> Vec -{ - let shard_crosslink_index = crosslink_shards.iter(). - position(|&s| s == *shard_id); - - match shard_crosslink_index { - None => panic!("shard_id not in crosslink_shards."), - Some(i) => { - let crosslink_shards_count = crosslink_shards.len(); - assert!(crosslink_shards_count > 0, - "crosslink_shards_count must be > 0"); - let active_validators = cry_state.num_active_validators(); - assert!(active_validators > 0, - "active_validators must be > 0"); - - let start = active_validators * i / crosslink_shards_count; - let end = active_validators * (i + 1) / crosslink_shards_count; - - assert!(cry_state.current_shuffling.len() == active_validators, - "Crystallized state shuffling does not match active \ - validator count"); - - cry_state.current_shuffling[start..end].to_vec() - } - } -} - -pub fn process_crosslinks( - cry_state: &CrystallizedState, - partial_crosslinks: &Vec, - config: &Config) - -> (Vec, Vec) -{ - assert!(partial_crosslinks.len() > 0, "No crosslinks present."); - - /* - * Create a map of shard_id -> (partial_crosslink, vote_count) - * to store the partial crosslink with the most votes for - * each shard. - */ - let mut shard_pc_map: - HashMap = HashMap::new(); - for pc in partial_crosslinks { - let vote_count = pc.voter_bitfield.num_true_bits(); - let mut competiting_vote_count = 0; - match shard_pc_map.get(&pc.shard_id) { - Some(&competitor) => competiting_vote_count = competitor.1, - None => {} - } - // Here we implicitly avoid adding crosslinks with 0 votes - // to our shard_pc_map. - if vote_count > competiting_vote_count { - shard_pc_map.insert(pc.shard_id, (pc, vote_count)); - } - } - - // All shards which may are to be included in the next state. - let crosslink_shards = get_crosslink_shards(&cry_state, &config); - // A list of balance deltas for each validator. - let mut deltas = vec![0_i64; cry_state.num_active_validators()]; - // A cloned list of validator records from crystallized state. - let mut new_crosslink_records: Vec - = cry_state.crosslink_records.to_vec(); - - /* - * Loop through all shards up for inclusion in the next crystallized - * state and replace the existing CrosslinkRecord if we have a new - * PartialCrosslinkRecord with a quorum. - */ - for shard_id in &crosslink_shards { - // Set of validator indicies for a given shard. - let notaries_indicies = get_crosslink_notaries( - &cry_state, - &shard_id, - &crosslink_shards); - // Attempt to retrieve a partial crosslink for the current shard_id. - let new_partial_crosslink = shard_pc_map.get(&shard_id); - // Retrieve present enshrined crosslink record for this shard. - let previous_crosslink_epoch = - match cry_state.crosslink_records.get(*shard_id as usize) { - None => panic!("shard_id not known by \ - crystallized state."), - Some(c) => c.epoch - }; - // Determine rewards - let current_epoch = cry_state.current_epoch; - assert!(current_epoch >= previous_crosslink_epoch, "Previous crosslink \ - epoch cannot be > current epoch."); - let crosslink_distance = cry_state.current_epoch- previous_crosslink_epoch; - let online_reward: i64 = if crosslink_distance <= 2 { 3 } else { 0 }; - let offline_penalty: i64 = (crosslink_distance as i64).saturating_mul(2); - // Loop through each notary for this shard and penalise/reward depending - // on if they voted or not. - for notary in ¬aries_indicies { - let voted = match new_partial_crosslink { - None => false, - Some(pc) => pc.0.voter_bitfield.get_bit(¬ary) - }; - match voted { - true => deltas[*notary] += online_reward, - false => deltas[*notary] -= offline_penalty - }; - } - /* - * If there is a PartialCrosslinkRecord with a quorum of votes for - * this shard, create a new CrosslinkRecord. By default, if there - * is not a new partial record, the old CrosslinkRecord will be - * maintained. - */ - match new_partial_crosslink { - None => {}, - Some(pc) => { - let votes = pc.1; - // If there are 2/3 or more votes from the notaries for this - // partial crosslink record, create a new CrosslinkRecord. - if ((votes as usize) * 3) >= (notaries_indicies.len() * 2) { - new_crosslink_records[*shard_id as usize] = - CrosslinkRecord { - epoch: current_epoch, - hash: pc.0.shard_block_hash - }; - } - - } - } - } - (deltas, new_crosslink_records) -} - - -#[cfg(test)] -mod tests { - use super::*; - use super::super::shuffling::get_shuffling; - use super::super::super::validator_record::ValidatorRecord; - use super::super::super::super::utils::types::{ Sha256Digest, Bitfield }; - - #[test] - fn test_crosslink_aggvote_msg() { - let mut cs_state = CrystallizedState::zero(); - let mut agg_vote = AggregateVote::zero(); - // All zeros - let m1 = get_crosslink_aggvote_msg(&agg_vote, &cs_state); - assert_eq!(m1, - vec![0_u8; AGG_VOTE_MSG_SIZE as usize], - "failed all zeros test"); - // With some values - agg_vote.shard_id = 42; - cs_state.current_epoch = 99; - cs_state.last_justified_epoch = 123; - let m2 = get_crosslink_aggvote_msg(&agg_vote, &cs_state); - assert_eq!(m2[0..2], [0, 42]); - assert_eq!(m2[2..34], [0; 32]); // TODO: test with non-zero hash - assert_eq!(m2[34..66], [0; 32]); // TODO: test with non-zero hash - assert_eq!(m2[66..74], [0, 0, 0, 0, 0, 0, 0, 99]); - assert_eq!(m2[74..82], [0, 0, 0, 0, 0, 0, 0, 123]); - } - - #[test] - fn test_crosslink_shard_count_with_varying_active_vals() { - let mut config = Config::standard(); - - config.shard_count = 10; - config.notaries_per_crosslink = 10; - - let mut c = get_crosslink_shards_count( - &100, - &config); - assert_eq!(c, 10); - - c = get_crosslink_shards_count( - &101, - &config); - assert_eq!(c, 10); - - c = get_crosslink_shards_count( - &99, - &config); - assert_eq!(c, 9); - - c = get_crosslink_shards_count( - &0, - &config); - assert_eq!(c, 0); - } - - #[test] - #[should_panic(expected = "must require > 0 notaries.")] - fn test_crosslink_shard_count_with_zero_notaries_per_crosslink() { - let mut config = Config::standard(); - - config.shard_count = 10; - config.notaries_per_crosslink = 0; - - let validators: u16 = 10; - - let _ = get_crosslink_shards_count( - &(validators as usize), - &config); - } - - #[test] - fn test_crosslink_shard_getter_with_5_shards() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - - config.shard_count = 5; - config.notaries_per_crosslink = 2; - - (0..10).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - cry_state.next_shard = 0; - let c = get_crosslink_shards( - &cry_state, - &config); - assert_eq!(c, [0, 1, 2, 3, 4]); - - cry_state.next_shard = 4; - let c = get_crosslink_shards( - &cry_state, - &config); - assert_eq!(c, [4, 0, 1, 2, 3]); - - cry_state.next_shard = 1; - let c = get_crosslink_shards( - &cry_state, - &config); - assert_eq!(c, [1, 2, 3, 4, 0]); - - cry_state.next_shard = 3; - let c = get_crosslink_shards( - &cry_state, - &config); - assert_eq!(c, [3, 4, 0, 1, 2]); - } - - #[test] - #[should_panic(expected = "next_shard must be less than Config.shard_count")] - fn test_crosslink_shard_getter_with_too_large_next_shard() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - - config.shard_count = 1; - config.notaries_per_crosslink = 2; - - (0..2).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - cry_state.next_shard = 6; - let _ = get_crosslink_shards( - &cry_state, - &config); - } - - #[test] - fn test_crosslink_notaries_allocation() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - config.shard_count = 5; - config.notaries_per_crosslink = 2; - - (0..10).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - cry_state.next_shard = 0; - let crosslink_shards = get_crosslink_shards( - &cry_state, - &config); - - let s = get_shuffling( - &Sha256Digest::zero(), - &cry_state.num_active_validators(), - &config); - assert_eq!(s, [0, 9, 7, 6, 4, 1, 8, 5, 2, 3]); - cry_state.current_shuffling = s.clone(); - - let mut n = get_crosslink_notaries( - &cry_state, - &0, - &crosslink_shards); - assert_eq!(n, [0, 9]); - - n = get_crosslink_notaries( - &cry_state, - &1, - &crosslink_shards); - assert_eq!(n, [7, 6]); - - n = get_crosslink_notaries( - &cry_state, - &2, - &crosslink_shards); - assert_eq!(n, [4, 1]); - - n = get_crosslink_notaries( - &cry_state, - &3, - &crosslink_shards); - assert_eq!(n, [8, 5]); - - n = get_crosslink_notaries( - &cry_state, - &4, - &crosslink_shards); - assert_eq!(n, [2, 3]); - } - - #[test] - #[should_panic(expected = "shard_id not in crosslink_shards")] - fn test_crosslink_notaries_allocation_with_invalid_shard() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - - config.shard_count = 5; - config.notaries_per_crosslink = 2; - - (0..10).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - cry_state.next_shard = 0; - let crosslink_shards = get_crosslink_shards( - &cry_state, - &config); - - cry_state.current_shuffling = get_shuffling( - &Sha256Digest::zero(), - &cry_state.num_active_validators(), - &config); - - let _ = get_crosslink_notaries( - &cry_state, - &5, - &crosslink_shards); - } - - #[test] - fn test_crosslink_processing_with_perfect_partials() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - let validator_count: usize = 10; - - config.shard_count = 5; - config.notaries_per_crosslink = 2; - - (0..validator_count).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - let s = get_shuffling( - &Sha256Digest::zero(), - &cry_state.num_active_validators(), - &config); - assert_eq!(s, [0, 9, 7, 6, 4, 1, 8, 5, 2, 3]); - cry_state.current_shuffling = s.clone(); - - cry_state.current_epoch = 100; - - let mut partial_crosslinks: Vec = vec![]; - for shard_id in 0..config.shard_count { - // Setup a recent crosslink record for each shard - cry_state.crosslink_records.push(CrosslinkRecord { - epoch: cry_state.current_epoch - 1, - hash: Sha256Digest::zero() - }); - // Create a new partial crosslink record - let mut voter_bitfield = Bitfield::new(); - (0..validator_count).for_each(|i| voter_bitfield.set_bit(&i, &true)); - partial_crosslinks.push(PartialCrosslinkRecord { - shard_id, - shard_block_hash: Sha256Digest::from(shard_id as u64), - voter_bitfield - }); - } - - let (deltas, new_crosslinks) = process_crosslinks( - &cry_state, - &partial_crosslinks, - &config); - - assert_eq!(deltas, vec![3; validator_count]); - for shard_id in 0..config.shard_count { - let c = new_crosslinks[shard_id as usize]; - assert_eq!(c.epoch, cry_state.current_epoch); - assert_eq!(c.hash.low_u64(), shard_id as u64); - } - } - - #[test] - fn test_crosslink_processing_with_no_voting() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - let validator_count: usize = 10; - - config.shard_count = 5; - config.notaries_per_crosslink = 2; - - (0..validator_count).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - let s = get_shuffling( - &Sha256Digest::zero(), - &cry_state.num_active_validators(), - &config); - assert_eq!(s, [0, 9, 7, 6, 4, 1, 8, 5, 2, 3]); - cry_state.current_shuffling = s.clone(); - - cry_state.current_epoch = 100; - - let mut partial_crosslinks: Vec = vec![]; - for shard_id in 0..config.shard_count { - // Setup a recent crosslink record for each shard - cry_state.crosslink_records.push(CrosslinkRecord { - epoch: cry_state.current_epoch - 1, - hash: Sha256Digest::zero() - }); - // Create a new partial crosslink record - partial_crosslinks.push(PartialCrosslinkRecord { - shard_id, - shard_block_hash: Sha256Digest::from(shard_id as u64), - voter_bitfield: Bitfield::new() - }); - } - - let (deltas, new_crosslinks) = process_crosslinks( - &cry_state, - &partial_crosslinks, - &config); - - assert_eq!(deltas, vec![-2; validator_count]); - for shard_id in 0..config.shard_count { - let c = new_crosslinks[shard_id as usize]; - assert_eq!(c.epoch, cry_state.current_epoch - 1); - assert_eq!(c.hash.low_u64(), 0); - } - } -} diff --git a/src/state/transition/deposits.rs b/src/state/transition/deposits.rs deleted file mode 100644 index 004dddd00..000000000 --- a/src/state/transition/deposits.rs +++ /dev/null @@ -1,177 +0,0 @@ -use super::crystallized_state::CrystallizedState; -use super::utils::types::{ Bitfield, U256 }; -use super::utils::logging::Logger; - -pub fn process_ffg_deposits( - cry_state: &CrystallizedState, - ffg_vote_bitfield: &Bitfield, - log: &Logger) - -> (Vec, u64, U256, bool, bool) -{ - let active_validators: usize = cry_state.num_active_validators(); - let finality_distance: u64 = cry_state.finality_distance(); - let online_reward: u64 = if finality_distance <= 2 { 6 } else { 0 }; - let offline_penalty: u64 = finality_distance.saturating_mul(3); - let mut total_vote_count: u64 = 0; - let mut total_vote_deposits = U256::zero(); - - let mut deltas = vec![0_i64; active_validators]; - for i in 0..active_validators { - if ffg_vote_bitfield.get_bit(&i) { - total_vote_deposits = total_vote_deposits - .saturating_add(cry_state.active_validators[i].balance); - deltas[i] += online_reward as i64; - total_vote_count += 1; - } else { - deltas[i] -= offline_penalty as i64; - } - } - - // Justify if total voting deposits is greater than 2/3 the total deposits. - let should_justify = total_vote_deposits.saturating_mul(U256::from(3)) - >= cry_state.total_deposits.saturating_mul(U256::from(2)); - let mut should_finalize = false; - if should_justify { - if cry_state.last_justified_epoch == - cry_state.current_epoch.saturating_sub(1) { - should_finalize = true; - } - } - - info!(log, "counted ffg votes"; - "total_vote_count" => total_vote_count, - "total_vote_deposits" => total_vote_deposits.low_u64()); - - (deltas, total_vote_count, total_vote_deposits, should_justify, should_finalize) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::utils::types::{ Address, Sha256Digest }; - use super::super::utils::logging::test_logger; - use super::super::super::validator_record::ValidatorRecord; - use super::super:: - utils::test_helpers::get_dangerous_test_keypair; - - #[test] - fn test_deposit_processing_scenario_1() { - let log = test_logger(); - let mut cry_state = CrystallizedState::zero(); - let mut bitfield = Bitfield::new(); - let mut total_deposits = U256::zero(); - let individual_deposit = U256::from(1); - - - // load some validators into the cry state and flag - // they have all voted - for i in 0..10 { - cry_state.active_validators.push(ValidatorRecord { - pubkey: get_dangerous_test_keypair().public, - withdrawal_shard: 0, - withdrawal_address: Address::zero(), - randao_commitment: Sha256Digest::zero(), - balance: individual_deposit, - switch_dynasty: 0 - }); - total_deposits = total_deposits + individual_deposit; - bitfield.set_bit(&i, &true); - } - - cry_state.current_epoch = 100; - cry_state.last_justified_epoch = 99; - cry_state.last_finalized_epoch = 98; - cry_state.total_deposits = total_deposits; - - let (deltas, total_vote_count, total_vote_deposits, - should_justify, should_finalize) = process_ffg_deposits( - &cry_state, &bitfield, &log); - - assert_eq!(deltas, [6; 10]); - assert_eq!(total_vote_count, 10); - assert_eq!(total_vote_deposits, total_deposits); - assert_eq!(should_justify, true); - assert_eq!(should_finalize, true); - } - - #[test] - fn test_deposit_processing_scenario_2() { - let log = test_logger(); - let mut cry_state = CrystallizedState::zero(); - let bitfield = Bitfield::new(); - let individual_deposit = U256::from(0); - - - // load some validators into the cry state and flag - // they have all voted - for _ in 0..10 { - cry_state.active_validators.push(ValidatorRecord { - pubkey: get_dangerous_test_keypair().public, - withdrawal_shard: 0, - withdrawal_address: Address::zero(), - randao_commitment: Sha256Digest::zero(), - balance: individual_deposit, - switch_dynasty: 0 - }); - } - - cry_state.current_epoch = 100; - cry_state.last_justified_epoch = 99; - cry_state.last_finalized_epoch = 98; - cry_state.total_deposits = U256::from(10); - - let (deltas, total_vote_count, total_vote_deposits, - should_justify, should_finalize) = process_ffg_deposits( - &cry_state, &bitfield, &log); - - assert_eq!(deltas, [-6; 10]); - assert_eq!(total_vote_count, 0); - assert_eq!(total_vote_deposits, U256::zero()); - assert_eq!(should_justify, false); - assert_eq!(should_finalize, false); - } - - #[test] - fn test_deposit_processing_scenario_3() { - let log = test_logger(); - let mut cry_state = CrystallizedState::zero(); - let mut bitfield = Bitfield::new(); - let mut total_deposits = U256::zero(); - let individual_deposit = U256::from(50); - - - // load some validators into the cry state and flag - // some have voted - for i in 0..10 { - cry_state.active_validators.push(ValidatorRecord { - pubkey: get_dangerous_test_keypair().public, - withdrawal_shard: 0, - withdrawal_address: Address::zero(), - randao_commitment: Sha256Digest::zero(), - balance: individual_deposit, - switch_dynasty: 0, - }); - - if i < 5 { - bitfield.set_bit(&i, &true); - total_deposits = total_deposits + individual_deposit; - } - } - - cry_state.current_epoch = 100; - cry_state.last_justified_epoch = 99; - cry_state.last_finalized_epoch = 98; - cry_state.total_deposits = U256::from(5); - - let (deltas, total_vote_count, total_vote_deposits, - should_justify, should_finalize) = process_ffg_deposits( - &cry_state, &bitfield, &log); - - assert_eq!(deltas[0..5].to_vec(), [6;5]); - assert_eq!(deltas[5..10].to_vec(), [-6;5]); - assert_eq!(total_vote_count, 5); - assert_eq!(total_vote_deposits, total_deposits); - assert_eq!(should_justify, true); - assert_eq!(should_finalize, true); - } -} diff --git a/src/state/transition/epoch.rs b/src/state/transition/epoch.rs deleted file mode 100644 index 41c3a5f3e..000000000 --- a/src/state/transition/epoch.rs +++ /dev/null @@ -1,203 +0,0 @@ -use super::active_state::ActiveState; -use super::crystallized_state::CrystallizedState; -use super::validator_record::ValidatorRecord; -use super::utils::types::{ Bitfield, U256, Sha256Digest }; -use super::utils::logging::Logger; -use super::config::Config; - -use super::deposits::process_ffg_deposits; -use super::crosslinks::process_crosslinks; -use super::attestors::process_recent_attesters; -use super::proposers::process_recent_proposers; -use super::validators::get_incremented_validator_sets; -use super::shuffling::get_shuffling; - -pub fn initialize_new_epoch( - cry_state: &CrystallizedState, - act_state: &ActiveState, - config: &Config, - log: &Logger) - -> (CrystallizedState, ActiveState) -{ - /* - * Clone the cry_state active validators and the - * act_state ffg bitfield for later modification. - */ - let mut new_validator_records: Vec = - cry_state.active_validators.to_vec(); - // TODO: why isnt this mut? - let ffg_voter_bitfield: Bitfield = - act_state.ffg_voter_bitfield.clone(); - - /* - * For each active_validator in the cry_state, reward/penalize - * them according to their presence in the ffg voter bitfield - * (also with consideration to the cry_state finality distance). - * These rewards/penalties are represented in the ffg_deltas vec. - * - * Determines if justification should take place based upon - * the ratio of total deposits to voting deposits. If justification - * is possible, finalize if the previous epoch was also justified. - */ - let (ffg_deltas, _, _, should_justify, should_finalize) = - process_ffg_deposits ( - &cry_state, - &ffg_voter_bitfield, - &log); - - info!(log, "processed ffg deposits"; - "should_justify" => should_justify, - "should_finalize" => should_finalize); - - /* - * For all the partial crosslinks in the active state, return a vec of - * complete crosslink records representing the most popular partial - * record for each shard_id. - * - * During this process, create a vec of deltas rewarding/penalizing each - * validator for thier votes/non-votes on their allocated shard_ids. - */ - let (crosslink_notaries_deltas, new_crosslinks) = - process_crosslinks( - &cry_state, - &act_state.partial_crosslinks, - &config); - - info!(log, "processed crosslinks"; - "new_crosslinks_count" => new_crosslinks.len()); - - /* - * Create a vec of deltas rewarding/penalizing each validator - * for their votes/non-votes on blocks during the last epoch. - */ - let recent_attesters_deltas = process_recent_attesters( - &cry_state, - &act_state.recent_attesters, - &config); - - /* - * Create a vec of deltas rewarding/penalizing each validator - * for their block proposals during the past epoch. - */ - let recent_proposers_deltas = process_recent_proposers( - &cry_state, - &act_state.recent_proposers); - - /* - * For each validator, update their balances as per the deltas calculated - * previously in this function. - */ - for (i, validator) in new_validator_records.iter_mut().enumerate() { - let balance: i64 = - validator.balance.low_u64() as i64 + - ffg_deltas[i] + - crosslink_notaries_deltas[i] + - recent_attesters_deltas[i] + - recent_proposers_deltas[i]; - if balance > 0 { - validator.balance = U256::from(balance as u64); - } else { - validator.balance = U256::zero(); - } - } - - /* - * Determine the new total deposit sum, determined by the individual - * rewards/penalities accrued by validators during this epoch. - */ - let deposit_sum: i64 = - ffg_deltas.iter().sum::() + - crosslink_notaries_deltas.iter().sum::() + - recent_attesters_deltas.iter().sum::() + - recent_proposers_deltas.iter().sum::(); -info!(log, "processed validator deltas"; - "new_total_deposits" => deposit_sum); - let total_deposits: U256 = match deposit_sum > 0 { - true => U256::from(deposit_sum as u64), - false => U256::zero() - }; - - let last_justified_epoch = match should_justify { - true => cry_state.current_epoch, - false => cry_state.last_justified_epoch - }; - - let (last_finalized_epoch, dynasty) = match should_finalize { - true => (cry_state.current_epoch - 1, cry_state.dynasty + 1), - false => (cry_state.last_finalized_epoch, cry_state.dynasty) - }; - - /* - * If finalization should take place, "increment" the validator sets. - * This involves exiting validators who's balance is too low (from - * deltas) or who's dynasty has ended and inducting queued validators - * (if possible). - */ - let (new_queued_validators, new_active_validators, new_exited_validators) = - match should_finalize - { - true => get_incremented_validator_sets( - &cry_state, - &new_validator_records, - &config, - &log), - false => (cry_state.queued_validators.to_vec(), - cry_state.active_validators.to_vec(), - cry_state.exited_validators.to_vec()) - }; - - /* - * Get the validator shuffling for the new epoch, based upon - * the rando of the supplied active state. - */ - let shuffling = get_shuffling( - &act_state.randao, - &new_active_validators.len(), - &config); - - /* - * Generate a new CrystallizedState - */ - let new_cry_state = CrystallizedState { - active_validators: new_active_validators, - queued_validators: new_queued_validators, - exited_validators: new_exited_validators, - current_shuffling: shuffling, - current_epoch: cry_state.current_epoch + 1, - last_justified_epoch, - last_finalized_epoch, - dynasty, - // TODO: why is this zero? - next_shard: 0, - // TODO: currenct checkpoint wasnt in reference implementation - current_checkpoint: Sha256Digest::zero(), - crosslink_records: new_crosslinks, - total_deposits - }; - - info!(log, "created new crystallized state"; - "epoch" => new_cry_state.current_epoch, - "last_justified_epoch" => new_cry_state.last_justified_epoch, - "last_finalized_epoch" => new_cry_state.last_finalized_epoch); - /* - * Replicate the supplied active state, but reset the fields which - * accumulate things during the course of an epoch (e.g, recent_proposers, - * partial_crosslinks, etc) - */ - let new_act_state = ActiveState { - height: act_state.height, - randao: act_state.randao, - ffg_voter_bitfield: Bitfield::new(), - recent_attesters: vec![], - partial_crosslinks: vec![], - total_skip_count: act_state.total_skip_count, - recent_proposers: vec![] - }; - - info!(log, "reset active state"; - "height" => new_act_state.height); - - (new_cry_state, new_act_state) -} - - diff --git a/src/state/transition/ffg.rs b/src/state/transition/ffg.rs deleted file mode 100644 index 97a3ea9b6..000000000 --- a/src/state/transition/ffg.rs +++ /dev/null @@ -1,192 +0,0 @@ -use std::collections::HashMap; - -use super::crystallized_state::CrystallizedState; -use super::partial_crosslink_record::PartialCrosslinkRecord; -use super::aggregate_vote::AggregateVote; -use super::config::Config; -use super::utils::types::Bitfield; -use super::utils::bls::PublicKey; -use super::crosslinks::{ - get_crosslink_shards, - get_crosslink_aggvote_msg, - get_crosslink_notaries }; - -pub fn update_ffg_and_crosslink_progress( - cry_state: &CrystallizedState, - partial_crosslinks: &Vec, - ffg_voter_bitfield: &Bitfield, - aggregate_votes: &Vec, - config: &Config) - -> (Vec, Bitfield, usize) -{ - let mut vote_key_bitfield_map: HashMap, Bitfield> = - HashMap::new(); - for pc in partial_crosslinks { - vote_key_bitfield_map.insert(pc.vote_key(), pc.voter_bitfield.clone()); - } - let mut global_bitfield = ffg_voter_bitfield.clone(); - let mut total_voters: usize = 0; - let crosslink_shards: Vec = get_crosslink_shards( - &cry_state, &config); - - for av in aggregate_votes { - let attestation = get_crosslink_aggvote_msg( - &av, - &cry_state); - let validator_indicies = get_crosslink_notaries( - &cry_state, - &av.shard_id, - &crosslink_shards); - let mut crosslink_bitfield = match vote_key_bitfield_map.get(&av.vote_key()) { - None => Bitfield::new(), - Some(existing_bitfield) => existing_bitfield.clone() - }; - let mut public_keys: Vec<&PublicKey> = vec![]; - for (i, vi) in validator_indicies.iter().enumerate() { - if av.notary_bitfield.get_bit(&i) { - public_keys.push(&cry_state.active_validators[i].pubkey); - if global_bitfield.get_bit(&vi) == false { - global_bitfield.set_bit(&vi, &true); - crosslink_bitfield.set_bit(&i, &true); - total_voters += 1; - } - } - } - // TODO: add bls verfification here, it is completely bypassed - assert_eq!(attestation, attestation); // fixes warning - - vote_key_bitfield_map.insert(av.vote_key(), crosslink_bitfield); - } - - let mut new_partial_crosslinks: Vec = vec![]; - for (vote_key, bitfield) in vote_key_bitfield_map { - new_partial_crosslinks.push(PartialCrosslinkRecord::new_from_vote_key( - &vote_key, - bitfield)); - } - - (new_partial_crosslinks, global_bitfield, total_voters) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::shuffling::get_shuffling; - use super::super::super::validator_record::ValidatorRecord; - use super::super::super::super::utils::types::{ Sha256Digest, Bitfield }; - use super::super::super::super::utils::bls::AggregateSignature; - - #[test] - fn test_update_ffg_and_crosslink_progress_scenario_1() { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - - // Create some shard_ids and associated hashes - let shard_ids: Vec = (0..10).collect(); - let shard_hashes: Vec = shard_ids.iter() - .map(|_| Sha256Digest::random()).collect(); - - // Define which shards with have partial crosslinks and which will - // have aggregate votes. Note: there should be some overlap here. - let shards_with_partial_crosslinks: Vec = shard_ids[0..5].to_vec(); - let shards_with_aggregate_votes: Vec = shard_ids[4..10].to_vec(); - - // Update the config to neatly fit the shards we created. - config.shard_count = shard_ids.len() as u16; - config.notaries_per_crosslink = 10; - - // Create just enough validators to notarise each shard - let validator_count: usize = - (config.shard_count * config.notaries_per_crosslink) as usize; - - // Load active validators into the cry_state - (0..validator_count).for_each( - |_| cry_state.active_validators.push( - ValidatorRecord::zero_with_thread_rand_pub_key())); - - // Set a shuffling for the validators - let s = get_shuffling( - &Sha256Digest::zero(), - &cry_state.num_active_validators(), - &config); - cry_state.current_shuffling = s.clone(); - - // Create the required partial crosslink records - let partial_crosslinks: Vec = - shards_with_partial_crosslinks - .iter() - .map(|i| { - let mut bitfield = Bitfield::new(); - // Only the first 7 validators should sign the partial xlinks - for i in 0..7 { - bitfield.set_bit(&i, &true); - } - PartialCrosslinkRecord { - shard_id: *i, - shard_block_hash: shard_hashes[*i as usize], - voter_bitfield: bitfield - } - }).collect(); - - let mut total_aggregate_sig_votes = 0; - let mut aggregate_sig_bitfield = Bitfield::new(); - - // Create the required aggregate votes - let aggregate_votes: Vec = shards_with_aggregate_votes - .iter() - .map(|i| { - let validator_indicies = get_crosslink_notaries( - &cry_state, - i, - &shard_ids); - let mut bitfield = Bitfield::new(); - // Only the last 2 validators should sign the aggregate votes - for i in 8..10 { - bitfield.set_bit(&i, &true); - total_aggregate_sig_votes += 1; - aggregate_sig_bitfield.set_bit(&validator_indicies[i], &true) - } - AggregateVote { - shard_id: *i, - shard_block_hash: shard_hashes[*i as usize], - notary_bitfield: bitfield, - aggregate_sig: AggregateSignature::new() - } - }).collect(); - assert_eq!(aggregate_votes.len(), shards_with_aggregate_votes.len(), - "test setup failed."); - - let (new_partial_crosslinks, global_bitfield, vote_count) = - update_ffg_and_crosslink_progress( - &cry_state, - &partial_crosslinks, - &Bitfield::new(), - &aggregate_votes, - &config); - - assert_eq!(total_aggregate_sig_votes, vote_count, - "The total votes returned did not \ - match our running tally."); - - assert_eq!(total_aggregate_sig_votes, - global_bitfield.num_true_bits() as usize, - "The FFG field did not have as many true \ - bits as expected."); - - assert!(aggregate_sig_bitfield == global_bitfield); - - for pc in new_partial_crosslinks { - let id = pc.shard_id; - let mut vote_count = 0; - if shards_with_partial_crosslinks.contains(&id) { - vote_count += 7; - } - if shards_with_aggregate_votes.contains(&id) { - vote_count += 2; - } - assert_eq!(pc.voter_bitfield.num_true_bits(), vote_count, - "shard_id {} failed.", id); - assert_eq!(pc.shard_block_hash, shard_hashes[id as usize]); - } - } -} diff --git a/src/state/transition/mod.rs b/src/state/transition/mod.rs deleted file mode 100644 index 4564453fa..000000000 --- a/src/state/transition/mod.rs +++ /dev/null @@ -1,76 +0,0 @@ -extern crate rlp; - -use super::bytes; -use super::config; -use super::utils; -use super::blake2; -use super::active_state; -use super::aggregate_vote; -use super::crystallized_state; -use super::crosslink_record; -use super::partial_crosslink_record; -use super::recent_proposer_record; -use super::validator_record; -use super::block; - -pub mod new_active_state; -pub mod crosslinks; -pub mod deposits; -pub mod epoch; -pub mod ffg; -pub mod proposers; -pub mod shuffling; -pub mod validators; -pub mod attestors; - - -use super::block::Block; -use super::config::Config; -use super::crystallized_state::CrystallizedState; -use super::active_state::ActiveState; -use super::transition::epoch::initialize_new_epoch; -use super::transition::new_active_state::compute_new_active_state; -use super::utils::logging::Logger; - -pub fn compute_state_transition ( - parent_cry_state: &CrystallizedState, - parent_act_state: &ActiveState, - parent_block: &Block, - block: &Block, - config: &Config, - log: &Logger) - -> (CrystallizedState, ActiveState) -{ - let is_new_epoch = parent_act_state.height % - config.epoch_length == 0; - - /* - * If this transition will push the chain into a new epoch, - * calculate a new crystallized state and "reset" the - * current active state. Otherwise, continue with the existing - * state pair. - */ - let (cry_state, mut act_state) = match is_new_epoch { - false => (parent_cry_state.clone(), parent_act_state.clone()), - true => initialize_new_epoch( - &parent_cry_state, - &parent_act_state, - &config, - &log) - }; - - if is_new_epoch { - info!(log, "initialized new epoch"; - "epoch" => cry_state.current_epoch); - } - - act_state = compute_new_active_state( - &cry_state, - &act_state, - &parent_block, - &block, - &config, - &log); - - (cry_state, act_state) -} diff --git a/src/state/transition/new_active_state.rs b/src/state/transition/new_active_state.rs deleted file mode 100644 index 748d77552..000000000 --- a/src/state/transition/new_active_state.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::ops::BitXor; - -use super::active_state::ActiveState; -use super::crystallized_state::CrystallizedState; -use super::recent_proposer_record::RecentPropserRecord; -use super::block::Block; -use super::utils::types::Sha256Digest; -use super::utils::logging::Logger; -use super::config::Config; -use super::super::pubkeystore::verify_block; -use super::rlp; - -use super::attestors::{ - process_attestations, - get_attesters_and_proposer -}; -use super::ffg::update_ffg_and_crosslink_progress; - -/// Computes the active state generated by applying a new block -/// to a parent block. -/// -/// The `CrystallizedState` and `ActiveState` represented by -/// parent_block.state_hash must also be supplied. -/// -/// # Panics -/// Will panic if the block verification or state transition fails. -/// Some situations may include; signature verification failure or -/// insufficient active validators. -pub fn compute_new_active_state( - cry_state: &CrystallizedState, - act_state: &ActiveState, - parent_block: &Block, - new_block: &Block, - config: &Config, - log: &Logger) - -> ActiveState -{ - /* - * For the present state pair, determine the proposer and attester - * set for the newly presented block (`new_block`). - */ - let (attestation_indicies, proposer) = get_attesters_and_proposer( - &cry_state, - &act_state, - &new_block.skip_count, - &config, - &log); - - info!(log, "calculated attesters and proposers"; - "attesters_count" => attestation_indicies.len(), - "proposer_index" => proposer); - - /* - * Ensure that the new_block bitfield accurately represents the - * public keys which have signed the previous block. I.e., for each - * `true` bit in the new_block bitfield, ensure the corresponding - * attester has signed the aggregate signature. - * - * As it is possible for there to be no attesters, an option - * is returned. The option unwraps to a vec of validator indicies - * which attested to the block. - */ - let parent_block_rlp = rlp::encode(parent_block); - let attesters_option = process_attestations( - &cry_state.active_validators, - &attestation_indicies, - &new_block.attestation_bitfield, - &parent_block_rlp.to_vec(), - &new_block.attestation_aggregate_sig); - let attesters = attesters_option.expect("No attesters available."); - - /* - * Ensure the new_block has been signed by the proposer dictated - * by the state pair. - */ - let verified = verify_block(&new_block, &proposer); - assert!(verified, "Block sig verification failed."); - - info!(log, "verified block signature"; - "proposer_index" => proposer); - - /* - * Collect all the aggregate votes and partial crosslinks - * into a new vec of partial crosslinks. Each entry in this - * new vec will be unique for the "shard_id" field -- each of these - * entries will contain the binary AND of all attestation bitfields - * for that relevant shard_id. - * - * During this process, the aggregate signatures are tested - * against each attester in the respective bitfields (i.e., - * signatures are verified). - * - * Also returned is a count of all validators who attested to a - * shard, as well as a bitfield representing the same thing. - */ - let (partial_crosslinks, ffg_voter_bitfield, total_new_voters) = - update_ffg_and_crosslink_progress( - &cry_state, - &act_state.partial_crosslinks, - &act_state.ffg_voter_bitfield, - &new_block.shard_aggregate_votes, - &config); - - /* - * Create a new RecentProposerRecord, with a reward determined - * by: - * - * - The number of attestations to last_block. - * - The number of crosslink attestations present in the - * previous active_state and new_block. - */ - let proposer = RecentPropserRecord { - index: proposer, - randao_commitment: Sha256Digest::zero(), - balance_delta: (attesters.len() + total_new_voters) as i64 - }; - - /* - * Determine fields for the new active state, then return it. - */ - let height = act_state.height + 1; - let randao = act_state.randao.bitxor(new_block.randao_reveal); - let mut recent_attesters = act_state.recent_attesters.to_vec(); - recent_attesters.extend_from_slice(&attesters); - let total_skip_count = act_state.total_skip_count + new_block.skip_count; - let mut recent_proposers = act_state.recent_proposers.to_vec(); - recent_proposers.push(proposer); - - ActiveState { - height, - randao, - ffg_voter_bitfield, - recent_attesters, - partial_crosslinks, - total_skip_count, - recent_proposers - } } diff --git a/src/state/transition/proposers.rs b/src/state/transition/proposers.rs deleted file mode 100644 index 8ff89c84f..000000000 --- a/src/state/transition/proposers.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::crystallized_state::CrystallizedState; -use super::recent_proposer_record::RecentPropserRecord; - - -pub fn process_recent_proposers( - cry_state: &CrystallizedState, - recent_proposers: &Vec) - -> Vec -{ - let mut deltas: Vec = vec![0; cry_state.num_active_validators()]; - for p in recent_proposers { - deltas[p.index] += p.balance_delta; - } - deltas -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::utils::types::Sha256Digest; - use super::super::validator_record::ValidatorRecord; - - #[test] - fn test_process_recent_proposers() { - let mut cry_state = CrystallizedState::zero(); - let validator_count = 20; - - let mut recent_proposers: Vec = vec![]; - - for i in 0..validator_count { - cry_state.active_validators - .push(ValidatorRecord::zero_with_thread_rand_pub_key()); - if i % 2 == 0 { - recent_proposers.push(RecentPropserRecord { - index: i, - randao_commitment: Sha256Digest::zero(), - balance_delta: 10 - }); - } - } - - let d = process_recent_proposers( - &cry_state, - &recent_proposers); - - for i in 0..validator_count { - if i % 2 == 0 { - assert_eq!(d[i], 10); - } else { - assert_eq!(d[i], 0); - } - } - } -} diff --git a/src/state/transition/shuffling.rs b/src/state/transition/shuffling.rs deleted file mode 100644 index d515de8c6..000000000 --- a/src/state/transition/shuffling.rs +++ /dev/null @@ -1,124 +0,0 @@ -use super::config::Config; -use super::blake2::{ Blake2s, Digest }; -use super::utils::types::Sha256Digest; - -// Interprets a 3-byte slice from a [u8] as an integer. -fn get_shift_from_source(source: &[u8], offset: usize) -> usize { - (source[offset + 2] as usize) | - ((source[offset + 1] as usize) << 8) | - ((source[offset ] as usize) << 16) -} - -// Given entropy in the form of `seed`, return a shuffled list of validators -// indicies of size `validator_count` or `sample`. -pub fn get_shuffling( - seed: &Sha256Digest, - validator_count: &usize, - config: &Config) - -> Vec -{ - assert!(*validator_count > 0, "cannot shuffle 0 validators"); - let mut output: Vec = (0..*validator_count).collect(); - assert!(*validator_count <= (config.max_validators as usize), - "validator_count exceeds max_validators"); - - // Do the first blake hash round - let mut source = Blake2s::new(); - source.input(&seed); - - let mut v = 0; - while v < *validator_count { - let current_source = source.result(); - let mut source_offset = 0; - while source_offset < 30 { - let m = get_shift_from_source(¤t_source, source_offset); - let shuffled_position: usize = (m % (validator_count - v)) + v; - output.swap(v as usize, shuffled_position as usize); - v += 1; - if v >= *validator_count { break; } - source_offset += 3; - } - // Re-hash the source (TODO: this does one extra hash, can be optimised) - source = Blake2s::new(); - source.input(¤t_source); - } - output -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_shuffling_shift_fn() { - let mut x = get_shift_from_source( - &vec![0_u8, 0, 1], - 0); - assert_eq!((x as u32), 1); - - x = get_shift_from_source( - &vec![0_u8, 1, 1], - 0); - assert_eq!(x, 257); - - x = get_shift_from_source( - &vec![1_u8, 1, 1], - 0); - assert_eq!(x, 65793); - - x = get_shift_from_source( - &vec![255_u8, 1, 1], - 0); - assert_eq!(x, 16711937); - } - - - #[test] - fn test_shuffling() { - let s = get_shuffling( - &Sha256Digest::zero(), - &10, - &Config::standard()); - assert_eq!(s, - vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3), - "10 validator shuffle was not as expected"); - } - - #[test] - fn test_shuffling_32() { - let s = get_shuffling( - &Sha256Digest::zero(), - &32, - &Config::standard()); - - assert_eq!(s, - vec!(30, 0, 31, 9, 22, 10, 20, 2, 13, 21, 1, 7, 29, 28, 3, - 27, 6, 8, 25, 15, 12, 26, 4, 18, 16, 23, 19, 11, 14, - 17, 5, 24), - "32 Validator shuffle was not as expected"); - } - - #[test] - fn test_shuffling_unique() { - let s = get_shuffling( - &Sha256Digest::zero(), - &20, - &Config::standard()); - assert_eq!(false, - (1..s.len()).any(|i| s[i..].contains(&s[i-1])), - "Validator Shuffle Non-Unique") - } - - #[test] - fn test_shuffling_with_gt_half_max_validators() { - let mut config = Config::standard(); - config.max_validators = 19; - let s = get_shuffling( - &Sha256Digest::zero(), - &10, - &Config::standard()); - assert_eq!(s, - vec!(0, 9, 7, 6, 4, 1, 8, 5, 2, 3), - "10 validator shuffle was not as expected"); - } -} diff --git a/src/state/transition/validators.rs b/src/state/transition/validators.rs deleted file mode 100644 index aaa916ee2..000000000 --- a/src/state/transition/validators.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::cmp::min; - -use super::crystallized_state::CrystallizedState; -use super::validator_record::ValidatorRecord; -use super::utils::logging::Logger; -use super::config::Config; - -pub fn get_incremented_validator_sets( - cry_state: &CrystallizedState, - active_validators: &Vec, - config: &Config, - log: &Logger) - -> (Vec, Vec, Vec) -{ - let mut new_active_validators: Vec = vec![]; - let mut new_exited_validators: Vec - = cry_state.exited_validators.clone(); - let next_dynasty = cry_state.dynasty + 1; - let mut ejection_count = 0; - - for v in active_validators { - if (v.balance <= config.eject_balance) | - (v.switch_dynasty == next_dynasty) { - new_exited_validators.push(v.clone()); - ejection_count += 1; - } - else { - new_active_validators.push(v.clone()); - } - } - - let induction_count = min( - cry_state.num_queued_validators(), - cry_state.num_active_validators() / 30 + 1); - let mut first_ineligable = induction_count; - for i in 0..induction_count { - if cry_state.queued_validators[i].switch_dynasty > next_dynasty { - first_ineligable = i; - break; - } - new_active_validators.push(cry_state.queued_validators[i].clone()); - } - let new_queued_validators = cry_state. - queued_validators[first_ineligable..cry_state.queued_validators.len()] - .to_vec(); - - info!(log, "updated validator sets"; - "inducted_count" => induction_count, - "ejected_count" => ejection_count); - - (new_queued_validators, new_active_validators, new_exited_validators) -} - -#[cfg(test)] -mod tests { - use super::*; - use super::super::utils::types::U256; - use super::super::utils::logging::test_logger; - - fn test_setup() -> (CrystallizedState, Config) { - let mut cry_state = CrystallizedState::zero(); - let mut config = Config::standard(); - - config.shard_count = 5; - config.notaries_per_crosslink = 2; - config.default_balance = U256::from(32000); - config.eject_balance = U256::from(16000); - cry_state.current_epoch = 100; - cry_state.dynasty = 100; - (cry_state, config) - } - - #[test] - fn test_incrementing_validator_sets_scenario_1() { - let (mut cry_state, config) = test_setup(); - let validator_count = 10; - - let mut a: Vec = vec![]; - let mut q: Vec = vec![]; - let mut x: Vec = vec![]; - - (0..validator_count).for_each(|_| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - v.switch_dynasty = cry_state.dynasty + 5; - v.balance = config.default_balance.clone(); - a.push(v) - }); - - (0..validator_count).for_each(|_| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - v.switch_dynasty = cry_state.dynasty + 1; - v.balance = config.default_balance.clone(); - q.push(v) - }); - - (0..validator_count).for_each(|_| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - v.switch_dynasty = cry_state.dynasty - 1; - v.balance = config.default_balance.clone(); - x.push(v) - }); - - cry_state.active_validators = a.to_vec(); - cry_state.queued_validators = q.to_vec(); - cry_state.exited_validators = x.to_vec(); - - let (nq, na, nx) = get_incremented_validator_sets( - &cry_state, - &a, - &config, - &test_logger()); - - let inducted = validator_count / 30 + 1; - assert!(inducted > 0); - - assert_eq!(na.len(), validator_count + inducted, "new active incorrect"); - assert_eq!(nq.len(), validator_count - inducted, "new queued incorrect"); - assert_eq!(nx.len(), validator_count, "new exited incorrect"); - } - - #[test] - fn test_incrementing_validator_sets_scenario_2() { - let (mut cry_state, config) = test_setup(); - let validator_count = 60; - let expiring_active = 5; - let eligable_queued = 1; - - let mut a: Vec = vec![]; - let mut q: Vec = vec![]; - let mut x: Vec = vec![]; - - (0..validator_count).for_each(|i| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - if i < expiring_active { - v.switch_dynasty = cry_state.dynasty + 1; - } else { - v.switch_dynasty = cry_state.dynasty + 5; - } - v.balance = config.default_balance.clone(); - a.push(v) - }); - - (0..validator_count).for_each(|i| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - if i < eligable_queued { - v.switch_dynasty = cry_state.dynasty + 1; - } else { - v.switch_dynasty = cry_state.dynasty + 5; - } - v.balance = config.default_balance.clone(); - q.push(v) - }); - - (0..validator_count).for_each(|_| { - let mut v = ValidatorRecord::zero_with_thread_rand_pub_key(); - v.switch_dynasty = cry_state.dynasty - 1; - v.balance = config.default_balance.clone(); - x.push(v) - }); - - cry_state.active_validators = a.to_vec(); - cry_state.queued_validators = q.to_vec(); - cry_state.exited_validators = x.to_vec(); - - let (nq, na, nx) = get_incremented_validator_sets( - &cry_state, - &a, - &config, - &test_logger()); - - let inducted = validator_count / 30 + 1; - assert!(inducted > eligable_queued, "this test requires more inductable \ - validators than there are eligable."); - - assert_eq!(na.len(), validator_count - expiring_active + eligable_queued, - "new active incorrect"); - assert_eq!(nq.len(), validator_count - eligable_queued, - "new queued incorrect"); - assert_eq!(nx.len(), validator_count + expiring_active, - "new exited incorrect"); - } -}