Add untested validator change code

This commit is contained in:
Paul Hauner 2018-10-23 23:45:54 +02:00
parent cc28b7370d
commit a170bfe4fc
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
3 changed files with 159 additions and 0 deletions

View File

@ -43,6 +43,7 @@ members = [
"beacon_chain/utils/ssz_helpers",
"beacon_chain/utils/vec_shuffle",
"beacon_chain/validation",
"beacon_chain/validator_change",
"beacon_chain/validator_induction",
"beacon_chain/validator_shuffling",
"lighthouse/db",

View File

@ -0,0 +1,10 @@
[package]
name = "validator_change"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
[dependencies]
active-validators = { path = "../utils/active-validators" }
bytes = "0.4.10"
hashing = { path = "../utils/hashing" }
types = { path = "../types" }

View File

@ -0,0 +1,148 @@
extern crate active_validators;
extern crate bytes;
extern crate hashing;
extern crate types;
use active_validators::validator_is_active;
use bytes::{
BytesMut,
BufMut,
};
use hashing::canonical_hash;
use std::cmp::max;
use types::{
Hash256,
ValidatorRecord,
ValidatorStatus,
};
pub enum UpdateValidatorSetError {
ArithmeticOverflow,
}
const VALIDATOR_FLAG_ENTRY: u8 = 0;
const VALIDATOR_FLAG_EXIT: u8 = 1;
pub fn update_validator_set(
validators: &mut Vec<ValidatorRecord>,
hash_chain: Hash256,
present_slot: u64,
deposit_size_gwei: u64,
max_validator_churn_quotient: u64)
-> Result<(), UpdateValidatorSetError>
{
/*
* Total balance of all active validators.
*
* Return an error if an overflow occurs.
*/
let total_balance = {
let mut bal: u64 = 0;
for v in validators.iter() {
if validator_is_active(&v) {
bal = bal.checked_add(v.balance)
.ok_or(UpdateValidatorSetError::ArithmeticOverflow)?;
}
}
bal
};
/*
* Note: this is not the maximum allowable change, it can actually be higher.
*/
let max_allowable_change = {
let double_deposit_size = deposit_size_gwei.checked_mul(2)
.ok_or(UpdateValidatorSetError::ArithmeticOverflow)?;
max(double_deposit_size, total_balance / max_validator_churn_quotient)
};
let mut hasher = ValidatorChangeHashChain {
bytes: hash_chain.to_vec(),
};
let mut total_changed: u64 = 0;
for (i, v) in validators.iter_mut().enumerate() {
match v.status {
/*
* Validator is pending activiation.
*/
x if x == ValidatorStatus::PendingActivation as u8 => {
let new_total_changed = total_changed.checked_add(deposit_size_gwei)
.ok_or(UpdateValidatorSetError::ArithmeticOverflow)?;
/*
* If entering this validator would not exceed the max balance delta,
* activate the validator.
*/
if new_total_changed <= max_allowable_change {
v.status = ValidatorStatus::Active as u8;
hasher.extend(i, &v.pubkey.as_bytes(), VALIDATOR_FLAG_ENTRY);
total_changed = new_total_changed;
} else {
// Entering the validator would exceed the balance delta.
break;
}
}
/*
* Validator is pending exit.
*/
x if x == ValidatorStatus::PendingExit as u8 => {
let new_total_changed = total_changed.checked_add(v.balance)
.ok_or(UpdateValidatorSetError::ArithmeticOverflow)?;
/*
* If exiting this validator would not exceed the max balance delta,
* exit the validator
*/
if new_total_changed <= max_allowable_change {
v.status = ValidatorStatus::PendingWithdraw as u8;
v.exit_slot = present_slot;
hasher.extend(i, &v.pubkey.as_bytes(), VALIDATOR_FLAG_EXIT);
total_changed = new_total_changed;
} else {
// Exiting the validator would exceed the balance delta.
break;
}
}
_ => ()
};
if total_changed >= max_allowable_change {
break;
}
}
Ok(())
}
pub struct ValidatorChangeHashChain {
bytes: Vec<u8>,
}
impl ValidatorChangeHashChain {
pub fn extend(&mut self, index: usize, pubkey: &Vec<u8>, flag: u8)
{
let mut message = self.bytes.clone();
message.append(&mut serialize_validator_change_record(index, pubkey, flag));
self.bytes = canonical_hash(&message);
}
}
fn serialize_validator_change_record(index: usize, pubkey: &Vec<u8>, flag: u8)
-> Vec<u8>
{
let mut buf = BytesMut::with_capacity(68);
buf.put_u8(flag);
let index_bytes = {
let mut buf = BytesMut::with_capacity(8);
buf.put_u64_be(index as u64);
buf.take()[8 - 3..8].to_vec()
};
buf.put(index_bytes);
buf.put(pubkey);
buf.take().to_vec()
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}