mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
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:
@@ -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,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(),
|
||||
)),
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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>> {
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user