Update block processing to v0.5.0

This commit is contained in:
Paul Hauner
2019-03-17 12:25:37 +11:00
parent 7f4af20212
commit 6bd2055a0a
13 changed files with 413 additions and 336 deletions

View File

@@ -2,11 +2,11 @@ use self::epoch_cache::EpochCache;
use crate::test_utils::TestRandom;
use crate::{validator_registry::get_active_validator_indices, *};
use int_to_bytes::int_to_bytes32;
use log::{debug, trace};
use log::trace;
use pubkey_cache::PubkeyCache;
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz::{hash, SignedRoot, TreeHash};
use ssz::{hash, ssz_encode, SignedRoot, TreeHash};
use ssz_derive::{Decode, Encode, TreeHash};
use std::collections::HashMap;
use test_random_derive::TestRandom;
@@ -31,12 +31,14 @@ pub enum Error {
UnableToShuffle,
UnknownValidator,
InvalidBitfield,
ValidatorIsWithdrawable,
InsufficientRandaoMixes,
InsufficientValidators,
InsufficientBlockRoots,
InsufficientIndexRoots,
InsufficientAttestations,
InsufficientCommittees,
InsufficientSlashedBalances,
EpochCacheUninitialized(RelativeEpoch),
PubkeyCacheInconsistent,
PubkeyCacheIncomplete {
@@ -377,10 +379,37 @@ impl BeaconState {
}
}
/// XOR-assigns the existing `epoch` randao mix with the hash of the `signature`.
///
/// # Errors:
///
/// See `Self::get_randao_mix`.
///
/// Spec v0.5.0
pub fn update_randao_mix(
&mut self,
epoch: Epoch,
signature: &Signature,
spec: &ChainSpec,
) -> Result<(), Error> {
let i = epoch.as_usize() % spec.latest_randao_mixes_length;
let signature_hash = Hash256::from_slice(&hash(&ssz_encode(signature)));
self.latest_randao_mixes[i] = *self.get_randao_mix(epoch, spec)? ^ signature_hash;
Ok(())
}
/// Return the randao mix at a recent ``epoch``.
///
/// Spec v0.4.0
pub fn get_randao_mix(&self, epoch: Epoch, spec: &ChainSpec) -> Option<&Hash256> {
/// # Errors:
/// - `InsufficientRandaoMixes` if `self.latest_randao_mixes` is shorter than
/// `spec.latest_randao_mixes_length`.
/// - `EpochOutOfBounds` if the state no longer stores randao mixes for the given `epoch`.
///
/// Spec v0.5.0
pub fn get_randao_mix(&self, epoch: Epoch, spec: &ChainSpec) -> Result<&Hash256, Error> {
let current_epoch = self.current_epoch(spec);
if (current_epoch - (spec.latest_randao_mixes_length as u64) < epoch)
@@ -388,8 +417,9 @@ impl BeaconState {
{
self.latest_randao_mixes
.get(epoch.as_usize() % spec.latest_randao_mixes_length)
.ok_or_else(|| Error::InsufficientRandaoMixes)
} else {
None
Err(Error::EpochOutOfBounds)
}
}
@@ -418,8 +448,7 @@ impl BeaconState {
/// Spec v0.4.0
pub fn generate_seed(&self, epoch: Epoch, spec: &ChainSpec) -> Result<Hash256, Error> {
let mut input = self
.get_randao_mix(epoch - spec.min_seed_lookahead, spec)
.ok_or_else(|| Error::InsufficientRandaoMixes)?
.get_randao_mix(epoch - spec.min_seed_lookahead, spec)?
.as_bytes()
.to_vec();
@@ -601,7 +630,7 @@ impl BeaconState {
/// Initiate an exit for the validator of the given `index`.
///
/// Spec v0.4.0
/// Spec v0.5.0
pub fn initiate_validator_exit(&mut self, validator_index: usize) {
self.validator_registry[validator_index].initiated_exit = true;
}
@@ -622,7 +651,7 @@ impl BeaconState {
/// Slash the validator with index ``index``.
///
/// Spec v0.4.0
/// Spec v0.5.0
pub fn slash_validator(
&mut self,
validator_index: usize,
@@ -634,26 +663,27 @@ impl BeaconState {
.validator_registry
.get(validator_index)
.ok_or_else(|| Error::UnknownValidator)?;
let effective_balance = self.get_effective_balance(validator_index, spec)?;
// A validator that is withdrawn cannot be slashed.
//
// This constraint will be lifted in Phase 0.
if self.slot
>= validator
.withdrawable_epoch
.start_slot(spec.slots_per_epoch)
{
return Err(Error::SlotOutOfBounds);
return Err(Error::ValidatorIsWithdrawable);
}
self.exit_validator(validator_index, spec);
let effective_balance = self.get_effective_balance(validator_index, spec)?;
self.latest_slashed_balances[current_epoch.as_usize() % spec.latest_slashed_exit_length] +=
effective_balance;
self.increment_current_epoch_slashed_balances(effective_balance, spec)?;
let whistleblower_index =
self.get_beacon_proposer_index(self.slot, RelativeEpoch::Current, spec)?;
let whistleblower_reward = effective_balance / spec.whistleblower_reward_quotient;
let whistleblower_reward = effective_balance;
safe_add_assign!(
self.validator_balances[whistleblower_index as usize],
whistleblower_reward
@@ -662,14 +692,31 @@ impl BeaconState {
self.validator_balances[validator_index],
whistleblower_reward
);
self.validator_registry[validator_index].slashed = true;
self.validator_registry[validator_index].withdrawable_epoch =
current_epoch + Epoch::from(spec.latest_slashed_exit_length);
debug!(
"Whistleblower {} penalized validator {}.",
whistleblower_index, validator_index
);
Ok(())
}
/// Increment `self.latest_slashed_balances` with a slashing from the current epoch.
///
/// Spec v0.5.0.
fn increment_current_epoch_slashed_balances(
&mut self,
increment: u64,
spec: &ChainSpec,
) -> Result<(), Error> {
let current_epoch = self.current_epoch(spec);
let slashed_balances_index = current_epoch.as_usize() % spec.latest_slashed_exit_length;
if slashed_balances_index >= self.latest_slashed_balances.len() {
return Err(Error::InsufficientSlashedBalances);
}
self.latest_slashed_balances[slashed_balances_index] += increment;
Ok(())
}

View File

@@ -29,7 +29,7 @@ pub struct ChainSpec {
pub shard_count: u64,
pub target_committee_size: u64,
pub max_balance_churn_quotient: u64,
pub max_indices_per_slashable_vote: u64,
pub max_indices_per_slashable_vote: usize,
pub max_exit_dequeues_per_epoch: u64,
pub shuffle_round_count: u8,

View File

@@ -11,8 +11,8 @@ use test_random_derive::TestRandom;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct ProposerSlashing {
pub proposer_index: u64,
pub proposal_1: BeaconBlockHeader,
pub proposal_2: BeaconBlockHeader,
pub header_1: BeaconBlockHeader,
pub header_2: BeaconBlockHeader,
}
#[cfg(test)]

View File

@@ -25,7 +25,7 @@ impl TestingProposerSlashingBuilder {
let hash_1 = Hash256::from([1; 32]);
let hash_2 = Hash256::from([2; 32]);
let mut proposal_1 = BeaconBlockHeader {
let mut header_1 = BeaconBlockHeader {
slot,
previous_block_root: hash_1,
state_root: hash_1,
@@ -33,27 +33,27 @@ impl TestingProposerSlashingBuilder {
signature: Signature::empty_signature(),
};
let mut proposal_2 = BeaconBlockHeader {
let mut header_2 = BeaconBlockHeader {
previous_block_root: hash_2,
..proposal_1.clone()
..header_1.clone()
};
proposal_1.signature = {
let message = proposal_1.signed_root();
header_1.signature = {
let message = header_1.signed_root();
let epoch = slot.epoch(spec.slots_per_epoch);
signer(proposer_index, &message[..], epoch, Domain::BeaconBlock)
};
proposal_2.signature = {
let message = proposal_2.signed_root();
header_2.signature = {
let message = header_2.signed_root();
let epoch = slot.epoch(spec.slots_per_epoch);
signer(proposer_index, &message[..], epoch, Domain::BeaconBlock)
};
ProposerSlashing {
proposer_index,
proposal_1,
proposal_2,
header_1,
header_2,
}
}
}