types updated against spec and process_deposit routine partially implemented
This commit is contained in:
parent
e93eb55dcd
commit
faaba18799
@ -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,
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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" }
|
||||||
|
@ -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 {
|
||||||
|
// replace withdrawn validator
|
||||||
|
Some(i) => {
|
||||||
|
if state.validator_registry[i].withdrawal_credentials == deposit_input.withdrawal_credentials {
|
||||||
|
state.validator_balances[i] += DEPOSIT_GWEI;
|
||||||
|
return Ok(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to induct a validator into the CrystallizedState.
|
Err(ValidatorInductionError::InvalidWithdrawalCredentials)
|
||||||
///
|
},
|
||||||
/// Returns an error if the registration is invalid, otherwise returns the index of the
|
// no withdrawn validators; push a new one on
|
||||||
/// validator in `CrystallizedState.validators`.
|
None => {
|
||||||
pub fn induct(
|
let validator = ValidatorRecord {
|
||||||
&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(),
|
pubkey: deposit_input.pubkey.clone(),
|
||||||
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
||||||
randao_commitment: deposit_input.randao_commitment,
|
randao_commitment: deposit_input.randao_commitment,
|
||||||
randao_layers: 0,
|
randao_layers: 0,
|
||||||
balance: DEPOSIT_GWEI,
|
status: ValidatorStatus::PendingActivation,
|
||||||
status: status,
|
latest_status_change_slot: state.validator_registry_latest_change_slot.clone(),
|
||||||
latest_status_change_slot: self.beacon_state.validator_registry_latest_change_slot,
|
|
||||||
exit_count: 0
|
exit_count: 0
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of the first `ValidatorRecord` in the `CrystallizedState` where
|
match min_empty_validator_index(state, spec) {
|
||||||
/// `validator.status == Withdrawn`. If no such record exists, `None` is returned.
|
Some(i) => {
|
||||||
fn first_withdrawn_validator(&mut self) -> Option<usize> {
|
state.validator_registry[i] = validator;
|
||||||
for i in self.empty_validator_start..self.beacon_state.validator_registry.len() {
|
state.validator_balances[i] = DEPOSIT_GWEI;
|
||||||
if self.beacon_state.validator_registry[i].status == ValidatorStatus::Withdrawn {
|
Ok(i)
|
||||||
self.empty_validator_start = i + 1;
|
},
|
||||||
|
None => {
|
||||||
|
state.validator_registry.push(validator);
|
||||||
|
state.validator_balances.push(DEPOSIT_GWEI);
|
||||||
|
Ok(state.validator_registry.len() - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min_empty_validator_index(
|
||||||
|
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);
|
return Some(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a `ValidatorRecord` to the `CrystallizedState` by replacing first validator where
|
|
||||||
/// `validator.status == Withdraw`. If no such withdrawn validator exists, adds the new
|
|
||||||
/// validator to the end of the list.
|
|
||||||
fn add_validator(&mut self, v: ValidatorRecord) -> usize {
|
|
||||||
match self.first_withdrawn_validator() {
|
|
||||||
Some(i) => {
|
|
||||||
self.beacon_state.validator_registry[i] = v;
|
|
||||||
i
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.beacon_state.validator_registry.push(v);
|
|
||||||
self.beacon_state.validator_registry.len() - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_vec(self) -> Vec<ValidatorRecord> {
|
|
||||||
self.beacon_state.validator_registry
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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(®.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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};
|
||||||
|
Loading…
Reference in New Issue
Block a user