Merge branch 'master' into chain-update
This commit is contained in:
commit
f01aac5ffa
@ -45,7 +45,6 @@ members = [
|
|||||||
"beacon_chain/utils/slot_clock",
|
"beacon_chain/utils/slot_clock",
|
||||||
"beacon_chain/utils/ssz",
|
"beacon_chain/utils/ssz",
|
||||||
"beacon_chain/utils/vec_shuffle",
|
"beacon_chain/utils/vec_shuffle",
|
||||||
"beacon_chain/validator_change",
|
|
||||||
"beacon_chain/validator_induction",
|
"beacon_chain/validator_induction",
|
||||||
"beacon_chain/validator_shuffling",
|
"beacon_chain/validator_shuffling",
|
||||||
"lighthouse/beacon_chain",
|
"lighthouse/beacon_chain",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use spec::ChainSpec;
|
use spec::ChainSpec;
|
||||||
use types::{BeaconState, CrosslinkRecord, ForkData, ValidatorStatus};
|
use types::{BeaconState, CrosslinkRecord, ForkData};
|
||||||
use validator_induction::ValidatorInductor;
|
|
||||||
use validator_shuffling::{shard_and_committees_for_cycle, ValidatorAssignmentError};
|
use validator_shuffling::{shard_and_committees_for_cycle, ValidatorAssignmentError};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -11,26 +10,11 @@ pub enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn genesis_beacon_state(spec: &ChainSpec) -> Result<BeaconState, Error> {
|
pub fn genesis_beacon_state(spec: &ChainSpec) -> Result<BeaconState, Error> {
|
||||||
/*
|
|
||||||
* Parse the ValidatorRegistrations into ValidatorRecords and induct them.
|
|
||||||
*
|
|
||||||
* Ignore any records which fail proof-of-possession or are invalid.
|
|
||||||
*/
|
|
||||||
let validators = {
|
|
||||||
let mut inductor = ValidatorInductor::new(0, spec.shard_count, vec![]);
|
|
||||||
for registration in &spec.initial_validators {
|
|
||||||
let _ = inductor.induct(®istration, ValidatorStatus::Active);
|
|
||||||
}
|
|
||||||
inductor.to_vec()
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign the validators to shards, using all zeros as the seed.
|
* Assign the validators to shards, using all zeros as the seed.
|
||||||
*
|
|
||||||
* Crystallizedstate stores two cycles, so we simply repeat the same assignment twice.
|
|
||||||
*/
|
*/
|
||||||
let _shard_and_committee_for_slots = {
|
let _shard_and_committee_for_slots = {
|
||||||
let mut a = shard_and_committees_for_cycle(&[0; 32], &validators, 0, &spec)?;
|
let mut a = shard_and_committees_for_cycle(&[0; 32], &spec.initial_validators, 0, &spec)?;
|
||||||
let mut b = a.clone();
|
let mut b = a.clone();
|
||||||
a.append(&mut b);
|
a.append(&mut b);
|
||||||
a
|
a
|
||||||
@ -55,7 +39,8 @@ pub fn genesis_beacon_state(spec: &ChainSpec) -> Result<BeaconState, Error> {
|
|||||||
/*
|
/*
|
||||||
* Validator registry
|
* Validator registry
|
||||||
*/
|
*/
|
||||||
validator_registry: validators,
|
validator_registry: spec.initial_validators.clone(),
|
||||||
|
validator_balances: spec.initial_balances.clone(),
|
||||||
validator_registry_latest_change_slot: spec.initial_slot_number,
|
validator_registry_latest_change_slot: spec.initial_slot_number,
|
||||||
validator_registry_exit_count: 0,
|
validator_registry_exit_count: 0,
|
||||||
validator_registry_delta_chain_tip: spec.zero_hash,
|
validator_registry_delta_chain_tip: spec.zero_hash,
|
||||||
@ -100,7 +85,6 @@ mod tests {
|
|||||||
extern crate bls;
|
extern crate bls;
|
||||||
extern crate validator_induction;
|
extern crate validator_induction;
|
||||||
|
|
||||||
use self::bls::{create_proof_of_possession, Keypair};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// TODO: enhance these tests.
|
// TODO: enhance these tests.
|
||||||
@ -117,19 +101,4 @@ mod tests {
|
|||||||
spec.initial_validators.len()
|
spec.initial_validators.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_genesis_bad_validator() {
|
|
||||||
let mut spec = ChainSpec::foundation();
|
|
||||||
|
|
||||||
let random_kp = Keypair::random();
|
|
||||||
spec.initial_validators[4].proof_of_possession = create_proof_of_possession(&random_kp);
|
|
||||||
|
|
||||||
let state = genesis_beacon_state(&spec).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
state.validator_registry.len(),
|
|
||||||
spec.initial_validators.len() - 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use super::ChainSpec;
|
use super::ChainSpec;
|
||||||
use bls::{create_proof_of_possession, Keypair, PublicKey, SecretKey};
|
use bls::{Keypair, PublicKey, SecretKey};
|
||||||
|
|
||||||
use types::{Address, Hash256, ValidatorRegistration};
|
use types::{Address, Hash256, ValidatorRecord};
|
||||||
|
|
||||||
|
/// The size of a validators deposit in GWei.
|
||||||
|
pub const DEPOSIT_GWEI: u64 = 32_000_000_000;
|
||||||
|
|
||||||
impl ChainSpec {
|
impl ChainSpec {
|
||||||
/// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
|
/// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
|
||||||
@ -64,14 +67,15 @@ impl ChainSpec {
|
|||||||
* Intialization parameters
|
* Intialization parameters
|
||||||
*/
|
*/
|
||||||
initial_validators: initial_validators_for_testing(),
|
initial_validators: initial_validators_for_testing(),
|
||||||
|
initial_balances: initial_balances_for_testing(),
|
||||||
genesis_time: 1_544_672_897,
|
genesis_time: 1_544_672_897,
|
||||||
processed_pow_receipt_root: Hash256::from("pow_root".as_bytes()),
|
processed_pow_receipt_root: Hash256::from("pow_root".as_bytes()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a set of validator registrations to use with testing until the real chain starts.
|
/// Generate a set of validator records to use with testing until the real chain starts.
|
||||||
fn initial_validators_for_testing() -> Vec<ValidatorRegistration> {
|
fn initial_validators_for_testing() -> Vec<ValidatorRecord> {
|
||||||
// Some dummy private keys to start with.
|
// Some dummy private keys to start with.
|
||||||
let key_strings = vec![
|
let key_strings = vec![
|
||||||
"jzjxxgjajfjrmgodszzsgqccmhnyvetcuxobhtynojtpdtbj",
|
"jzjxxgjajfjrmgodszzsgqccmhnyvetcuxobhtynojtpdtbj",
|
||||||
@ -94,19 +98,28 @@ fn initial_validators_for_testing() -> Vec<ValidatorRegistration> {
|
|||||||
pk: public_key,
|
pk: public_key,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let validator_registration = ValidatorRegistration {
|
let validator_record = ValidatorRecord {
|
||||||
pubkey: keypair.pk.clone(),
|
pubkey: keypair.pk.clone(),
|
||||||
withdrawal_shard: 0,
|
withdrawal_credentials: Hash256::zero(),
|
||||||
withdrawal_address: Address::random(),
|
randao_commitment: Hash256::zero(),
|
||||||
randao_commitment: Hash256::random(),
|
randao_layers: 0,
|
||||||
proof_of_possession: create_proof_of_possession(&keypair),
|
status: From::from(0),
|
||||||
|
latest_status_change_slot: 0,
|
||||||
|
exit_count: 0,
|
||||||
|
custody_commitment: Hash256::zero(),
|
||||||
|
latest_custody_reseed_slot: 0,
|
||||||
|
penultimate_custody_reseed_slot: 0,
|
||||||
};
|
};
|
||||||
initial_validators.push(validator_registration);
|
initial_validators.push(validator_record);
|
||||||
}
|
}
|
||||||
|
|
||||||
initial_validators
|
initial_validators
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initial_balances_for_testing() -> Vec<u64> {
|
||||||
|
vec![DEPOSIT_GWEI; 4]
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -3,7 +3,7 @@ extern crate types;
|
|||||||
|
|
||||||
mod foundation;
|
mod foundation;
|
||||||
|
|
||||||
use types::{Address, Hash256, ValidatorRegistration};
|
use types::{Address, Hash256, ValidatorRecord};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct ChainSpec {
|
pub struct ChainSpec {
|
||||||
@ -60,7 +60,8 @@ pub struct ChainSpec {
|
|||||||
/*
|
/*
|
||||||
* Intialization parameters
|
* Intialization parameters
|
||||||
*/
|
*/
|
||||||
pub initial_validators: Vec<ValidatorRegistration>,
|
pub initial_validators: Vec<ValidatorRecord>,
|
||||||
|
pub initial_balances: Vec<u64>,
|
||||||
pub genesis_time: u64,
|
pub genesis_time: u64,
|
||||||
pub processed_pow_receipt_root: Hash256,
|
pub processed_pow_receipt_root: Hash256,
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
use super::Hash256;
|
|
||||||
use super::{Attestation, SpecialRecord};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct ActiveState {
|
|
||||||
pub pending_attestations: Vec<Attestation>,
|
|
||||||
pub pending_specials: Vec<SpecialRecord>,
|
|
||||||
pub recent_block_hashes: Vec<Hash256>,
|
|
||||||
pub randao_mix: Hash256,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveState {
|
|
||||||
// TODO: implement this.
|
|
||||||
pub fn canonical_root(&self) -> Hash256 {
|
|
||||||
Hash256::zero()
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ use hashing::canonical_hash;
|
|||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
|
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
pub struct BeaconState {
|
pub struct BeaconState {
|
||||||
// Misc
|
// Misc
|
||||||
pub slot: u64,
|
pub slot: u64,
|
||||||
@ -20,6 +20,7 @@ pub struct BeaconState {
|
|||||||
|
|
||||||
// Validator registry
|
// Validator registry
|
||||||
pub validator_registry: Vec<ValidatorRecord>,
|
pub validator_registry: Vec<ValidatorRecord>,
|
||||||
|
pub validator_balances: Vec<u64>,
|
||||||
pub validator_registry_latest_change_slot: u64,
|
pub validator_registry_latest_change_slot: u64,
|
||||||
pub validator_registry_exit_count: u64,
|
pub validator_registry_exit_count: u64,
|
||||||
pub validator_registry_delta_chain_tip: Hash256,
|
pub validator_registry_delta_chain_tip: Hash256,
|
||||||
@ -62,6 +63,7 @@ impl Encodable for BeaconState {
|
|||||||
s.append(&self.genesis_time);
|
s.append(&self.genesis_time);
|
||||||
s.append(&self.fork_data);
|
s.append(&self.fork_data);
|
||||||
s.append(&self.validator_registry);
|
s.append(&self.validator_registry);
|
||||||
|
s.append(&self.validator_balances);
|
||||||
s.append(&self.validator_registry_latest_change_slot);
|
s.append(&self.validator_registry_latest_change_slot);
|
||||||
s.append(&self.validator_registry_exit_count);
|
s.append(&self.validator_registry_exit_count);
|
||||||
s.append(&self.validator_registry_delta_chain_tip);
|
s.append(&self.validator_registry_delta_chain_tip);
|
||||||
@ -89,6 +91,7 @@ impl Decodable for BeaconState {
|
|||||||
let (genesis_time, i) = <_>::ssz_decode(bytes, i)?;
|
let (genesis_time, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (fork_data, i) = <_>::ssz_decode(bytes, i)?;
|
let (fork_data, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (validator_registry, i) = <_>::ssz_decode(bytes, i)?;
|
let (validator_registry, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (validator_balances, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (validator_registry_latest_change_slot, i) = <_>::ssz_decode(bytes, i)?;
|
let (validator_registry_latest_change_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (validator_registry_exit_count, i) = <_>::ssz_decode(bytes, i)?;
|
let (validator_registry_exit_count, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (validator_registry_delta_chain_tip, i) = <_>::ssz_decode(bytes, i)?;
|
let (validator_registry_delta_chain_tip, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
@ -114,6 +117,7 @@ impl Decodable for BeaconState {
|
|||||||
genesis_time,
|
genesis_time,
|
||||||
fork_data,
|
fork_data,
|
||||||
validator_registry,
|
validator_registry,
|
||||||
|
validator_balances,
|
||||||
validator_registry_latest_change_slot,
|
validator_registry_latest_change_slot,
|
||||||
validator_registry_exit_count,
|
validator_registry_exit_count,
|
||||||
validator_registry_delta_chain_tip,
|
validator_registry_delta_chain_tip,
|
||||||
@ -145,6 +149,7 @@ impl<T: RngCore> TestRandom<T> for BeaconState {
|
|||||||
genesis_time: <_>::random_for_test(rng),
|
genesis_time: <_>::random_for_test(rng),
|
||||||
fork_data: <_>::random_for_test(rng),
|
fork_data: <_>::random_for_test(rng),
|
||||||
validator_registry: <_>::random_for_test(rng),
|
validator_registry: <_>::random_for_test(rng),
|
||||||
|
validator_balances: <_>::random_for_test(rng),
|
||||||
validator_registry_latest_change_slot: <_>::random_for_test(rng),
|
validator_registry_latest_change_slot: <_>::random_for_test(rng),
|
||||||
validator_registry_exit_count: <_>::random_for_test(rng),
|
validator_registry_exit_count: <_>::random_for_test(rng),
|
||||||
validator_registry_delta_chain_tip: <_>::random_for_test(rng),
|
validator_registry_delta_chain_tip: <_>::random_for_test(rng),
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
use super::ValidatorRegistration;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ChainConfig {
|
|
||||||
// Old, potentially outdated constants
|
|
||||||
pub cycle_length: u8,
|
|
||||||
pub deposit_size_gwei: u64,
|
|
||||||
pub shard_count: u16,
|
|
||||||
pub min_committee_size: u64,
|
|
||||||
pub max_validator_churn_quotient: u64,
|
|
||||||
pub genesis_time: u64,
|
|
||||||
pub slot_duration_millis: u64,
|
|
||||||
pub initial_validators: Vec<ValidatorRegistration>,
|
|
||||||
|
|
||||||
// New constants
|
|
||||||
pub epoch_length: u64,
|
|
||||||
pub min_attestation_inclusion_delay: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Presently this is just some arbitrary time in Sept 2018.
|
|
||||||
*/
|
|
||||||
const TEST_GENESIS_TIME: u64 = 1_537_488_655;
|
|
||||||
|
|
||||||
impl ChainConfig {
|
|
||||||
pub fn standard() -> Self {
|
|
||||||
Self {
|
|
||||||
cycle_length: 64,
|
|
||||||
deposit_size_gwei: 32 * (10 ^ 9),
|
|
||||||
shard_count: 1024,
|
|
||||||
min_committee_size: 128,
|
|
||||||
max_validator_churn_quotient: 32,
|
|
||||||
genesis_time: TEST_GENESIS_TIME,
|
|
||||||
slot_duration_millis: 16 * 1000,
|
|
||||||
initial_validators: vec![],
|
|
||||||
|
|
||||||
// New
|
|
||||||
epoch_length: 64,
|
|
||||||
min_attestation_inclusion_delay: 4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(&self) -> bool {
|
|
||||||
// criteria that ensure the config is valid
|
|
||||||
|
|
||||||
// shard_count / cycle_length > 0 otherwise validator delegation
|
|
||||||
// will fail.
|
|
||||||
if self.shard_count / u16::from(self.cycle_length) == 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn super_fast_tests() -> Self {
|
|
||||||
Self {
|
|
||||||
cycle_length: 2,
|
|
||||||
deposit_size_gwei: 32 * (10 ^ 9),
|
|
||||||
shard_count: 2,
|
|
||||||
min_committee_size: 2,
|
|
||||||
max_validator_churn_quotient: 32,
|
|
||||||
genesis_time: TEST_GENESIS_TIME, // arbitrary
|
|
||||||
slot_duration_millis: 16 * 1000,
|
|
||||||
initial_validators: vec![],
|
|
||||||
|
|
||||||
// New constants
|
|
||||||
epoch_length: 64,
|
|
||||||
min_attestation_inclusion_delay: 4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
use super::crosslink_record::CrosslinkRecord;
|
|
||||||
use super::shard_committee::ShardCommittee;
|
|
||||||
use super::validator_record::ValidatorRecord;
|
|
||||||
use super::Hash256;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub struct CrystallizedState {
|
|
||||||
pub validator_set_change_slot: u64,
|
|
||||||
pub validators: Vec<ValidatorRecord>,
|
|
||||||
pub crosslinks: Vec<CrosslinkRecord>,
|
|
||||||
pub last_state_recalculation_slot: u64,
|
|
||||||
pub last_finalized_slot: u64,
|
|
||||||
pub last_justified_slot: u64,
|
|
||||||
pub justified_streak: u64,
|
|
||||||
pub shard_and_committee_for_slots: Vec<Vec<ShardCommittee>>,
|
|
||||||
pub deposits_penalized_in_period: Vec<u32>,
|
|
||||||
pub validator_set_delta_hash_chain: Hash256,
|
|
||||||
pub pre_fork_version: u32,
|
|
||||||
pub post_fork_version: u32,
|
|
||||||
pub fork_slot_number: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CrystallizedState {
|
|
||||||
// TODO: implement this.
|
|
||||||
pub fn canonical_root(&self) -> Hash256 {
|
|
||||||
Hash256::zero()
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ pub struct DepositInput {
|
|||||||
pub pubkey: PublicKey,
|
pub pubkey: PublicKey,
|
||||||
pub withdrawal_credentials: Hash256,
|
pub withdrawal_credentials: Hash256,
|
||||||
pub randao_commitment: Hash256,
|
pub randao_commitment: Hash256,
|
||||||
|
pub custody_commitment: Hash256,
|
||||||
pub proof_of_possession: Signature,
|
pub proof_of_possession: Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ impl Encodable for DepositInput {
|
|||||||
s.append(&self.pubkey);
|
s.append(&self.pubkey);
|
||||||
s.append(&self.withdrawal_credentials);
|
s.append(&self.withdrawal_credentials);
|
||||||
s.append(&self.randao_commitment);
|
s.append(&self.randao_commitment);
|
||||||
|
s.append(&self.custody_commitment);
|
||||||
s.append(&self.proof_of_possession);
|
s.append(&self.proof_of_possession);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,6 +28,7 @@ impl Decodable for DepositInput {
|
|||||||
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
|
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (proof_of_possession, i) = <_>::ssz_decode(bytes, i)?;
|
let (proof_of_possession, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
@ -33,6 +36,7 @@ impl Decodable for DepositInput {
|
|||||||
pubkey,
|
pubkey,
|
||||||
withdrawal_credentials,
|
withdrawal_credentials,
|
||||||
randao_commitment,
|
randao_commitment,
|
||||||
|
custody_commitment,
|
||||||
proof_of_possession,
|
proof_of_possession,
|
||||||
},
|
},
|
||||||
i,
|
i,
|
||||||
@ -46,6 +50,7 @@ impl<T: RngCore> TestRandom<T> for DepositInput {
|
|||||||
pubkey: <_>::random_for_test(rng),
|
pubkey: <_>::random_for_test(rng),
|
||||||
withdrawal_credentials: <_>::random_for_test(rng),
|
withdrawal_credentials: <_>::random_for_test(rng),
|
||||||
randao_commitment: <_>::random_for_test(rng),
|
randao_commitment: <_>::random_for_test(rng),
|
||||||
|
custody_commitment: <_>::random_for_test(rng),
|
||||||
proof_of_possession: <_>::random_for_test(rng),
|
proof_of_possession: <_>::random_for_test(rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
|
|||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub struct ForkData {
|
pub struct ForkData {
|
||||||
pub pre_fork_version: u64,
|
pub pre_fork_version: u64,
|
||||||
pub post_fork_version: u64,
|
pub post_fork_version: u64,
|
||||||
|
@ -5,7 +5,6 @@ extern crate ssz;
|
|||||||
|
|
||||||
pub mod test_utils;
|
pub mod test_utils;
|
||||||
|
|
||||||
pub mod active_state;
|
|
||||||
pub mod attestation;
|
pub mod attestation;
|
||||||
pub mod attestation_data;
|
pub mod attestation_data;
|
||||||
pub mod beacon_block;
|
pub mod beacon_block;
|
||||||
@ -13,9 +12,7 @@ pub mod beacon_block_body;
|
|||||||
pub mod beacon_state;
|
pub mod beacon_state;
|
||||||
pub mod candidate_pow_receipt_root_record;
|
pub mod candidate_pow_receipt_root_record;
|
||||||
pub mod casper_slashing;
|
pub mod casper_slashing;
|
||||||
pub mod chain_config;
|
|
||||||
pub mod crosslink_record;
|
pub mod crosslink_record;
|
||||||
pub mod crystallized_state;
|
|
||||||
pub mod deposit;
|
pub mod deposit;
|
||||||
pub mod deposit_data;
|
pub mod deposit_data;
|
||||||
pub mod deposit_input;
|
pub mod deposit_input;
|
||||||
@ -29,23 +26,19 @@ pub mod shard_reassignment_record;
|
|||||||
pub mod slashable_vote_data;
|
pub mod slashable_vote_data;
|
||||||
pub mod special_record;
|
pub mod special_record;
|
||||||
pub mod validator_record;
|
pub mod validator_record;
|
||||||
pub mod validator_registration;
|
|
||||||
|
|
||||||
pub mod readers;
|
pub mod readers;
|
||||||
|
|
||||||
use self::ethereum_types::{H160, H256, U256};
|
use self::ethereum_types::{H160, H256, U256};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub use crate::active_state::ActiveState;
|
|
||||||
pub use crate::attestation::Attestation;
|
pub use crate::attestation::Attestation;
|
||||||
pub use crate::attestation_data::AttestationData;
|
pub use crate::attestation_data::AttestationData;
|
||||||
pub use crate::beacon_block::BeaconBlock;
|
pub use crate::beacon_block::BeaconBlock;
|
||||||
pub use crate::beacon_block_body::BeaconBlockBody;
|
pub use crate::beacon_block_body::BeaconBlockBody;
|
||||||
pub use crate::beacon_state::BeaconState;
|
pub use crate::beacon_state::BeaconState;
|
||||||
pub use crate::casper_slashing::CasperSlashing;
|
pub use crate::casper_slashing::CasperSlashing;
|
||||||
pub use crate::chain_config::ChainConfig;
|
|
||||||
pub use crate::crosslink_record::CrosslinkRecord;
|
pub use crate::crosslink_record::CrosslinkRecord;
|
||||||
pub use crate::crystallized_state::CrystallizedState;
|
|
||||||
pub use crate::deposit::Deposit;
|
pub use crate::deposit::Deposit;
|
||||||
pub use crate::deposit_data::DepositData;
|
pub use crate::deposit_data::DepositData;
|
||||||
pub use crate::deposit_input::DepositInput;
|
pub use crate::deposit_input::DepositInput;
|
||||||
@ -58,7 +51,6 @@ pub use crate::shard_committee::ShardCommittee;
|
|||||||
pub use crate::slashable_vote_data::SlashableVoteData;
|
pub use crate::slashable_vote_data::SlashableVoteData;
|
||||||
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
|
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
|
||||||
pub use crate::validator_record::{ValidatorRecord, ValidatorStatus};
|
pub use crate::validator_record::{ValidatorRecord, ValidatorStatus};
|
||||||
pub use crate::validator_registration::ValidatorRegistration;
|
|
||||||
|
|
||||||
pub type Hash256 = H256;
|
pub type Hash256 = H256;
|
||||||
pub type Address = H160;
|
pub type Address = H160;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::bls::PublicKey;
|
use super::bls::PublicKey;
|
||||||
use super::{Address, Hash256};
|
use super::{Hash256};
|
||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use ssz::{Decodable, DecodeError, Encodable, SszStream};
|
use ssz::{Decodable, DecodeError, Encodable, SszStream};
|
||||||
@ -32,13 +32,15 @@ impl convert::From<u8> for ValidatorStatus {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ValidatorRecord {
|
pub struct ValidatorRecord {
|
||||||
pub pubkey: PublicKey,
|
pub pubkey: PublicKey,
|
||||||
pub withdrawal_shard: u64,
|
pub withdrawal_credentials: Hash256,
|
||||||
pub withdrawal_address: Address,
|
|
||||||
pub randao_commitment: Hash256,
|
pub randao_commitment: Hash256,
|
||||||
pub randao_last_change: u64,
|
pub randao_layers: u64,
|
||||||
pub balance: u64,
|
|
||||||
pub status: ValidatorStatus,
|
pub status: ValidatorStatus,
|
||||||
pub exit_slot: u64,
|
pub latest_status_change_slot: u64,
|
||||||
|
pub exit_count: u64,
|
||||||
|
pub custody_commitment: Hash256,
|
||||||
|
pub latest_custody_reseed_slot: u64,
|
||||||
|
pub penultimate_custody_reseed_slot: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatorRecord {
|
impl ValidatorRecord {
|
||||||
@ -94,37 +96,43 @@ impl<T: RngCore> TestRandom<T> for ValidatorStatus {
|
|||||||
impl Encodable for ValidatorRecord {
|
impl Encodable for ValidatorRecord {
|
||||||
fn ssz_append(&self, s: &mut SszStream) {
|
fn ssz_append(&self, s: &mut SszStream) {
|
||||||
s.append(&self.pubkey);
|
s.append(&self.pubkey);
|
||||||
s.append(&self.withdrawal_shard);
|
s.append(&self.withdrawal_credentials);
|
||||||
s.append(&self.withdrawal_address);
|
|
||||||
s.append(&self.randao_commitment);
|
s.append(&self.randao_commitment);
|
||||||
s.append(&self.randao_last_change);
|
s.append(&self.randao_layers);
|
||||||
s.append(&self.balance);
|
|
||||||
s.append(&self.status);
|
s.append(&self.status);
|
||||||
s.append(&self.exit_slot);
|
s.append(&self.latest_status_change_slot);
|
||||||
|
s.append(&self.exit_count);
|
||||||
|
s.append(&self.custody_commitment);
|
||||||
|
s.append(&self.latest_custody_reseed_slot);
|
||||||
|
s.append(&self.penultimate_custody_reseed_slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for ValidatorRecord {
|
impl Decodable for ValidatorRecord {
|
||||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||||
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (withdrawal_shard, i) = <_>::ssz_decode(bytes, i)?;
|
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (withdrawal_address, i) = <_>::ssz_decode(bytes, i)?;
|
|
||||||
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (randao_last_change, i) = <_>::ssz_decode(bytes, i)?;
|
let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (balance, i) = <_>::ssz_decode(bytes, i)?;
|
|
||||||
let (status, i) = <_>::ssz_decode(bytes, i)?;
|
let (status, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
let (exit_slot, i) = <_>::ssz_decode(bytes, i)?;
|
let (latest_status_change_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (exit_count, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (latest_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
let (penultimate_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
Self {
|
Self {
|
||||||
pubkey,
|
pubkey,
|
||||||
withdrawal_shard,
|
withdrawal_credentials,
|
||||||
withdrawal_address,
|
|
||||||
randao_commitment,
|
randao_commitment,
|
||||||
randao_last_change,
|
randao_layers,
|
||||||
balance,
|
|
||||||
status,
|
status,
|
||||||
exit_slot,
|
latest_status_change_slot,
|
||||||
|
exit_count,
|
||||||
|
custody_commitment,
|
||||||
|
latest_custody_reseed_slot,
|
||||||
|
penultimate_custody_reseed_slot
|
||||||
},
|
},
|
||||||
i,
|
i,
|
||||||
))
|
))
|
||||||
@ -135,13 +143,15 @@ impl<T: RngCore> TestRandom<T> for ValidatorRecord {
|
|||||||
fn random_for_test(rng: &mut T) -> Self {
|
fn random_for_test(rng: &mut T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pubkey: <_>::random_for_test(rng),
|
pubkey: <_>::random_for_test(rng),
|
||||||
withdrawal_shard: <_>::random_for_test(rng),
|
withdrawal_credentials: <_>::random_for_test(rng),
|
||||||
withdrawal_address: <_>::random_for_test(rng),
|
|
||||||
randao_commitment: <_>::random_for_test(rng),
|
randao_commitment: <_>::random_for_test(rng),
|
||||||
randao_last_change: <_>::random_for_test(rng),
|
randao_layers: <_>::random_for_test(rng),
|
||||||
balance: <_>::random_for_test(rng),
|
|
||||||
status: <_>::random_for_test(rng),
|
status: <_>::random_for_test(rng),
|
||||||
exit_slot: <_>::random_for_test(rng),
|
latest_status_change_slot: <_>::random_for_test(rng),
|
||||||
|
exit_count: <_>::random_for_test(rng),
|
||||||
|
custody_commitment: <_>::random_for_test(rng),
|
||||||
|
latest_custody_reseed_slot: <_>::random_for_test(rng),
|
||||||
|
penultimate_custody_reseed_slot: <_>::random_for_test(rng),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,40 +42,40 @@ mod tests {
|
|||||||
extern crate yaml_rust;
|
extern crate yaml_rust;
|
||||||
|
|
||||||
use self::yaml_rust::yaml;
|
use self::yaml_rust::yaml;
|
||||||
use super::hashing::canonical_hash;
|
|
||||||
use super::*;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
// TODO: update test vectors to use keccak instead of blake.
|
use std::{fs::File, io::prelude::*, path::PathBuf};
|
||||||
// https://github.com/sigp/lighthouse/issues/121
|
|
||||||
|
use super::{hashing::canonical_hash, *};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn test_shuffling() {
|
fn test_shuffling() {
|
||||||
let mut file = File::open("./src/specs/shuffle_test_vectors.yaml").unwrap();
|
let mut file = {
|
||||||
|
let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
file_path_buf.push("src/specs/shuffle_test_vectors.yaml");
|
||||||
|
|
||||||
|
File::open(file_path_buf).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut yaml_str = String::new();
|
let mut yaml_str = String::new();
|
||||||
|
|
||||||
file.read_to_string(&mut yaml_str).unwrap();
|
file.read_to_string(&mut yaml_str).unwrap();
|
||||||
|
|
||||||
let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
|
let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
|
||||||
let doc = &docs[0];
|
let doc = &docs[0];
|
||||||
let test_cases = doc["test_cases"].as_vec();
|
let test_cases = doc["test_cases"].as_vec().unwrap();
|
||||||
|
|
||||||
for test_case in test_cases.unwrap() {
|
for test_case in test_cases {
|
||||||
let input = test_case["input"].clone().into_vec().unwrap();
|
let input = test_case["input"].clone().into_vec().unwrap();
|
||||||
let output = test_case["output"].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_bytes = test_case["seed"].as_str().unwrap().as_bytes();
|
||||||
let mut seed;
|
|
||||||
|
|
||||||
if seed_bytes.len() > 0 {
|
let seed = if seed_bytes.len() > 0 {
|
||||||
seed = canonical_hash(seed_bytes);
|
canonical_hash(seed_bytes)
|
||||||
} else {
|
} else {
|
||||||
seed = vec![];
|
vec![]
|
||||||
}
|
};
|
||||||
|
|
||||||
let mut s = shuffle(&seed, input).unwrap();
|
assert_eq!(shuffle(&seed, input).unwrap(), output);
|
||||||
|
|
||||||
assert_eq!(s, output);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# This file was generated with sigp/shuffling_sandbox
|
|
||||||
# python3 sandbox.py test_vectors
|
|
||||||
title: Shuffling Algorithm Tests
|
title: Shuffling Algorithm Tests
|
||||||
summary: Test vectors for shuffling a list based upon a seed.
|
summary: Test vectors for shuffling a list based upon a seed.
|
||||||
test_suite: Shuffling
|
test_suite: Shuffling
|
||||||
@ -15,13 +13,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: ''
|
seed: ''
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [1, 6, 4, 1, 6, 6, 2, 2, 4, 5]
|
output: [2, 1, 1, 5, 6, 6, 6, 2, 4, 4]
|
||||||
seed: ''
|
seed: ''
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [4, 7, 10, 13, 3, 1, 2, 9, 12, 6, 11, 8, 5]
|
output: [4, 9, 6, 8, 13, 3, 2, 11, 5, 1, 12, 7, 10]
|
||||||
seed: ''
|
seed: ''
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [1, 6, 65, 1, 6, 6, 2, 2, 4, 5]
|
output: [2, 1, 1, 5, 6, 6, 6, 2, 4, 65]
|
||||||
seed: ''
|
seed: ''
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -33,13 +31,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: 4kn4driuctg8
|
seed: 4kn4driuctg8
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 4, 2, 5, 4, 2, 6, 6, 1, 1]
|
output: [2, 4, 4, 2, 1, 1, 6, 5, 6, 6]
|
||||||
seed: 4kn4driuctg8
|
seed: 4kn4driuctg8
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [13, 1, 9, 8, 3, 10, 6, 2, 5, 12, 11, 4, 7]
|
output: [7, 6, 3, 12, 11, 1, 8, 13, 10, 5, 9, 4, 2]
|
||||||
seed: 4kn4driuctg8
|
seed: 4kn4driuctg8
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 65, 2, 5, 4, 2, 6, 6, 1, 1]
|
output: [2, 4, 65, 2, 1, 1, 6, 5, 6, 6]
|
||||||
seed: 4kn4driuctg8
|
seed: 4kn4driuctg8
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -51,13 +49,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: ytre1p
|
seed: ytre1p
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 5, 1, 6, 4, 1, 2, 4, 6]
|
output: [6, 1, 1, 5, 6, 2, 6, 2, 4, 4]
|
||||||
seed: ytre1p
|
seed: ytre1p
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [3, 8, 10, 4, 7, 11, 6, 1, 2, 5, 13, 9, 12]
|
output: [6, 2, 3, 4, 8, 5, 12, 9, 7, 11, 10, 1, 13]
|
||||||
seed: ytre1p
|
seed: ytre1p
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 5, 1, 6, 4, 1, 2, 65, 6]
|
output: [6, 1, 1, 5, 6, 2, 6, 2, 4, 65]
|
||||||
seed: ytre1p
|
seed: ytre1p
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -69,13 +67,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: mytobcffnkvj
|
seed: mytobcffnkvj
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [5, 6, 2, 1, 6, 4, 6, 4, 1, 2]
|
output: [2, 4, 1, 1, 6, 4, 6, 5, 6, 2]
|
||||||
seed: mytobcffnkvj
|
seed: mytobcffnkvj
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [12, 4, 11, 6, 13, 10, 9, 2, 3, 7, 8, 1, 5]
|
output: [11, 5, 9, 7, 2, 4, 12, 10, 8, 1, 6, 3, 13]
|
||||||
seed: mytobcffnkvj
|
seed: mytobcffnkvj
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [5, 6, 2, 1, 6, 65, 6, 4, 1, 2]
|
output: [2, 65, 1, 1, 6, 4, 6, 5, 6, 2]
|
||||||
seed: mytobcffnkvj
|
seed: mytobcffnkvj
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -87,13 +85,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: myzu3g7evxp5nkvj
|
seed: myzu3g7evxp5nkvj
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 6, 5, 4, 4, 1, 6, 2, 1]
|
output: [6, 2, 1, 4, 2, 6, 5, 6, 4, 1]
|
||||||
seed: myzu3g7evxp5nkvj
|
seed: myzu3g7evxp5nkvj
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [10, 12, 13, 3, 7, 11, 2, 4, 9, 8, 6, 5, 1]
|
output: [2, 1, 11, 3, 9, 7, 8, 13, 4, 10, 5, 6, 12]
|
||||||
seed: myzu3g7evxp5nkvj
|
seed: myzu3g7evxp5nkvj
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 6, 5, 65, 4, 1, 6, 2, 1]
|
output: [6, 2, 1, 4, 2, 6, 5, 6, 65, 1]
|
||||||
seed: myzu3g7evxp5nkvj
|
seed: myzu3g7evxp5nkvj
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -105,13 +103,13 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: xdpli1jsx5xb
|
seed: xdpli1jsx5xb
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 4, 1, 2, 6, 5, 1, 6, 4]
|
output: [2, 1, 2, 4, 6, 6, 5, 6, 1, 4]
|
||||||
seed: xdpli1jsx5xb
|
seed: xdpli1jsx5xb
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [11, 8, 12, 9, 2, 1, 10, 4, 13, 5, 7, 3, 6]
|
output: [5, 8, 12, 9, 11, 4, 7, 13, 1, 3, 2, 10, 6]
|
||||||
seed: xdpli1jsx5xb
|
seed: xdpli1jsx5xb
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [6, 2, 65, 1, 2, 6, 5, 1, 6, 4]
|
output: [2, 1, 2, 65, 6, 6, 5, 6, 1, 4]
|
||||||
seed: xdpli1jsx5xb
|
seed: xdpli1jsx5xb
|
||||||
- input: []
|
- input: []
|
||||||
output: []
|
output: []
|
||||||
@ -123,11 +121,11 @@ test_cases:
|
|||||||
output: [255]
|
output: [255]
|
||||||
seed: oab3mbb3xe8qsx5xb
|
seed: oab3mbb3xe8qsx5xb
|
||||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [2, 5, 1, 6, 1, 2, 6, 6, 4, 4]
|
output: [6, 2, 1, 1, 6, 2, 4, 4, 6, 5]
|
||||||
seed: oab3mbb3xe8qsx5xb
|
seed: oab3mbb3xe8qsx5xb
|
||||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
output: [5, 13, 9, 7, 11, 10, 12, 2, 6, 8, 3, 1, 4]
|
output: [1, 8, 5, 13, 2, 10, 7, 11, 12, 6, 3, 4, 9]
|
||||||
seed: oab3mbb3xe8qsx5xb
|
seed: oab3mbb3xe8qsx5xb
|
||||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||||
output: [2, 5, 1, 6, 1, 2, 6, 6, 65, 4]
|
output: [6, 2, 1, 1, 6, 2, 4, 65, 6, 5]
|
||||||
seed: oab3mbb3xe8qsx5xb
|
seed: oab3mbb3xe8qsx5xb
|
||||||
|
@ -8,3 +8,4 @@ edition = "2018"
|
|||||||
bls = { path = "../utils/bls" }
|
bls = { path = "../utils/bls" }
|
||||||
hashing = { path = "../utils/hashing" }
|
hashing = { path = "../utils/hashing" }
|
||||||
types = { path = "../types" }
|
types = { path = "../types" }
|
||||||
|
spec = { path = "../spec" }
|
||||||
|
@ -1,278 +1,206 @@
|
|||||||
use bls::verify_proof_of_possession;
|
use bls::{verify_proof_of_possession};
|
||||||
use types::{ValidatorRecord, ValidatorRegistration, ValidatorStatus};
|
use types::{BeaconState, Deposit, ValidatorRecord, ValidatorStatus};
|
||||||
|
use spec::ChainSpec;
|
||||||
/// The size of a validators deposit in GWei.
|
|
||||||
pub const DEPOSIT_GWEI: u64 = 32_000_000_000;
|
|
||||||
|
|
||||||
/// Inducts validators into a `CrystallizedState`.
|
|
||||||
pub struct ValidatorInductor {
|
|
||||||
pub current_slot: u64,
|
|
||||||
pub shard_count: u64,
|
|
||||||
validators: Vec<ValidatorRecord>,
|
|
||||||
empty_validator_start: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ValidatorInductionError {
|
pub enum ValidatorInductionError {
|
||||||
InvalidShard,
|
InvalidShard,
|
||||||
InvaidProofOfPossession,
|
InvaidProofOfPossession,
|
||||||
|
InvalidWithdrawalCredentials
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatorInductor {
|
pub fn process_deposit(
|
||||||
pub fn new(current_slot: u64, shard_count: u64, validators: Vec<ValidatorRecord>) -> Self {
|
state: &mut BeaconState,
|
||||||
Self {
|
deposit: &Deposit,
|
||||||
current_slot,
|
spec: &ChainSpec)
|
||||||
shard_count,
|
-> Result<usize, ValidatorInductionError> {
|
||||||
validators,
|
let deposit_input = &deposit.deposit_data.deposit_input;
|
||||||
empty_validator_start: 0,
|
let deposit_data = &deposit.deposit_data;
|
||||||
}
|
|
||||||
|
// TODO: Update the signature validation as defined in the spec once issues #91 and #70 are completed
|
||||||
|
if !verify_proof_of_possession(&deposit_input.proof_of_possession, &deposit_input.pubkey) {
|
||||||
|
return Err(ValidatorInductionError::InvaidProofOfPossession);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to induct a validator into the CrystallizedState.
|
let validator_index = state.validator_registry.iter()
|
||||||
///
|
.position(|validator| validator.pubkey == deposit_input.pubkey);
|
||||||
/// Returns an error if the registration is invalid, otherwise returns the index of the
|
|
||||||
/// validator in `CrystallizedState.validators`.
|
|
||||||
pub fn induct(
|
|
||||||
&mut self,
|
|
||||||
rego: &ValidatorRegistration,
|
|
||||||
status: ValidatorStatus,
|
|
||||||
) -> Result<usize, ValidatorInductionError> {
|
|
||||||
let v = self.process_registration(rego, status)?;
|
|
||||||
Ok(self.add_validator(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify a `ValidatorRegistration` and return a `ValidatorRecord` if valid.
|
match validator_index {
|
||||||
fn process_registration(
|
Some(i) => {
|
||||||
&self,
|
if state.validator_registry[i].withdrawal_credentials == deposit_input.withdrawal_credentials {
|
||||||
r: &ValidatorRegistration,
|
state.validator_balances[i] += deposit_data.value;
|
||||||
status: ValidatorStatus,
|
return Ok(i);
|
||||||
) -> Result<ValidatorRecord, ValidatorInductionError> {
|
|
||||||
/*
|
|
||||||
* Ensure withdrawal shard is not too high.
|
|
||||||
*/
|
|
||||||
if r.withdrawal_shard > self.shard_count {
|
|
||||||
return Err(ValidatorInductionError::InvalidShard);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prove validator has knowledge of their secret key.
|
|
||||||
*/
|
|
||||||
if !verify_proof_of_possession(&r.proof_of_possession, &r.pubkey) {
|
|
||||||
return Err(ValidatorInductionError::InvaidProofOfPossession);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ValidatorRecord {
|
|
||||||
pubkey: r.pubkey.clone(),
|
|
||||||
withdrawal_shard: r.withdrawal_shard,
|
|
||||||
withdrawal_address: r.withdrawal_address,
|
|
||||||
randao_commitment: r.randao_commitment,
|
|
||||||
randao_last_change: self.current_slot,
|
|
||||||
balance: DEPOSIT_GWEI,
|
|
||||||
status: status,
|
|
||||||
exit_slot: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of the first `ValidatorRecord` in the `CrystallizedState` where
|
|
||||||
/// `validator.status == Withdrawn`. If no such record exists, `None` is returned.
|
|
||||||
fn first_withdrawn_validator(&mut self) -> Option<usize> {
|
|
||||||
for i in self.empty_validator_start..self.validators.len() {
|
|
||||||
if self.validators[i].status == ValidatorStatus::Withdrawn {
|
|
||||||
self.empty_validator_start = i + 1;
|
|
||||||
return Some(i);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a `ValidatorRecord` to the `CrystallizedState` by replacing first validator where
|
Err(ValidatorInductionError::InvalidWithdrawalCredentials)
|
||||||
/// `validator.status == Withdraw`. If no such withdrawn validator exists, adds the new
|
},
|
||||||
/// validator to the end of the list.
|
None => {
|
||||||
fn add_validator(&mut self, v: ValidatorRecord) -> usize {
|
let validator = ValidatorRecord {
|
||||||
match self.first_withdrawn_validator() {
|
pubkey: deposit_input.pubkey.clone(),
|
||||||
Some(i) => {
|
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
||||||
self.validators[i] = v;
|
randao_commitment: deposit_input.randao_commitment,
|
||||||
i
|
randao_layers: 0,
|
||||||
}
|
status: ValidatorStatus::PendingActivation,
|
||||||
None => {
|
latest_status_change_slot: state.validator_registry_latest_change_slot,
|
||||||
self.validators.push(v);
|
exit_count: 0,
|
||||||
self.validators.len() - 1
|
custody_commitment: deposit_input.custody_commitment,
|
||||||
|
latest_custody_reseed_slot: 0,
|
||||||
|
penultimate_custody_reseed_slot: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
match min_empty_validator_index(state, spec) {
|
||||||
|
Some(i) => {
|
||||||
|
state.validator_registry[i] = validator;
|
||||||
|
state.validator_balances[i] = deposit_data.value;
|
||||||
|
Ok(i)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
state.validator_registry.push(validator);
|
||||||
|
state.validator_balances.push(deposit_data.value);
|
||||||
|
Ok(state.validator_registry.len() - 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_vec(self) -> Vec<ValidatorRecord> {
|
fn min_empty_validator_index(
|
||||||
self.validators
|
state: &BeaconState,
|
||||||
|
spec: &ChainSpec
|
||||||
|
) -> Option<usize> {
|
||||||
|
for i in 0..state.validator_registry.len() {
|
||||||
|
if state.validator_balances[i] == 0
|
||||||
|
&& state.validator_registry[i].latest_status_change_slot
|
||||||
|
+ spec.zero_balance_validator_ttl <= state.slot {
|
||||||
|
return Some(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||||
|
|
||||||
use bls::{create_proof_of_possession, Keypair};
|
use bls::{create_proof_of_possession, Keypair};
|
||||||
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
|
||||||
use types::{Address, Hash256};
|
|
||||||
|
|
||||||
fn registration_equals_record(reg: &ValidatorRegistration, rec: &ValidatorRecord) -> bool {
|
/// The size of a validators deposit in GWei.
|
||||||
(reg.pubkey == rec.pubkey)
|
pub const DEPOSIT_GWEI: u64 = 32_000_000_000;
|
||||||
& (reg.withdrawal_shard == rec.withdrawal_shard)
|
|
||||||
& (reg.withdrawal_address == rec.withdrawal_address)
|
fn get_deposit() -> Deposit {
|
||||||
& (reg.randao_commitment == rec.randao_commitment)
|
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||||
& (verify_proof_of_possession(®.proof_of_possession, &rec.pubkey))
|
let mut deposit = Deposit::random_for_test(&mut rng);
|
||||||
|
|
||||||
|
let kp = Keypair::random();
|
||||||
|
deposit.deposit_data.deposit_input.pubkey = kp.pk.clone();
|
||||||
|
deposit.deposit_data.deposit_input.proof_of_possession = create_proof_of_possession(&kp);
|
||||||
|
deposit
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a basic working ValidatorRegistration for use in tests.
|
fn get_validator() -> ValidatorRecord {
|
||||||
fn get_registration() -> ValidatorRegistration {
|
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||||
let kp = Keypair::random();
|
ValidatorRecord::random_for_test(&mut rng)
|
||||||
ValidatorRegistration {
|
}
|
||||||
pubkey: kp.pk.clone(),
|
|
||||||
withdrawal_shard: 0,
|
fn deposit_equals_record(dep: &Deposit, val: &ValidatorRecord) -> bool {
|
||||||
withdrawal_address: Address::zero(),
|
(dep.deposit_data.deposit_input.pubkey == val.pubkey)
|
||||||
randao_commitment: Hash256::zero(),
|
& (dep.deposit_data.deposit_input.withdrawal_credentials == val.withdrawal_credentials)
|
||||||
proof_of_possession: create_proof_of_possession(&kp),
|
& (dep.deposit_data.deposit_input.randao_commitment == val.randao_commitment)
|
||||||
}
|
& (verify_proof_of_possession(&dep.deposit_data.deposit_input.proof_of_possession, &val.pubkey))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validator_inductor_valid_empty_validators() {
|
fn test_process_deposit_valid_empty_validators() {
|
||||||
let validators = vec![];
|
let mut state = BeaconState::default();
|
||||||
|
let mut deposit = get_deposit();
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
deposit.deposit_data.value = DEPOSIT_GWEI;
|
||||||
|
|
||||||
let r = get_registration();
|
let result = process_deposit(&mut state, &deposit, &spec);
|
||||||
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
|
||||||
let validators = inductor.to_vec();
|
|
||||||
|
|
||||||
assert_eq!(result.unwrap(), 0);
|
assert_eq!(result.unwrap(), 0);
|
||||||
assert!(registration_equals_record(&r, &validators[0]));
|
assert!(deposit_equals_record(&deposit, &state.validator_registry[0]));
|
||||||
assert_eq!(validators.len(), 1);
|
assert_eq!(state.validator_registry.len(), 1);
|
||||||
|
assert_eq!(state.validator_balances.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validator_inductor_status() {
|
fn test_process_deposits_empty_validators() {
|
||||||
let validators = vec![];
|
let mut state = BeaconState::default();
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
|
||||||
let r = get_registration();
|
for i in 0..5 {
|
||||||
|
let mut deposit = get_deposit();
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
let result = process_deposit(&mut state, &deposit, &spec);
|
||||||
let _ = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
deposit.deposit_data.value = DEPOSIT_GWEI;
|
||||||
let _ = inductor.induct(&r, ValidatorStatus::Active);
|
assert_eq!(result.unwrap(), i);
|
||||||
let validators = inductor.to_vec();
|
assert!(deposit_equals_record(&deposit, &state.validator_registry[i]));
|
||||||
|
assert_eq!(state.validator_registry.len(), i + 1);
|
||||||
assert!(validators[0].status == ValidatorStatus::PendingActivation);
|
assert_eq!(state.validator_balances.len(), i + 1);
|
||||||
assert!(validators[1].status == ValidatorStatus::Active);
|
|
||||||
assert_eq!(validators.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_validator_inductor_valid_all_active_validators() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
let mut validators = vec![];
|
|
||||||
for _ in 0..5 {
|
|
||||||
let mut v = ValidatorRecord::random_for_test(&mut rng);
|
|
||||||
v.status = ValidatorStatus::Active;
|
|
||||||
validators.push(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let r = get_registration();
|
|
||||||
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
|
||||||
let validators = inductor.to_vec();
|
|
||||||
|
|
||||||
assert_eq!(result.unwrap(), 5);
|
|
||||||
assert!(registration_equals_record(&r, &validators[5]));
|
|
||||||
assert_eq!(validators.len(), 6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validator_inductor_valid_all_second_validator_withdrawn() {
|
fn test_process_deposit_top_out() {
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
let mut state = BeaconState::default();
|
||||||
let mut validators = vec![];
|
let spec = ChainSpec::foundation();
|
||||||
let mut v = ValidatorRecord::random_for_test(&mut rng);
|
|
||||||
v.status = ValidatorStatus::Active;
|
|
||||||
validators.push(v);
|
|
||||||
for _ in 0..4 {
|
|
||||||
let mut v = ValidatorRecord::random_for_test(&mut rng);
|
|
||||||
v.status = ValidatorStatus::Withdrawn;
|
|
||||||
validators.push(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = get_registration();
|
let mut deposit = get_deposit();
|
||||||
|
let mut validator = get_validator();
|
||||||
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
deposit.deposit_data.value = DEPOSIT_GWEI;
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
validator.pubkey = deposit.deposit_data.deposit_input.pubkey.clone();
|
||||||
let validators = inductor.to_vec();
|
validator.withdrawal_credentials = deposit.deposit_data.deposit_input.withdrawal_credentials;
|
||||||
|
validator.randao_commitment = deposit.deposit_data.deposit_input.randao_commitment;
|
||||||
|
|
||||||
assert_eq!(result.unwrap(), 1);
|
state.validator_registry.push(validator);
|
||||||
assert!(registration_equals_record(&r, &validators[1]));
|
state.validator_balances.push(DEPOSIT_GWEI);
|
||||||
assert_eq!(validators.len(), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
let result = process_deposit(&mut state, &deposit, &spec);
|
||||||
fn test_validator_inductor_valid_all_withdrawn_validators() {
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
|
||||||
let mut validators = vec![];
|
|
||||||
for _ in 0..5 {
|
|
||||||
let mut v = ValidatorRecord::random_for_test(&mut rng);
|
|
||||||
v.status = ValidatorStatus::Withdrawn;
|
|
||||||
validators.push(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure the first validator gets the 0'th slot
|
|
||||||
*/
|
|
||||||
let r = get_registration();
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
|
||||||
let validators = inductor.to_vec();
|
|
||||||
assert_eq!(result.unwrap(), 0);
|
assert_eq!(result.unwrap(), 0);
|
||||||
assert!(registration_equals_record(&r, &validators[0]));
|
assert!(deposit_equals_record(&deposit, &state.validator_registry[0]));
|
||||||
|
assert_eq!(state.validator_balances[0], DEPOSIT_GWEI * 2);
|
||||||
/*
|
assert_eq!(state.validator_registry.len(), 1);
|
||||||
* Ensure the second validator gets the 1'st slot
|
assert_eq!(state.validator_balances.len(), 1);
|
||||||
*/
|
|
||||||
let r_two = get_registration();
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
|
||||||
let result = inductor.induct(&r_two, ValidatorStatus::PendingActivation);
|
|
||||||
let validators = inductor.to_vec();
|
|
||||||
assert_eq!(result.unwrap(), 1);
|
|
||||||
assert!(registration_equals_record(&r_two, &validators[1]));
|
|
||||||
assert_eq!(validators.len(), 5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validator_inductor_shard_too_high() {
|
fn test_process_deposit_replace_validator() {
|
||||||
let validators = vec![];
|
let mut state = BeaconState::default();
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
|
||||||
let mut r = get_registration();
|
let mut validator = get_validator();
|
||||||
r.withdrawal_shard = 1025;
|
validator.latest_status_change_slot = 0;
|
||||||
|
state.validator_registry.push(validator);
|
||||||
|
state.validator_balances.push(0);
|
||||||
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
let mut deposit = get_deposit();
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
deposit.deposit_data.value = DEPOSIT_GWEI;
|
||||||
let validators = inductor.to_vec();
|
state.slot = spec.zero_balance_validator_ttl;
|
||||||
|
|
||||||
assert_eq!(result, Err(ValidatorInductionError::InvalidShard));
|
let result = process_deposit(&mut state, &deposit, &spec);
|
||||||
assert_eq!(validators.len(), 0);
|
|
||||||
|
assert_eq!(result.unwrap(), 0);
|
||||||
|
assert!(deposit_equals_record(&deposit, &state.validator_registry[0]));
|
||||||
|
assert_eq!(state.validator_balances[0], DEPOSIT_GWEI);
|
||||||
|
assert_eq!(state.validator_registry.len(), 1);
|
||||||
|
assert_eq!(state.validator_balances.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validator_inductor_shard_proof_of_possession_failure() {
|
fn test_process_deposit_invalid_proof_of_possession() {
|
||||||
let validators = vec![];
|
let mut state = BeaconState::default();
|
||||||
|
let mut deposit = get_deposit();
|
||||||
|
let spec = ChainSpec::foundation();
|
||||||
|
deposit.deposit_data.value = DEPOSIT_GWEI;
|
||||||
|
deposit.deposit_data.deposit_input.proof_of_possession = create_proof_of_possession(&Keypair::random());
|
||||||
|
|
||||||
let mut r = get_registration();
|
let result = process_deposit(&mut state, &deposit, &spec);
|
||||||
let kp = Keypair::random();
|
|
||||||
r.proof_of_possession = create_proof_of_possession(&kp);
|
|
||||||
|
|
||||||
let mut inductor = ValidatorInductor::new(0, 1024, validators);
|
assert_eq!(result, Err(ValidatorInductionError::InvaidProofOfPossession));
|
||||||
let result = inductor.induct(&r, ValidatorStatus::PendingActivation);
|
assert_eq!(state.validator_registry.len(), 0);
|
||||||
let validators = inductor.to_vec();
|
assert_eq!(state.validator_balances.len(), 0);
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
result,
|
|
||||||
Err(ValidatorInductionError::InvaidProofOfPossession)
|
|
||||||
);
|
|
||||||
assert_eq!(validators.len(), 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
extern crate bls;
|
extern crate bls;
|
||||||
extern crate hashing;
|
extern crate hashing;
|
||||||
extern crate types;
|
extern crate types;
|
||||||
|
extern crate spec;
|
||||||
|
|
||||||
mod inductor;
|
mod inductor;
|
||||||
|
|
||||||
pub use crate::inductor::{ValidatorInductionError, ValidatorInductor};
|
pub use crate::inductor::{ValidatorInductionError, process_deposit};
|
||||||
|
Loading…
Reference in New Issue
Block a user