Update to Spec v0.10 (#817)

* Start updating types

* WIP

* Signature hacking

* Existing EF tests passing with fake_crypto

* Updates

* Delete outdated API spec

* The refactor continues

* It compiles

* WIP test fixes

* All release tests passing bar genesis state parsing

* Update and test YamlConfig

* Update to spec v0.10 compatible BLS

* Updates to BLS EF tests

* Add EF test for AggregateVerify

And delete unused hash2curve tests for uncompressed points

* Update EF tests to v0.10.1

* Use optional block root correctly in block proc

* Use genesis fork in deposit domain. All tests pass

* Cargo fmt

* Fast aggregate verify test

* Update REST API docs

* Cargo fmt

* Fix unused import

* Bump spec tags to v0.10.1

* Add `seconds_per_eth1_block` to chainspec

* Update to timestamp based eth1 voting scheme

* Return None from `get_votes_to_consider` if block cache is empty

* Handle overflows in `is_candidate_block`

* Revert to failing tests

* Fix eth1 data sets test

* Choose default vote according to spec

* Fix collect_valid_votes tests

* Fix `get_votes_to_consider` to choose all eligible blocks

* Uncomment winning_vote tests

* Add comments; remove unused code

* Reduce seconds_per_eth1_block for simulation

* Addressed review comments

* Add test for default vote case

* Fix logs

* Remove unused functions

* Meter default eth1 votes

* Fix comments

* Address review comments; remove unused dependency

* Disable/delete two outdated tests

* Bump eth1 default vote warn to error

* Delete outdated eth1 test

Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
Michael Sproul
2020-02-11 10:19:36 +11:00
committed by GitHub
parent 03e77390a3
commit 371e5adcf8
145 changed files with 1666 additions and 4437 deletions

View File

@@ -3,7 +3,7 @@ use types::*;
/// Returns validator indices which participated in the attestation, sorted by increasing index.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_attesting_indices<T: EthSpec>(
state: &BeaconState<T>,
attestation_data: &AttestationData,

View File

@@ -6,7 +6,7 @@ type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
/// Convert `attestation` to (almost) indexed-verifiable form.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation<T>,

View File

@@ -3,7 +3,7 @@ use types::{BeaconStateError as Error, *};
/// Initiate the exit of the validator of the given `index`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn initiate_validator_exit<T: EthSpec>(
state: &mut BeaconState<T>,
index: usize,

View File

@@ -4,7 +4,7 @@ use types::{BeaconStateError as Error, *};
/// Slash the validator with index ``index``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn slash_validator<T: EthSpec>(
state: &mut BeaconState<T>,
slashed_index: usize,

View File

@@ -6,7 +6,7 @@ use types::*;
/// Initialize a `BeaconState` from genesis data.
///
/// Spec v0.9.1
/// Spec v0.10.1
// TODO: this is quite inefficient and we probably want to rethink how we do this
pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
eth1_block_hash: Hash256,
@@ -15,7 +15,7 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
spec: &ChainSpec,
) -> Result<BeaconState<T>, BlockProcessingError> {
let genesis_time =
eth1_timestamp - eth1_timestamp % spec.seconds_per_day + 2 * spec.seconds_per_day;
eth1_timestamp - eth1_timestamp % spec.min_genesis_delay + 2 * spec.min_genesis_delay;
let eth1_data = Eth1Data {
// Temporary deposit root
deposit_root: Hash256::zero(),
@@ -47,7 +47,7 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
/// Determine whether a candidate genesis state is suitable for starting the chain.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSpec) -> bool {
state.genesis_time >= spec.min_genesis_time
&& state.get_active_validator_indices(T::genesis_epoch()).len() as u64
@@ -56,7 +56,7 @@ pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSp
/// Activate genesis validators, if their balance is acceptable.
///
/// Spec v0.8.0
/// Spec v0.10.1
pub fn process_activations<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) {
for (index, validator) in state.validators.iter_mut().enumerate() {
let balance = state.balances[index];

View File

@@ -3,7 +3,7 @@ use errors::{BlockOperationError, BlockProcessingError, HeaderInvalid, IntoWithI
use rayon::prelude::*;
use signature_sets::{block_proposal_signature_set, randao_signature_set};
use std::convert::TryInto;
use tree_hash::SignedRoot;
use tree_hash::TreeHash;
use types::*;
pub use self::verify_attester_slashing::{
@@ -64,23 +64,27 @@ impl VerifySignatures {
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
/// returns an error describing why the block was invalid or how the function failed to execute.
///
/// If `block_signed_root` is `Some`, this root is used for verification of the proposers
/// signature. If it is `None` the signed root is calculated here. This parameter only exists to
/// avoid re-calculating the root when it is already known.
/// If `block_root` is `Some`, this root is used for verification of the proposer's signature. If it
/// is `None` the signing root is computed from scratch. This parameter only exists to avoid
/// re-calculating the root when it is already known. Note `block_root` should be equal to the
/// tree hash root of the block, NOT the signing root of the block. This function takes
/// care of mixing in the domain.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn per_block_processing<T: EthSpec>(
mut state: &mut BeaconState<T>,
block: &BeaconBlock<T>,
block_signed_root: Option<Hash256>,
signed_block: &SignedBeaconBlock<T>,
block_root: Option<Hash256>,
block_signature_strategy: BlockSignatureStrategy,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
let block = &signed_block.message;
let verify_signatures = match block_signature_strategy {
BlockSignatureStrategy::VerifyBulk => {
// Verify all signatures in the block at once.
block_verify!(
BlockSignatureVerifier::verify_entire_block(state, block, spec).is_ok(),
BlockSignatureVerifier::verify_entire_block(state, signed_block, block_root, spec)
.is_ok(),
BlockProcessingError::BulkSignatureVerificationFailed
);
VerifySignatures::False
@@ -89,7 +93,11 @@ pub fn per_block_processing<T: EthSpec>(
BlockSignatureStrategy::NoVerification => VerifySignatures::False,
};
process_block_header(state, block, block_signed_root, verify_signatures, spec)?;
process_block_header(state, block, spec)?;
if verify_signatures.is_true() {
verify_block_signature(&state, signed_block, block_root, &spec)?;
}
// Ensure the current and previous epoch caches are built.
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
@@ -128,18 +136,16 @@ pub fn per_block_processing<T: EthSpec>(
/// Processes the block header.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_block_header<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock<T>,
block_signed_root: Option<Hash256>,
verify_signatures: VerifySignatures,
spec: &ChainSpec,
) -> Result<(), BlockOperationError<HeaderInvalid>> {
verify!(block.slot == state.slot, HeaderInvalid::StateSlotMismatch);
let expected_previous_block_root =
Hash256::from_slice(&state.latest_block_header.signed_root());
Hash256::from_slice(&state.latest_block_header.tree_hash_root());
verify!(
block.parent_root == expected_previous_block_root,
HeaderInvalid::ParentBlockRootMismatch {
@@ -158,24 +164,20 @@ pub fn process_block_header<T: EthSpec>(
HeaderInvalid::ProposerSlashed(proposer_idx)
);
if verify_signatures.is_true() {
verify_block_signature(&state, &block, block_signed_root, &spec)?;
}
Ok(())
}
/// Verifies the signature of a block.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_block_signature<T: EthSpec>(
state: &BeaconState<T>,
block: &BeaconBlock<T>,
block_signed_root: Option<Hash256>,
block: &SignedBeaconBlock<T>,
block_root: Option<Hash256>,
spec: &ChainSpec,
) -> Result<(), BlockOperationError<HeaderInvalid>> {
verify!(
block_proposal_signature_set(state, block, block_signed_root, spec)?.is_valid(),
block_proposal_signature_set(state, block, block_root, spec)?.is_valid(),
HeaderInvalid::ProposalSignatureInvalid
);
@@ -185,7 +187,7 @@ pub fn verify_block_signature<T: EthSpec>(
/// Verifies the `randao_reveal` against the block's proposer pubkey and updates
/// `state.latest_randao_mixes`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_randao<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock<T>,
@@ -208,7 +210,7 @@ pub fn process_randao<T: EthSpec>(
/// Update the `state.eth1_data_votes` based upon the `eth1_data` provided.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_eth1_data<T: EthSpec>(
state: &mut BeaconState<T>,
eth1_data: &Eth1Data,
@@ -225,7 +227,7 @@ pub fn process_eth1_data<T: EthSpec>(
/// Returns `Some(eth1_data)` if adding the given `eth1_data` to `state.eth1_data_votes` would
/// result in a change to `state.eth1_data`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_new_eth1_data<T: EthSpec>(
state: &BeaconState<T>,
eth1_data: &Eth1Data,
@@ -249,7 +251,7 @@ pub fn get_new_eth1_data<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_proposer_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
proposer_slashings: &[ProposerSlashing],
@@ -278,7 +280,7 @@ pub fn process_proposer_slashings<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_attester_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
attester_slashings: &[AttesterSlashing<T>],
@@ -332,7 +334,7 @@ pub fn process_attester_slashings<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_attestations<T: EthSpec>(
state: &mut BeaconState<T>,
attestations: &[Attestation<T>],
@@ -378,7 +380,7 @@ pub fn process_attestations<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_deposits<T: EthSpec>(
state: &mut BeaconState<T>,
deposits: &[Deposit],
@@ -415,7 +417,7 @@ pub fn process_deposits<T: EthSpec>(
/// Process a single deposit, optionally verifying its merkle proof.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_deposit<T: EthSpec>(
state: &mut BeaconState<T>,
deposit: &Deposit,
@@ -481,10 +483,10 @@ pub fn process_deposit<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_exits<T: EthSpec>(
state: &mut BeaconState<T>,
voluntary_exits: &[VoluntaryExit],
voluntary_exits: &[SignedVoluntaryExit],
verify_signatures: VerifySignatures,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
@@ -498,7 +500,7 @@ pub fn process_exits<T: EthSpec>(
// Update the state in series.
for exit in voluntary_exits {
initiate_validator_exit(state, exit.validator_index as usize, spec)?;
initiate_validator_exit(state, exit.message.validator_index as usize, spec)?;
}
Ok(())

View File

@@ -1,5 +1,5 @@
use std::convert::TryInto;
use tree_hash::SignedRoot;
use tree_hash::TreeHash;
use types::test_utils::{
AttestationTestTask, AttesterSlashingTestTask, DepositTestTask, ExitTestTask,
ProposerSlashingTestTask, TestingBeaconBlockBuilder, TestingBeaconStateBuilder,
@@ -41,7 +41,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (mut state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -51,7 +51,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}
@@ -84,7 +84,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (mut state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -93,7 +93,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}
@@ -141,7 +141,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -150,7 +150,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}
@@ -184,7 +184,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -193,7 +193,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}
@@ -233,7 +233,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -242,7 +242,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}
@@ -275,7 +275,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
randao_sk: Option<SecretKey>,
previous_block_root: Option<Hash256>,
spec: &ChainSpec,
) -> (BeaconBlock<T>, BeaconState<T>) {
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;
@@ -284,7 +284,7 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
match previous_block_root {
Some(root) => builder.set_parent_root(root),
None => builder.set_parent_root(Hash256::from_slice(
&state.latest_block_header.signed_root(),
&state.latest_block_header.tree_hash_root(),
)),
}

View File

@@ -1,10 +1,12 @@
use super::signature_sets::{Error as SignatureSetError, Result as SignatureSetResult, *};
use crate::common::get_indexed_attestation;
use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError};
use bls::{verify_signature_sets, SignatureSet};
use rayon::prelude::*;
use types::{
BeaconBlock, BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256, IndexedAttestation,
BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256, IndexedAttestation,
SignedBeaconBlock,
};
pub type Result<T> = std::result::Result<T, Error>;
@@ -40,12 +42,12 @@ impl From<BlockOperationError<AttestationInvalid>> for Error {
}
}
/// Reads the BLS signatures and keys from a `BeaconBlock`, storing them as a `Vec<SignatureSet>`.
/// Reads the BLS signatures and keys from a `SignedBeaconBlock`, storing them as a `Vec<SignatureSet>`.
///
/// This allows for optimizations related to batch BLS operations (see the
/// `Self::verify_entire_block(..)` function).
pub struct BlockSignatureVerifier<'a, T: EthSpec> {
block: &'a BeaconBlock<T>,
block: &'a SignedBeaconBlock<T>,
state: &'a BeaconState<T>,
spec: &'a ChainSpec,
sets: Vec<SignatureSet<'a>>,
@@ -54,7 +56,11 @@ pub struct BlockSignatureVerifier<'a, T: EthSpec> {
impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
/// Create a new verifier without any included signatures. See the `include...` functions to
/// add signatures, and the `verify`
pub fn new(state: &'a BeaconState<T>, block: &'a BeaconBlock<T>, spec: &'a ChainSpec) -> Self {
pub fn new(
state: &'a BeaconState<T>,
block: &'a SignedBeaconBlock<T>,
spec: &'a ChainSpec,
) -> Self {
Self {
block,
state,
@@ -63,7 +69,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
}
}
/// Verify all* the signatures in the given `BeaconBlock`, returning `Ok(())` if the signatures
/// Verify all* the signatures in the given `SignedBeaconBlock`, returning `Ok(())` if the signatures
/// are valid.
///
/// * : _Does not verify any signatures in `block.body.deposits`. A block is still valid if it
@@ -72,12 +78,13 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
/// See `Self::verify` for more detail.
pub fn verify_entire_block(
state: &'a BeaconState<T>,
block: &'a BeaconBlock<T>,
block: &'a SignedBeaconBlock<T>,
block_root: Option<Hash256>,
spec: &'a ChainSpec,
) -> Result<()> {
let mut verifier = Self::new(state, block, spec);
verifier.include_block_proposal(None)?;
verifier.include_block_proposal(block_root)?;
verifier.include_randao_reveal()?;
verifier.include_proposer_slashings()?;
verifier.include_attester_slashings()?;
@@ -129,7 +136,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
/// Includes the randao signature for `self.block` for verification.
fn include_randao_reveal(&mut self) -> Result<()> {
let set = randao_signature_set(self.state, self.block, self.spec)?;
let set = randao_signature_set(self.state, &self.block.message, self.spec)?;
self.sets.push(set);
Ok(())
}
@@ -138,6 +145,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
fn include_proposer_slashings(&mut self) -> Result<()> {
let mut sets: Vec<SignatureSet> = self
.block
.message
.body
.proposer_slashings
.iter()
@@ -158,6 +166,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
/// Includes all signatures in `self.block.body.attester_slashings` for verification.
fn include_attester_slashings(&mut self) -> Result<()> {
self.block
.message
.body
.attester_slashings
.iter()
@@ -175,6 +184,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
/// Includes all signatures in `self.block.body.attestations` for verification.
fn include_attestations(&mut self) -> Result<Vec<IndexedAttestation<T>>> {
self.block
.message
.body
.attestations
.iter()
@@ -198,6 +208,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> {
fn include_exits(&mut self) -> Result<()> {
let mut sets = self
.block
.message
.body
.voluntary_exits
.iter()

View File

@@ -210,6 +210,11 @@ pub enum AttestationInvalid {
},
/// Attestation slot is too far in the past to be included in a block.
IncludedTooLate { state: Slot, attestation: Slot },
/// Attestation target epoch does not match attestation slot.
TargetEpochSlotMismatch {
target_epoch: Epoch,
slot_epoch: Epoch,
},
/// Attestation target epoch does not match the current or previous epoch.
BadTargetEpoch,
/// Attestation justified checkpoint doesn't match the state's current or previous justified

View File

@@ -11,7 +11,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// Verify an `IndexedAttestation`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn is_valid_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>,
indexed_attestation: &IndexedAttestation<T>,
@@ -26,14 +26,13 @@ pub fn is_valid_indexed_attestation<T: EthSpec>(
Invalid::MaxIndicesExceed(T::MaxValidatorsPerCommittee::to_usize(), indices.len())
);
// Check that indices are sorted
// Check that indices are sorted and unique
let check_sorted = |list: &[u64]| -> Result<()> {
list.windows(2).enumerate().try_for_each(|(i, pair)| {
// The spec allows duplicates, so use strict comparison (>).
if pair[0] > pair[1] {
Err(error(Invalid::BadValidatorIndicesOrdering(i)))
} else {
if pair[0] < pair[1] {
Ok(())
} else {
Err(error(Invalid::BadValidatorIndicesOrdering(i)))
}
})?;
Ok(())

View File

@@ -5,11 +5,12 @@
use bls::{G1Point, G1Ref, SignatureSet, SignedMessage};
use std::borrow::Cow;
use std::convert::TryInto;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash::TreeHash;
use types::{
AggregateSignature, AttesterSlashing, BeaconBlock, BeaconBlockHeader, BeaconState,
BeaconStateError, ChainSpec, DepositData, Domain, EthSpec, Hash256, IndexedAttestation,
ProposerSlashing, PublicKey, Signature, VoluntaryExit,
AggregateSignature, AttesterSlashing, BeaconBlock, BeaconState, BeaconStateError, ChainSpec,
DepositData, Domain, EthSpec, Hash256, IndexedAttestation, ProposerSlashing, PublicKey,
Signature, SignedBeaconBlock, SignedBeaconBlockHeader, SignedRoot, SignedVoluntaryExit,
SigningRoot,
};
pub type Result<T> = std::result::Result<T, Error>;
@@ -41,10 +42,11 @@ impl From<BeaconStateError> for Error {
/// A signature set that is valid if a block was signed by the expected block producer.
pub fn block_proposal_signature_set<'a, T: EthSpec>(
state: &'a BeaconState<T>,
block: &'a BeaconBlock<T>,
block_signed_root: Option<Hash256>,
signed_block: &'a SignedBeaconBlock<T>,
block_root: Option<Hash256>,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let block = &signed_block.message;
let proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
let domain = spec.get_domain(
@@ -53,17 +55,20 @@ pub fn block_proposal_signature_set<'a, T: EthSpec>(
&state.fork,
);
let message = if let Some(root) = block_signed_root {
root.as_bytes().to_vec()
let message = if let Some(root) = block_root {
SigningRoot {
object_root: root,
domain,
}
.tree_hash_root()
} else {
block.signed_root()
block.signing_root(domain).as_bytes().to_vec()
};
Ok(SignatureSet::single(
&block.signature,
&signed_block.signature,
validator_pubkey(state, proposer_index)?,
message,
domain,
))
}
@@ -81,13 +86,12 @@ pub fn randao_signature_set<'a, T: EthSpec>(
&state.fork,
);
let message = state.current_epoch().tree_hash_root();
let message = state.current_epoch().signing_root(domain);
Ok(SignatureSet::single(
&block.body.randao_reveal,
validator_pubkey(state, proposer_index)?,
message,
domain,
message.as_bytes().to_vec(),
))
}
@@ -102,13 +106,13 @@ pub fn proposer_slashing_signature_set<'a, T: EthSpec>(
Ok((
block_header_signature_set(
state,
&proposer_slashing.header_1,
&proposer_slashing.signed_header_1,
validator_pubkey(state, proposer_index)?,
spec,
)?,
block_header_signature_set(
state,
&proposer_slashing.header_2,
&proposer_slashing.signed_header_2,
validator_pubkey(state, proposer_index)?,
spec,
)?,
@@ -118,23 +122,26 @@ pub fn proposer_slashing_signature_set<'a, T: EthSpec>(
/// Returns a signature set that is valid if the given `pubkey` signed the `header`.
fn block_header_signature_set<'a, T: EthSpec>(
state: &'a BeaconState<T>,
header: &'a BeaconBlockHeader,
signed_header: &'a SignedBeaconBlockHeader,
pubkey: Cow<'a, G1Point>,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let domain = spec.get_domain(
header.slot.epoch(T::slots_per_epoch()),
signed_header.message.slot.epoch(T::slots_per_epoch()),
Domain::BeaconProposer,
&state.fork,
);
let message = header.signed_root();
let message = signed_header
.message
.signing_root(domain)
.as_bytes()
.to_vec();
Ok(SignatureSet::single(
&header.signature,
&signed_header.signature,
pubkey,
message,
domain,
))
}
@@ -145,23 +152,22 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
indexed_attestation: &'b IndexedAttestation<T>,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let message = indexed_attestation.data.tree_hash_root();
let pubkeys = indexed_attestation
.attesting_indices
.into_iter()
.map(|&validator_idx| Ok(validator_pubkey(state, validator_idx as usize)?))
.collect::<Result<_>>()?;
let signed_message = SignedMessage::new(pubkeys, message);
let domain = spec.get_domain(
indexed_attestation.data.target.epoch,
Domain::BeaconAttester,
&state.fork,
);
Ok(SignatureSet::new(signature, vec![signed_message], domain))
let message = indexed_attestation.data.signing_root(domain);
let signed_message = SignedMessage::new(pubkeys, message.as_bytes().to_vec());
Ok(SignatureSet::new(signature, vec![signed_message]))
}
/// Returns the signature set for the given `attester_slashing` and corresponding `pubkeys`.
@@ -191,10 +197,16 @@ pub fn attester_slashing_signature_sets<'a, T: EthSpec>(
/// This method is separate to `deposit_signature_set` to satisfy lifetime requirements.
pub fn deposit_pubkey_signature_message(
deposit_data: &DepositData,
spec: &ChainSpec,
) -> Option<(PublicKey, Signature, Vec<u8>)> {
let pubkey = (&deposit_data.pubkey).try_into().ok()?;
let signature = (&deposit_data.signature).try_into().ok()?;
let message = deposit_data.signed_root();
let domain = spec.get_deposit_domain();
let message = deposit_data
.as_deposit_message()
.signing_root(domain)
.as_bytes()
.to_vec();
Some((pubkey, signature, message))
}
@@ -202,43 +214,37 @@ pub fn deposit_pubkey_signature_message(
/// `deposit_pubkey_signature_message`.
pub fn deposit_signature_set<'a>(
pubkey_signature_message: &'a (PublicKey, Signature, Vec<u8>),
spec: &'a ChainSpec,
) -> SignatureSet<'a> {
let (pubkey, signature, message) = pubkey_signature_message;
// Note: Deposits are valid across forks, thus the deposit domain is computed
// with the fork zeroed.
SignatureSet::single(
signature,
pubkey.g1_ref(),
message.clone(),
spec.get_deposit_domain(),
)
SignatureSet::single(signature, pubkey.g1_ref(), message.clone())
}
/// Returns a signature set that is valid if the `VoluntaryExit` was signed by the indicated
/// Returns a signature set that is valid if the `SignedVoluntaryExit` was signed by the indicated
/// validator.
pub fn exit_signature_set<'a, T: EthSpec>(
state: &'a BeaconState<T>,
exit: &'a VoluntaryExit,
signed_exit: &'a SignedVoluntaryExit,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let exit = &signed_exit.message;
let proposer_index = exit.validator_index as usize;
let domain = spec.get_domain(exit.epoch, Domain::VoluntaryExit, &state.fork);
let message = exit.signed_root();
let message = exit.signing_root(domain).as_bytes().to_vec();
Ok(SignatureSet::single(
&exit.signature,
&signed_exit.signature,
validator_pubkey(state, proposer_index)?,
message,
domain,
))
}
/// Maps a validator index to a `PublicKey`.
fn validator_pubkey<'a, T: EthSpec>(
pub fn validator_pubkey<'a, T: EthSpec>(
state: &'a BeaconState<T>,
validator_index: usize,
) -> Result<Cow<'a, G1Point>> {

View File

@@ -3,7 +3,6 @@
use super::block_processing_builder::BlockProcessingBuilder;
use super::errors::*;
use crate::{per_block_processing, BlockSignatureStrategy};
use tree_hash::SignedRoot;
use types::test_utils::{
AttestationTestTask, AttesterSlashingTestTask, DepositTestTask, ExitTestTask,
ProposerSlashingTestTask,
@@ -16,6 +15,8 @@ pub const SLOT_OFFSET: u64 = 4;
pub const EXIT_SLOT_OFFSET: u64 = 2048;
pub const NUM_ATTESTATIONS: u64 = 1;
type E = MainnetEthSpec;
#[test]
fn valid_block_ok() {
let spec = MainnetEthSpec::default_spec();
@@ -40,7 +41,7 @@ fn invalid_block_header_state_slot() {
let (mut block, mut state) = builder.build(None, None, &spec);
state.slot = Slot::new(133_713);
block.slot = Slot::new(424_242);
block.message.slot = Slot::new(424_242);
let result = per_block_processing(
&mut state,
@@ -77,8 +78,8 @@ fn invalid_parent_block_root() {
result,
Err(BlockProcessingError::HeaderInvalid {
reason: HeaderInvalid::ParentBlockRootMismatch {
state: Hash256::from_slice(&state.latest_block_header.signed_root()),
block: block.parent_root
state: state.latest_block_header.canonical_root(),
block: block.parent_root()
}
})
);
@@ -88,14 +89,11 @@ fn invalid_parent_block_root() {
fn invalid_block_signature() {
let spec = MainnetEthSpec::default_spec();
let builder = get_builder(&spec, SLOT_OFFSET, VALIDATOR_COUNT);
let (mut block, mut state) = builder.build(None, None, &spec);
let (block, mut state) = builder.build(None, None, &spec);
// sign the block with a keypair that is not the expected proposer
let keypair = Keypair::random();
let message = block.signed_root();
let epoch = block.slot.epoch(MainnetEthSpec::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::BeaconProposer, &state.fork);
block.signature = Signature::new(&message, domain, &keypair.sk);
let block = block.message.sign(&keypair.sk, &state.fork, &spec);
// process block with invalid block signature
let result = per_block_processing(
@@ -629,60 +627,6 @@ fn invalid_attestation_wrong_justified_checkpoint() {
);
}
#[test]
fn invalid_attestation_bad_target_too_low() {
let spec = MainnetEthSpec::default_spec();
let builder = get_builder(&spec, SLOT_OFFSET, VALIDATOR_COUNT);
let test_task = AttestationTestTask::BadTargetTooLow;
let (block, mut state) =
builder.build_with_n_attestations(test_task, NUM_ATTESTATIONS, None, None, &spec);
let result = per_block_processing(
&mut state,
&block,
None,
BlockSignatureStrategy::VerifyIndividual,
&spec,
);
// Expecting BadTargetEpoch because we manually set the
// target field of the AttestationData object to be invalid
assert_eq!(
result,
Err(BlockProcessingError::AttestationInvalid {
index: 0,
reason: AttestationInvalid::BadTargetEpoch
})
);
}
#[test]
fn invalid_attestation_bad_target_too_high() {
let spec = MainnetEthSpec::default_spec();
let builder = get_builder(&spec, SLOT_OFFSET, VALIDATOR_COUNT);
let test_task = AttestationTestTask::BadTargetTooHigh;
let (block, mut state) =
builder.build_with_n_attestations(test_task, NUM_ATTESTATIONS, None, None, &spec);
let result = per_block_processing(
&mut state,
&block,
None,
BlockSignatureStrategy::VerifyIndividual,
&spec,
);
// Expecting BadTargetEpoch because we manually set the
// target field of the AttestationData object to be invalid
assert_eq!(
result,
Err(BlockProcessingError::AttestationInvalid {
index: 0,
reason: AttestationInvalid::BadTargetEpoch
})
);
}
#[test]
fn invalid_attestation_bad_indexed_attestation_bad_signature() {
let spec = MainnetEthSpec::default_spec();
@@ -787,7 +731,7 @@ fn invalid_attestation_included_too_early() {
reason: AttestationInvalid::IncludedTooEarly {
state: state.slot,
delay: spec.min_attestation_inclusion_delay,
attestation: block.body.attestations[0].data.slot,
attestation: block.message.body.attestations[0].data.slot,
}
})
);
@@ -816,18 +760,18 @@ fn invalid_attestation_included_too_late() {
index: 0,
reason: AttestationInvalid::IncludedTooLate {
state: state.slot,
attestation: block.body.attestations[0].data.slot,
attestation: block.message.body.attestations[0].data.slot,
}
})
);
}
#[test]
fn invalid_attestation_bad_target_epoch() {
fn invalid_attestation_target_epoch_slot_mismatch() {
let spec = MainnetEthSpec::default_spec();
// note to maintainer: might need to increase validator count if we get NoCommittee
let builder = get_builder(&spec, SLOT_OFFSET, VALIDATOR_COUNT);
let test_task = AttestationTestTask::BadTargetEpoch;
let test_task = AttestationTestTask::TargetEpochSlotMismatch;
let (block, mut state) =
builder.build_with_n_attestations(test_task, NUM_ATTESTATIONS, None, None, &spec);
@@ -839,20 +783,16 @@ fn invalid_attestation_bad_target_epoch() {
&spec,
);
// Expecting BadTargetEpoch because the target epoch is bigger by one than the epoch expected
assert!(
result
== Err(BlockProcessingError::BeaconStateError(
BeaconStateError::NoCommittee {
slot: Slot::new(0),
index: 0
}
))
|| result
== Err(BlockProcessingError::AttestationInvalid {
index: 0,
reason: AttestationInvalid::BadTargetEpoch
})
let attestation = &block.message.body.attestations[0].data;
assert_eq!(
result,
Err(BlockProcessingError::AttestationInvalid {
index: 0,
reason: AttestationInvalid::TargetEpochSlotMismatch {
target_epoch: attestation.target.epoch,
slot_epoch: attestation.slot.epoch(E::slots_per_epoch()),
}
})
);
}

View File

@@ -15,7 +15,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
///
/// Optionally verifies the aggregate signature, depending on `verify_signatures`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation<T>,
@@ -49,7 +49,7 @@ pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
/// Returns a descriptive `Err` if the attestation is malformed or does not accurately reflect the
/// prior blocks in `state`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_attestation_for_state<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation<T>,
@@ -75,12 +75,19 @@ pub fn verify_attestation_for_state<T: EthSpec>(
/// Check target epoch and source checkpoint.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn verify_casper_ffg_vote<T: EthSpec>(
attestation: &Attestation<T>,
state: &BeaconState<T>,
) -> Result<()> {
let data = &attestation.data;
verify!(
data.target.epoch == data.slot.epoch(T::slots_per_epoch()),
Invalid::TargetEpochSlotMismatch {
target_epoch: data.target.epoch,
slot_epoch: data.slot.epoch(T::slots_per_epoch()),
}
);
if data.target.epoch == state.current_epoch() {
verify!(
data.source == state.current_justified_checkpoint,

View File

@@ -15,7 +15,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
///
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>,
@@ -47,7 +47,7 @@ pub fn verify_attester_slashing<T: EthSpec>(
///
/// Returns Ok(indices) if `indices.len() > 0`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_slashable_indices<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>,

View File

@@ -14,13 +14,13 @@ fn error(reason: DepositInvalid) -> BlockOperationError<DepositInvalid> {
/// Verify `Deposit.pubkey` signed `Deposit.signature`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_deposit_signature(deposit_data: &DepositData, spec: &ChainSpec) -> Result<()> {
let deposit_signature_message = deposit_pubkey_signature_message(&deposit_data)
let deposit_signature_message = deposit_pubkey_signature_message(&deposit_data, spec)
.ok_or_else(|| error(DepositInvalid::BadBlsBytes))?;
verify!(
deposit_signature_set(&deposit_signature_message, spec).is_valid(),
deposit_signature_set(&deposit_signature_message).is_valid(),
DepositInvalid::BadSignature
);
@@ -46,7 +46,7 @@ pub fn get_existing_validator_index<T: EthSpec>(
/// The deposit index is provided as a parameter so we can check proofs
/// before they're due to be processed, and in parallel.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_deposit_merkle_proof<T: EthSpec>(
state: &BeaconState<T>,
deposit: &Deposit,

View File

@@ -13,10 +13,10 @@ fn error(reason: ExitInvalid) -> BlockOperationError<ExitInvalid> {
///
/// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_exit<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
exit: &SignedVoluntaryExit,
verify_signatures: VerifySignatures,
spec: &ChainSpec,
) -> Result<()> {
@@ -25,10 +25,10 @@ pub fn verify_exit<T: EthSpec>(
/// Like `verify_exit` but doesn't run checks which may become true in future states.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_exit_time_independent_only<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
exit: &SignedVoluntaryExit,
verify_signatures: VerifySignatures,
spec: &ChainSpec,
) -> Result<()> {
@@ -37,14 +37,16 @@ pub fn verify_exit_time_independent_only<T: EthSpec>(
/// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn verify_exit_parametric<T: EthSpec>(
state: &BeaconState<T>,
exit: &VoluntaryExit,
signed_exit: &SignedVoluntaryExit,
verify_signatures: VerifySignatures,
spec: &ChainSpec,
time_independent_only: bool,
) -> Result<()> {
let exit = &signed_exit.message;
let validator = state
.validators
.get(exit.validator_index as usize)
@@ -82,7 +84,7 @@ fn verify_exit_parametric<T: EthSpec>(
if verify_signatures.is_true() {
verify!(
exit_signature_set(state, exit, spec)?.is_valid(),
exit_signature_set(state, signed_exit, spec)?.is_valid(),
ExitInvalid::BadSignature
);
}

View File

@@ -14,7 +14,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
///
/// Returns `Ok(())` if the `ProposerSlashing` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn verify_proposer_slashing<T: EthSpec>(
proposer_slashing: &ProposerSlashing,
state: &BeaconState<T>,
@@ -28,16 +28,17 @@ pub fn verify_proposer_slashing<T: EthSpec>(
// Verify slots match
verify!(
proposer_slashing.header_1.slot == proposer_slashing.header_2.slot,
proposer_slashing.signed_header_1.message.slot
== proposer_slashing.signed_header_2.message.slot,
Invalid::ProposalSlotMismatch(
proposer_slashing.header_1.slot,
proposer_slashing.header_2.slot
proposer_slashing.signed_header_1.message.slot,
proposer_slashing.signed_header_2.message.slot
)
);
// But the headers are different
verify!(
proposer_slashing.header_1 != proposer_slashing.header_2,
proposer_slashing.signed_header_1 != proposer_slashing.signed_header_2,
Invalid::ProposalsIdentical
);

View File

@@ -19,7 +19,7 @@ pub use validator_statuses::{TotalBalances, ValidatorStatus, ValidatorStatuses};
/// Mutates the given `BeaconState`, returning early if an error is encountered. If an error is
/// returned, a state might be "half-processed" and therefore in an invalid state.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn per_epoch_processing<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
@@ -66,7 +66,7 @@ pub fn per_epoch_processing<T: EthSpec>(
/// - `finalized_epoch`
/// - `finalized_root`
///
/// Spec v0.9.1
/// Spec v0.10.1
#[allow(clippy::if_same_then_else)] // For readability and consistency with spec.
pub fn process_justification_and_finalization<T: EthSpec>(
state: &mut BeaconState<T>,
@@ -134,7 +134,7 @@ pub fn process_justification_and_finalization<T: EthSpec>(
/// Finish up an epoch update.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_final_updates<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,

View File

@@ -33,7 +33,7 @@ impl std::ops::AddAssign for Delta {
/// Apply attester and proposer rewards.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_rewards_and_penalties<T: EthSpec>(
state: &mut BeaconState<T>,
validator_statuses: &mut ValidatorStatuses,
@@ -67,7 +67,7 @@ pub fn process_rewards_and_penalties<T: EthSpec>(
/// For each attesting validator, reward the proposer who was first to include their attestation.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_proposer_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState<T>,
@@ -100,7 +100,7 @@ fn get_proposer_deltas<T: EthSpec>(
/// Apply rewards for participation in attestations during the previous epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_attestation_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState<T>,
@@ -133,7 +133,7 @@ fn get_attestation_deltas<T: EthSpec>(
/// Determine the delta for a single validator, sans proposer rewards.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_attestation_delta<T: EthSpec>(
validator: &ValidatorStatus,
total_balances: &TotalBalances,

View File

@@ -2,7 +2,7 @@ use types::{BeaconStateError as Error, *};
/// Process slashings.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_slashings<T: EthSpec>(
state: &mut BeaconState<T>,
total_balance: u64,

View File

@@ -5,7 +5,7 @@ use types::*;
/// Performs a validator registry update, if required.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_registry_updates<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
@@ -15,10 +15,6 @@ pub fn process_registry_updates<T: EthSpec>(
// We assume it's safe to re-order the change in eligibility and `initiate_validator_exit`.
// Rest assured exiting validators will still be exited in the same order as in the spec.
let current_epoch = state.current_epoch();
let is_eligible = |validator: &Validator| {
validator.activation_eligibility_epoch == spec.far_future_epoch
&& validator.effective_balance == spec.max_effective_balance
};
let is_exiting_validator = |validator: &Validator| {
validator.is_active_at(current_epoch)
&& validator.effective_balance <= spec.ejection_balance
@@ -27,16 +23,18 @@ pub fn process_registry_updates<T: EthSpec>(
.validators
.iter()
.enumerate()
.filter(|(_, validator)| is_eligible(validator) || is_exiting_validator(validator))
.filter(|(_, validator)| {
validator.is_eligible_for_activation_queue(spec) || is_exiting_validator(validator)
})
.partition_map(|(index, validator)| {
if is_eligible(validator) {
if validator.is_eligible_for_activation_queue(spec) {
Either::Left(index)
} else {
Either::Right(index)
}
});
for index in eligible_validators {
state.validators[index].activation_eligibility_epoch = current_epoch;
state.validators[index].activation_eligibility_epoch = current_epoch + 1;
}
for index in exiting_validators {
initiate_validator_exit(state, index, spec)?;
@@ -47,22 +45,17 @@ pub fn process_registry_updates<T: EthSpec>(
.validators
.iter()
.enumerate()
.filter(|(_, validator)| {
validator.activation_eligibility_epoch != spec.far_future_epoch
&& validator.activation_epoch
>= state.compute_activation_exit_epoch(state.finalized_checkpoint.epoch, spec)
})
.sorted_by_key(|(_, validator)| validator.activation_eligibility_epoch)
.filter(|(_, validator)| validator.is_eligible_for_activation(state, spec))
.sorted_by_key(|(index, validator)| (validator.activation_eligibility_epoch, *index))
.map(|(index, _)| index)
.collect_vec();
// Dequeue validators for activation up to churn limit
let churn_limit = state.get_churn_limit(spec)? as usize;
let delayed_activation_epoch = state.compute_activation_exit_epoch(current_epoch, spec);
for index in activation_queue.into_iter().take(churn_limit) {
let validator = &mut state.validators[index];
if validator.activation_epoch == spec.far_future_epoch {
validator.activation_epoch = delayed_activation_epoch;
}
validator.activation_epoch = delayed_activation_epoch;
}
Ok(())

View File

@@ -144,7 +144,7 @@ impl ValidatorStatuses {
/// - Active validators
/// - Total balances for the current and previous epochs.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn new<T: EthSpec>(
state: &BeaconState<T>,
spec: &ChainSpec,
@@ -184,7 +184,7 @@ impl ValidatorStatuses {
/// Process some attestations from the given `state` updating the `statuses` and
/// `total_balances` fields.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn process_attestations<T: EthSpec>(
&mut self,
state: &BeaconState<T>,
@@ -263,7 +263,7 @@ impl ValidatorStatuses {
/// Returns `true` if the attestation's FFG target is equal to the hash of the `state`'s first
/// beacon block in the given `epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn target_matches_epoch_start_block<T: EthSpec>(
a: &PendingAttestation<T>,
state: &BeaconState<T>,
@@ -278,7 +278,7 @@ fn target_matches_epoch_start_block<T: EthSpec>(
/// Returns `true` if a `PendingAttestation` and `BeaconState` share the same beacon block hash for
/// the current slot of the `PendingAttestation`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn has_common_beacon_block_root<T: EthSpec>(
a: &PendingAttestation<T>,
state: &BeaconState<T>,

View File

@@ -13,7 +13,7 @@ pub enum Error {
/// `state_root` is `None`, the root of `state` will be computed using a cached tree hash.
/// Providing the `state_root` makes this function several orders of magniude faster.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn per_slot_processing<T: EthSpec>(
state: &mut BeaconState<T>,
state_root: Option<Hash256>,

View File

@@ -52,7 +52,7 @@ impl<T: EthSpec> BlockBuilder<T> {
self.state_builder.build_caches(&spec).unwrap();
}
pub fn build(mut self, spec: &ChainSpec) -> (BeaconBlock<T>, BeaconState<T>) {
pub fn build(mut self, spec: &ChainSpec) -> (SignedBeaconBlock<T>, BeaconState<T>) {
let (mut state, keypairs) = self.state_builder.build();
let builder = &mut self.block_builder;

View File

@@ -4,13 +4,13 @@ use state_processing::{
per_block_processing, test_utils::BlockBuilder, BlockProcessingError, BlockSignatureStrategy,
};
use types::{
AggregateSignature, BeaconBlock, BeaconState, ChainSpec, EthSpec, Keypair, MinimalEthSpec,
Signature, Slot,
AggregateSignature, BeaconState, ChainSpec, EthSpec, Keypair, MinimalEthSpec, Signature,
SignedBeaconBlock, Slot,
};
const VALIDATOR_COUNT: usize = 64;
fn get_block<T, F>(mut mutate_builder: F) -> (BeaconBlock<T>, BeaconState<T>)
fn get_block<T, F>(mut mutate_builder: F) -> (SignedBeaconBlock<T>, BeaconState<T>)
where
T: EthSpec,
F: FnMut(&mut BlockBuilder<T>),
@@ -27,7 +27,7 @@ fn test_scenario<T: EthSpec, F, G>(mutate_builder: F, mut invalidate_block: G, s
where
T: EthSpec,
F: FnMut(&mut BlockBuilder<T>),
G: FnMut(&mut BeaconBlock<T>),
G: FnMut(&mut SignedBeaconBlock<T>),
{
let (mut block, mut state) = get_block::<T, _>(mutate_builder);
@@ -100,7 +100,7 @@ fn agg_sig() -> AggregateSignature {
// TODO: use lazy static
fn sig() -> Signature {
let keypair = Keypair::random();
Signature::new(&[42, 42], 12, &keypair.sk)
Signature::new(&[42, 42], &keypair.sk)
}
type TestEthSpec = MinimalEthSpec;
@@ -119,7 +119,11 @@ mod signatures_minimal {
fn randao() {
let spec = &TestEthSpec::default_spec();
test_scenario::<TestEthSpec, _, _>(|_| {}, |block| block.body.randao_reveal = sig(), spec);
test_scenario::<TestEthSpec, _, _>(
|_| {},
|block| block.message.body.randao_reveal = sig(),
spec,
);
}
#[test]
@@ -130,14 +134,22 @@ mod signatures_minimal {
|mut builder| {
builder.num_proposer_slashings = 1;
},
|block| block.body.proposer_slashings[0].header_1.signature = sig(),
|block| {
block.message.body.proposer_slashings[0]
.signed_header_1
.signature = sig()
},
spec,
);
test_scenario::<TestEthSpec, _, _>(
|mut builder| {
builder.num_proposer_slashings = 1;
},
|block| block.body.proposer_slashings[0].header_2.signature = sig(),
|block| {
block.message.body.proposer_slashings[0]
.signed_header_2
.signature = sig()
},
spec,
);
}
@@ -150,14 +162,22 @@ mod signatures_minimal {
|mut builder| {
builder.num_attester_slashings = 1;
},
|block| block.body.attester_slashings[0].attestation_1.signature = agg_sig(),
|block| {
block.message.body.attester_slashings[0]
.attestation_1
.signature = agg_sig()
},
spec,
);
test_scenario::<TestEthSpec, _, _>(
|mut builder| {
builder.num_attester_slashings = 1;
},
|block| block.body.attester_slashings[0].attestation_2.signature = agg_sig(),
|block| {
block.message.body.attester_slashings[0]
.attestation_2
.signature = agg_sig()
},
spec,
);
}
@@ -170,7 +190,7 @@ mod signatures_minimal {
|mut builder| {
builder.num_attestations = 1;
},
|block| block.body.attestations[0].signature = agg_sig(),
|block| block.message.body.attestations[0].signature = agg_sig(),
spec,
);
}
@@ -185,7 +205,7 @@ mod signatures_minimal {
|mut builder| {
builder.num_deposits = 1;
},
|block| block.body.deposits[0].data.signature = sig().into(),
|block| block.message.body.deposits[0].data.signature = sig().into(),
spec,
);
}
@@ -201,7 +221,7 @@ mod signatures_minimal {
|mut builder| {
builder.num_exits = 1;
},
|block| block.body.voluntary_exits[0].signature = sig(),
|block| block.message.body.voluntary_exits[0].signature = sig(),
spec,
);
}