types updated against spec and process_deposit routine partially implemented

This commit is contained in:
Grant Wuerker 2018-12-20 20:22:08 -06:00
parent e93eb55dcd
commit faaba18799
5 changed files with 92 additions and 128 deletions

View File

@ -9,7 +9,11 @@ use super::Hash256;
#[derive(Debug, PartialEq, Default)] #[derive(Debug, PartialEq, Default)]
pub struct BeaconState { pub struct BeaconState {
pub slot: u64,
pub genesis_time: u64,
pub fork_data: ForkData,
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,
@ -20,15 +24,13 @@ pub struct BeaconState {
pub persistent_committee_reassignments: Vec<ShardReassignmentRecord>, pub persistent_committee_reassignments: Vec<ShardReassignmentRecord>,
pub previous_justified_slot: u64, pub previous_justified_slot: u64,
pub justified_slot: u64, pub justified_slot: u64,
pub justified_slot_bitfield: u64, pub justification_bitfield: u64,
pub finalized_slot: u64, pub finalized_slot: u64,
pub latest_crosslinks: Vec<CrosslinkRecord>, pub latest_crosslinks: Vec<CrosslinkRecord>,
pub latest_state_recalculation_slot: u64, pub latest_block_roots: Vec<Hash256>,
pub latest_block_hashes: Vec<Hash256>,
pub latest_penalized_exit_balances: Vec<u64>, pub latest_penalized_exit_balances: Vec<u64>,
pub latest_attestations: Vec<PendingAttestationRecord>, pub latest_attestations: Vec<PendingAttestationRecord>,
pub batched_block_roots: Vec<Hash256>,
pub processed_pow_receipt_root: Hash256, pub processed_pow_receipt_root: Hash256,
pub candidate_pow_receipt_roots: Vec<CandidatePoWReceiptRootRecord>, pub candidate_pow_receipt_roots: Vec<CandidatePoWReceiptRootRecord>,
pub genesis_time: u64,
pub fork_data: ForkData,
} }

View File

@ -32,7 +32,6 @@ pub struct ValidatorRecord {
pub withdrawal_credentials: Hash256, pub withdrawal_credentials: Hash256,
pub randao_commitment: Hash256, pub randao_commitment: Hash256,
pub randao_layers: u64, pub randao_layers: u64,
pub balance: u64,
pub status: ValidatorStatus, pub status: ValidatorStatus,
pub latest_status_change_slot: u64, pub latest_status_change_slot: u64,
pub exit_count: u64 pub exit_count: u64
@ -50,7 +49,6 @@ impl ValidatorRecord {
withdrawal_credentials: Hash256::zero(), withdrawal_credentials: Hash256::zero(),
randao_commitment: Hash256::zero(), randao_commitment: Hash256::zero(),
randao_layers: 0, randao_layers: 0,
balance: 0,
status: From::from(0), status: From::from(0),
latest_status_change_slot: 0, latest_status_change_slot: 0,
exit_count: 0 exit_count: 0

View File

@ -7,3 +7,4 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
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" }

View File

@ -1,111 +1,76 @@
use bls::verify_proof_of_possession; use bls::{PublicKey, verify_proof_of_possession};
use types::{ValidatorRecord, DepositInput, ValidatorStatus, BeaconState}; use types::{BeaconState, Deposit, ValidatorRecord, ValidatorStatus};
use spec::ChainSpec;
/// The size of a validators deposit in GWei. /// The size of a validators deposit in GWei.
pub const DEPOSIT_GWEI: u64 = 32_000_000_000; pub const DEPOSIT_GWEI: u64 = 32_000_000_000;
/// Inducts validators into a `CrystallizedState`.
pub struct ValidatorInductor {
pub current_slot: u64,
pub shard_count: u16,
beacon_state: BeaconState,
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: u16, beacon_state: BeaconState) -> Self { state: &mut BeaconState,
Self { deposit: &Deposit,
current_slot, spec: &ChainSpec)
shard_count, -> Result<usize, ValidatorInductionError> {
beacon_state, let deposit_input = &deposit.deposit_data.deposit_input;
empty_validator_start: 0, let validator_index = state.validator_registry.iter()
} .position(|validator| validator.pubkey == deposit_input.pubkey);
}
match validator_index {
/// Attempt to induct a validator into the CrystallizedState. // replace withdrawn validator
/// Some(i) => {
/// Returns an error if the registration is invalid, otherwise returns the index of the if state.validator_registry[i].withdrawal_credentials == deposit_input.withdrawal_credentials {
/// validator in `CrystallizedState.validators`. state.validator_balances[i] += DEPOSIT_GWEI;
pub fn induct( return Ok(i);
&mut self,
deposit_input: &DepositInput,
status: ValidatorStatus,
) -> Result<usize, ValidatorInductionError> {
let v = self.process_deposit(deposit_input, status)?;
Ok(self.add_validator(v))
}
/// Verify a `ValidatorRegistration` and return a `ValidatorRecord` if valid.
fn process_deposit(
&self,
deposit_input: &DepositInput,
status: ValidatorStatus,
) -> 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(&deposit_input.proof_of_possession, &deposit_input.pubkey) {
return Err(ValidatorInductionError::InvaidProofOfPossession);
}
Ok(ValidatorRecord {
pubkey: deposit_input.pubkey.clone(),
withdrawal_credentials: deposit_input.withdrawal_credentials,
randao_commitment: deposit_input.randao_commitment,
randao_layers: 0,
balance: DEPOSIT_GWEI,
status: status,
latest_status_change_slot: self.beacon_state.validator_registry_latest_change_slot,
exit_count: 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.beacon_state.validator_registry.len() {
if self.beacon_state.validator_registry[i].status == ValidatorStatus::Withdrawn {
self.empty_validator_start = i + 1;
return Some(i);
} }
}
None Err(ValidatorInductionError::InvalidWithdrawalCredentials)
} },
// no withdrawn validators; push a new one on
/// Adds a `ValidatorRecord` to the `CrystallizedState` by replacing first validator where None => {
/// `validator.status == Withdraw`. If no such withdrawn validator exists, adds the new let validator = ValidatorRecord {
/// validator to the end of the list. pubkey: deposit_input.pubkey.clone(),
fn add_validator(&mut self, v: ValidatorRecord) -> usize { withdrawal_credentials: deposit_input.withdrawal_credentials,
match self.first_withdrawn_validator() { randao_commitment: deposit_input.randao_commitment,
Some(i) => { randao_layers: 0,
self.beacon_state.validator_registry[i] = v; status: ValidatorStatus::PendingActivation,
i latest_status_change_slot: state.validator_registry_latest_change_slot.clone(),
} exit_count: 0
None => { };
self.beacon_state.validator_registry.push(v);
self.beacon_state.validator_registry.len() - 1 match min_empty_validator_index(state, spec) {
Some(i) => {
state.validator_registry[i] = validator;
state.validator_balances[i] = DEPOSIT_GWEI;
Ok(i)
},
None => {
state.validator_registry.push(validator);
state.validator_balances.push(DEPOSIT_GWEI);
Ok(state.validator_registry.len() - 1)
}
} }
} }
} }
}
pub fn to_vec(self) -> Vec<ValidatorRecord> { fn min_empty_validator_index(
self.beacon_state.validator_registry 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)]
@ -114,17 +79,27 @@ mod tests {
use bls::{Keypair, Signature}; use bls::{Keypair, Signature};
use hashing::proof_of_possession_hash; use hashing::proof_of_possession_hash;
use types::{Hash256}; use types::{Hash256, DepositData, DepositInput};
/* fn get_deposit() -> Deposit {
fn registration_equals_record(reg: &ValidatorRegistration, rec: &ValidatorRecord) -> bool { let kp = Keypair::random();
(reg.pubkey == rec.pubkey) let deposit_input = DepositInput {
& (reg.withdrawal_shard == rec.withdrawal_shard) pubkey: kp.pk.clone(),
& (reg.withdrawal_address == rec.withdrawal_address) withdrawal_credentials: Hash256::zero(),
& (reg.randao_commitment == rec.randao_commitment) randao_commitment: Hash256::zero(),
& (verify_proof_of_possession(&reg.proof_of_possession, &rec.pubkey)) proof_of_possession: get_proof_of_possession(&kp)
};
let deposit_data = DepositData {
deposit_input: deposit_input,
value: 0,
timestamp: 0
};
Deposit {
merkle_branch: Vec::new(),
merkle_tree_index: 0,
deposit_data: deposit_data
}
} }
*/
/// Generate a proof of possession for some keypair. /// Generate a proof of possession for some keypair.
fn get_proof_of_possession(kp: &Keypair) -> Signature { fn get_proof_of_possession(kp: &Keypair) -> Signature {
@ -132,30 +107,17 @@ mod tests {
Signature::new_hashed(&pop_message, &kp.sk) Signature::new_hashed(&pop_message, &kp.sk)
} }
/// Generate a basic working Deposit for use in tests.
fn get_deposit_input() -> DepositInput {
let kp = Keypair::random();
DepositInput {
pubkey: kp.pk.clone(),
withdrawal_credentials: Hash256::zero(),
randao_commitment: Hash256::zero(),
proof_of_possession: get_proof_of_possession(&kp)
}
}
#[test] #[test]
fn test_validator_inductor_valid_empty_validators() { fn test_validator_inductor_valid_empty_validators() {
let state = BeaconState::default(); let mut state = BeaconState::default();
let deposit = get_deposit();
let spec = ChainSpec::foundation();
let d = get_deposit_input(); let result = process_deposit(&mut state, &deposit, &spec);
let mut inductor = ValidatorInductor::new(0, 1024, state);
let result = inductor.induct(&d, 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!(registration_equals_record(&r, &validators[0]));
assert_eq!(validators.len(), 1); //assert_eq!(validators.len(), 1);
} }
/* /*

View File

@ -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 inductor::{ValidatorInductionError, ValidatorInductor}; pub use inductor::{ValidatorInductionError};