mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-01 11:43:44 +00:00
Altair consensus changes and refactors (#2279)
## Proposed Changes Implement the consensus changes necessary for the upcoming Altair hard fork. ## Additional Info This is quite a heavy refactor, with pivotal types like the `BeaconState` and `BeaconBlock` changing from structs to enums. This ripples through the whole codebase with field accesses changing to methods, e.g. `state.slot` => `state.slot()`. Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
pub mod sync_committee;
|
||||
@@ -0,0 +1,86 @@
|
||||
use crate::common::{altair::get_base_reward_per_increment, decrease_balance, increase_balance};
|
||||
use crate::per_block_processing::errors::{BlockProcessingError, SyncAggregateInvalid};
|
||||
use safe_arith::SafeArith;
|
||||
use tree_hash::TreeHash;
|
||||
use types::consts::altair::{PROPOSER_WEIGHT, SYNC_REWARD_WEIGHT, WEIGHT_DENOMINATOR};
|
||||
use types::{BeaconState, ChainSpec, Domain, EthSpec, SigningData, SyncAggregate, Unsigned};
|
||||
|
||||
pub fn process_sync_aggregate<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
aggregate: &SyncAggregate<T>,
|
||||
proposer_index: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Verify sync committee aggregate signature signing over the previous slot block root
|
||||
let previous_slot = state.slot().saturating_sub(1u64);
|
||||
|
||||
let current_sync_committee = state.current_sync_committee()?.clone();
|
||||
let committee_pubkeys = ¤t_sync_committee.pubkeys;
|
||||
|
||||
let participant_pubkeys = committee_pubkeys
|
||||
.iter()
|
||||
.zip(aggregate.sync_committee_bits.iter())
|
||||
.flat_map(|(pubkey, bit)| {
|
||||
if bit {
|
||||
// FIXME(altair): accelerate pubkey decompression with a cache
|
||||
Some(pubkey.decompress())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| SyncAggregateInvalid::PubkeyInvalid)?;
|
||||
|
||||
let domain = spec.get_domain(
|
||||
previous_slot.epoch(T::slots_per_epoch()),
|
||||
Domain::SyncCommittee,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let signing_root = SigningData {
|
||||
object_root: *state.get_block_root(previous_slot)?,
|
||||
domain,
|
||||
}
|
||||
.tree_hash_root();
|
||||
|
||||
let pubkey_refs = participant_pubkeys.iter().collect::<Vec<_>>();
|
||||
if !aggregate
|
||||
.sync_committee_signature
|
||||
.eth2_fast_aggregate_verify(signing_root, &pubkey_refs)
|
||||
{
|
||||
return Err(SyncAggregateInvalid::SignatureInvalid.into());
|
||||
}
|
||||
|
||||
// Compute participant and proposer rewards
|
||||
let total_active_balance = state.get_total_active_balance(spec)?;
|
||||
let total_active_increments =
|
||||
total_active_balance.safe_div(spec.effective_balance_increment)?;
|
||||
let total_base_rewards = get_base_reward_per_increment(total_active_balance, spec)?
|
||||
.safe_mul(total_active_increments)?;
|
||||
let max_participant_rewards = total_base_rewards
|
||||
.safe_mul(SYNC_REWARD_WEIGHT)?
|
||||
.safe_div(WEIGHT_DENOMINATOR)?
|
||||
.safe_div(T::slots_per_epoch())?;
|
||||
let participant_reward = max_participant_rewards.safe_div(T::SyncCommitteeSize::to_u64())?;
|
||||
let proposer_reward = participant_reward
|
||||
.safe_mul(PROPOSER_WEIGHT)?
|
||||
.safe_div(WEIGHT_DENOMINATOR.safe_sub(PROPOSER_WEIGHT)?)?;
|
||||
|
||||
// Apply participant and proposer rewards
|
||||
let committee_indices = state.get_sync_committee_indices(¤t_sync_committee)?;
|
||||
|
||||
for (participant_index, participation_bit) in committee_indices
|
||||
.into_iter()
|
||||
.zip(aggregate.sync_committee_bits.iter())
|
||||
{
|
||||
if participation_bit {
|
||||
increase_balance(state, participant_index as usize, participant_reward)?;
|
||||
increase_balance(state, proposer_index as usize, proposer_reward)?;
|
||||
} else {
|
||||
decrease_balance(state, participant_index as usize, participant_reward)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,380 +0,0 @@
|
||||
use tree_hash::TreeHash;
|
||||
use types::test_utils::{
|
||||
AttestationTestTask, AttesterSlashingTestTask, DepositTestTask, ProposerSlashingTestTask,
|
||||
TestingAttestationDataBuilder, TestingBeaconBlockBuilder, TestingBeaconStateBuilder,
|
||||
};
|
||||
use types::*;
|
||||
|
||||
pub struct BlockProcessingBuilder<'a, T: EthSpec> {
|
||||
pub state: BeaconState<T>,
|
||||
pub keypairs: Vec<Keypair>,
|
||||
pub block_builder: TestingBeaconBlockBuilder<T>,
|
||||
pub spec: &'a ChainSpec,
|
||||
}
|
||||
|
||||
impl<'a, T: EthSpec> BlockProcessingBuilder<'a, T> {
|
||||
pub fn new(num_validators: usize, state_slot: Slot, spec: &'a ChainSpec) -> Self {
|
||||
let mut state_builder =
|
||||
TestingBeaconStateBuilder::from_deterministic_keypairs(num_validators, &spec);
|
||||
state_builder.teleport_to_slot(state_slot);
|
||||
let (state, keypairs) = state_builder.build();
|
||||
let block_builder = TestingBeaconBlockBuilder::new(spec);
|
||||
|
||||
Self {
|
||||
state,
|
||||
keypairs,
|
||||
block_builder,
|
||||
spec,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_caches(mut self) -> Self {
|
||||
self.state
|
||||
.build_all_caches(self.spec)
|
||||
.expect("caches build OK");
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build_with_n_deposits(
|
||||
mut self,
|
||||
num_deposits: u64,
|
||||
test_task: DepositTestTask,
|
||||
randao_sk: Option<SecretKey>,
|
||||
previous_block_root: Option<Hash256>,
|
||||
spec: &ChainSpec,
|
||||
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
|
||||
let (mut state, keypairs) = (self.state, self.keypairs);
|
||||
|
||||
let builder = &mut self.block_builder;
|
||||
|
||||
builder.set_slot(state.slot);
|
||||
|
||||
match previous_block_root {
|
||||
Some(root) => builder.set_parent_root(root),
|
||||
None => builder.set_parent_root(state.latest_block_header.tree_hash_root()),
|
||||
}
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
|
||||
let keypair = &keypairs[proposer_index];
|
||||
|
||||
builder.set_proposer_index(proposer_index as u64);
|
||||
|
||||
match randao_sk {
|
||||
Some(sk) => {
|
||||
builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
|
||||
}
|
||||
None => builder.set_randao_reveal(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
|
||||
self.block_builder.insert_deposits(
|
||||
spec.max_effective_balance,
|
||||
test_task,
|
||||
1,
|
||||
num_deposits,
|
||||
&mut state,
|
||||
spec,
|
||||
);
|
||||
|
||||
let block = self.block_builder.build(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
(block, state)
|
||||
}
|
||||
|
||||
/// Insert a signed `VoluntaryIndex` for the given validator at the given `exit_epoch`.
|
||||
pub fn insert_exit(mut self, validator_index: u64, exit_epoch: Epoch) -> Self {
|
||||
self.block_builder.insert_exit(
|
||||
validator_index,
|
||||
exit_epoch,
|
||||
&self.keypairs[validator_index as usize].sk,
|
||||
&self.state,
|
||||
self.spec,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Insert an attestation for the given slot and index.
|
||||
///
|
||||
/// It will be signed by all validators for which `should_sign` returns `true`
|
||||
/// when called with `(committee_position, validator_index)`.
|
||||
// TODO: consider using this pattern to replace the TestingAttestationBuilder
|
||||
pub fn insert_attestation(
|
||||
mut self,
|
||||
slot: Slot,
|
||||
index: u64,
|
||||
mut should_sign: impl FnMut(usize, usize) -> bool,
|
||||
) -> Self {
|
||||
let committee = self.state.get_beacon_committee(slot, index).unwrap();
|
||||
let data = TestingAttestationDataBuilder::new(
|
||||
AttestationTestTask::Valid,
|
||||
&self.state,
|
||||
index,
|
||||
slot,
|
||||
self.spec,
|
||||
)
|
||||
.build();
|
||||
|
||||
let mut attestation = Attestation {
|
||||
aggregation_bits: BitList::with_capacity(committee.committee.len()).unwrap(),
|
||||
data,
|
||||
signature: AggregateSignature::empty(),
|
||||
};
|
||||
|
||||
for (i, &validator_index) in committee.committee.iter().enumerate() {
|
||||
if should_sign(i, validator_index) {
|
||||
attestation
|
||||
.sign(
|
||||
&self.keypairs[validator_index].sk,
|
||||
i,
|
||||
&self.state.fork,
|
||||
self.state.genesis_validators_root,
|
||||
self.spec,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
self.block_builder
|
||||
.block
|
||||
.body
|
||||
.attestations
|
||||
.push(attestation)
|
||||
.unwrap();
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Apply a mutation to the `BeaconBlock` before signing.
|
||||
pub fn modify(mut self, f: impl FnOnce(&mut BeaconBlock<T>)) -> Self {
|
||||
self.block_builder.modify(f);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build_with_n_attestations(
|
||||
mut self,
|
||||
test_task: AttestationTestTask,
|
||||
num_attestations: u64,
|
||||
randao_sk: Option<SecretKey>,
|
||||
previous_block_root: Option<Hash256>,
|
||||
spec: &ChainSpec,
|
||||
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
|
||||
let (state, keypairs) = (self.state, self.keypairs);
|
||||
let builder = &mut self.block_builder;
|
||||
|
||||
builder.set_slot(state.slot);
|
||||
|
||||
match previous_block_root {
|
||||
Some(root) => builder.set_parent_root(root),
|
||||
None => builder.set_parent_root(state.latest_block_header.tree_hash_root()),
|
||||
}
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
|
||||
let keypair = &keypairs[proposer_index];
|
||||
|
||||
builder.set_proposer_index(proposer_index as u64);
|
||||
|
||||
match randao_sk {
|
||||
Some(sk) => {
|
||||
builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
|
||||
}
|
||||
None => builder.set_randao_reveal(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
|
||||
let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect();
|
||||
self.block_builder
|
||||
.insert_attestations(
|
||||
test_task,
|
||||
&state,
|
||||
&all_secret_keys,
|
||||
num_attestations as usize,
|
||||
spec,
|
||||
)
|
||||
.unwrap();
|
||||
let block = self.block_builder.build(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
(block, state)
|
||||
}
|
||||
|
||||
pub fn build_with_attester_slashing(
|
||||
mut self,
|
||||
test_task: AttesterSlashingTestTask,
|
||||
num_attester_slashings: u64,
|
||||
randao_sk: Option<SecretKey>,
|
||||
previous_block_root: Option<Hash256>,
|
||||
spec: &ChainSpec,
|
||||
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
|
||||
let (state, keypairs) = (self.state, self.keypairs);
|
||||
let builder = &mut self.block_builder;
|
||||
|
||||
builder.set_slot(state.slot);
|
||||
|
||||
match previous_block_root {
|
||||
Some(root) => builder.set_parent_root(root),
|
||||
None => builder.set_parent_root(state.latest_block_header.tree_hash_root()),
|
||||
}
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
|
||||
let keypair = &keypairs[proposer_index];
|
||||
|
||||
builder.set_proposer_index(proposer_index as u64);
|
||||
|
||||
match randao_sk {
|
||||
Some(sk) => {
|
||||
builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
|
||||
}
|
||||
None => builder.set_randao_reveal(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
|
||||
let mut validator_indices = vec![];
|
||||
let mut secret_keys = vec![];
|
||||
for i in 0..num_attester_slashings {
|
||||
validator_indices.push(i);
|
||||
secret_keys.push(&keypairs[i as usize].sk);
|
||||
}
|
||||
|
||||
for _ in 0..num_attester_slashings {
|
||||
self.block_builder.insert_attester_slashing(
|
||||
test_task,
|
||||
&validator_indices,
|
||||
&secret_keys,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
}
|
||||
let block = self.block_builder.build(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
(block, state)
|
||||
}
|
||||
|
||||
pub fn build_with_proposer_slashing(
|
||||
mut self,
|
||||
test_task: ProposerSlashingTestTask,
|
||||
num_proposer_slashings: u64,
|
||||
randao_sk: Option<SecretKey>,
|
||||
previous_block_root: Option<Hash256>,
|
||||
spec: &ChainSpec,
|
||||
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
|
||||
let (state, keypairs) = (self.state, self.keypairs);
|
||||
let builder = &mut self.block_builder;
|
||||
|
||||
builder.set_slot(state.slot);
|
||||
|
||||
match previous_block_root {
|
||||
Some(root) => builder.set_parent_root(root),
|
||||
None => builder.set_parent_root(state.latest_block_header.tree_hash_root()),
|
||||
}
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
|
||||
let keypair = &keypairs[proposer_index];
|
||||
|
||||
builder.set_proposer_index(proposer_index as u64);
|
||||
|
||||
match randao_sk {
|
||||
Some(sk) => {
|
||||
builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
|
||||
}
|
||||
None => builder.set_randao_reveal(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
|
||||
for i in 0..num_proposer_slashings {
|
||||
let validator_indices = i;
|
||||
let secret_keys = &keypairs[i as usize].sk;
|
||||
self.block_builder.insert_proposer_slashing(
|
||||
test_task,
|
||||
validator_indices,
|
||||
&secret_keys,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
}
|
||||
let block = self.block_builder.build(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
(block, state)
|
||||
}
|
||||
|
||||
// NOTE: could remove optional args
|
||||
// NOTE: could return keypairs as well
|
||||
pub fn build(
|
||||
mut self,
|
||||
randao_sk: Option<SecretKey>,
|
||||
previous_block_root: Option<Hash256>,
|
||||
) -> (SignedBeaconBlock<T>, BeaconState<T>) {
|
||||
let (state, keypairs) = (self.state, self.keypairs);
|
||||
let spec = self.spec;
|
||||
let builder = &mut self.block_builder;
|
||||
|
||||
builder.set_slot(state.slot);
|
||||
|
||||
match previous_block_root {
|
||||
Some(root) => builder.set_parent_root(root),
|
||||
None => builder.set_parent_root(state.latest_block_header.tree_hash_root()),
|
||||
}
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
|
||||
let keypair = &keypairs[proposer_index];
|
||||
|
||||
builder.set_proposer_index(proposer_index as u64);
|
||||
|
||||
match randao_sk {
|
||||
Some(sk) => {
|
||||
builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
|
||||
}
|
||||
None => builder.set_randao_reveal(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
|
||||
let block = self.block_builder.build(
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
(block, state)
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ where
|
||||
let set = randao_signature_set(
|
||||
self.state,
|
||||
self.get_pubkey.clone(),
|
||||
&block.message,
|
||||
block.message(),
|
||||
self.spec,
|
||||
)?;
|
||||
self.sets.push(set);
|
||||
@@ -204,12 +204,12 @@ where
|
||||
/// Includes all signatures in `self.block.body.proposer_slashings` for verification.
|
||||
pub fn include_proposer_slashings(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
self.sets
|
||||
.reserve(block.message.body.proposer_slashings.len() * 2);
|
||||
.reserve(block.message().body().proposer_slashings().len() * 2);
|
||||
|
||||
block
|
||||
.message
|
||||
.body
|
||||
.proposer_slashings
|
||||
.message()
|
||||
.body()
|
||||
.proposer_slashings()
|
||||
.iter()
|
||||
.try_for_each(|proposer_slashing| {
|
||||
let (set_1, set_2) = proposer_slashing_signature_set(
|
||||
@@ -229,12 +229,12 @@ where
|
||||
/// Includes all signatures in `self.block.body.attester_slashings` for verification.
|
||||
pub fn include_attester_slashings(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
self.sets
|
||||
.reserve(block.message.body.attester_slashings.len() * 2);
|
||||
.reserve(block.message().body().attester_slashings().len() * 2);
|
||||
|
||||
block
|
||||
.message
|
||||
.body
|
||||
.attester_slashings
|
||||
.message()
|
||||
.body()
|
||||
.attester_slashings()
|
||||
.iter()
|
||||
.try_for_each(|attester_slashing| {
|
||||
let (set_1, set_2) = attester_slashing_signature_sets(
|
||||
@@ -256,15 +256,16 @@ where
|
||||
&mut self,
|
||||
block: &'a SignedBeaconBlock<T>,
|
||||
) -> Result<Vec<IndexedAttestation<T>>> {
|
||||
self.sets.reserve(block.message.body.attestations.len());
|
||||
self.sets
|
||||
.reserve(block.message().body().attestations().len());
|
||||
|
||||
block
|
||||
.message
|
||||
.body
|
||||
.attestations
|
||||
.message()
|
||||
.body()
|
||||
.attestations()
|
||||
.iter()
|
||||
.try_fold(
|
||||
Vec::with_capacity(block.message.body.attestations.len()),
|
||||
Vec::with_capacity(block.message().body().attestations().len()),
|
||||
|mut vec, attestation| {
|
||||
let committee = self
|
||||
.state
|
||||
@@ -290,12 +291,13 @@ where
|
||||
|
||||
/// Includes all signatures in `self.block.body.voluntary_exits` for verification.
|
||||
pub fn include_exits(&mut self, block: &'a SignedBeaconBlock<T>) -> Result<()> {
|
||||
self.sets.reserve(block.message.body.voluntary_exits.len());
|
||||
self.sets
|
||||
.reserve(block.message().body().voluntary_exits().len());
|
||||
|
||||
block
|
||||
.message
|
||||
.body
|
||||
.voluntary_exits
|
||||
.message()
|
||||
.body()
|
||||
.voluntary_exits()
|
||||
.iter()
|
||||
.try_for_each(|exit| {
|
||||
let exit =
|
||||
|
||||
@@ -11,6 +11,8 @@ use types::*;
|
||||
/// (e.g., when processing attestations instead of when processing deposits).
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum BlockProcessingError {
|
||||
/// Logic error indicating that the wrong state type was provided.
|
||||
IncorrectStateType,
|
||||
RandaoSignatureInvalid,
|
||||
BulkSignatureVerificationFailed,
|
||||
StateRootMismatch,
|
||||
@@ -45,11 +47,16 @@ pub enum BlockProcessingError {
|
||||
index: usize,
|
||||
reason: ExitInvalid,
|
||||
},
|
||||
SyncAggregateInvalid {
|
||||
reason: SyncAggregateInvalid,
|
||||
},
|
||||
BeaconStateError(BeaconStateError),
|
||||
SignatureSetError(SignatureSetError),
|
||||
SszTypesError(ssz_types::Error),
|
||||
MerkleTreeError(MerkleTreeError),
|
||||
ArithError(ArithError),
|
||||
InconsistentBlockFork(InconsistentFork),
|
||||
InconsistentStateFork(InconsistentFork),
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for BlockProcessingError {
|
||||
@@ -76,6 +83,12 @@ impl From<ArithError> for BlockProcessingError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SyncAggregateInvalid> for BlockProcessingError {
|
||||
fn from(reason: SyncAggregateInvalid) -> Self {
|
||||
BlockProcessingError::SyncAggregateInvalid { reason }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockOperationError<HeaderInvalid>> for BlockProcessingError {
|
||||
fn from(e: BlockOperationError<HeaderInvalid>) -> BlockProcessingError {
|
||||
match e {
|
||||
@@ -339,3 +352,11 @@ pub enum ExitInvalid {
|
||||
/// been invalid or an internal error occurred.
|
||||
SignatureSetError(SignatureSetError),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum SyncAggregateInvalid {
|
||||
/// One or more of the aggregate public keys is invalid.
|
||||
PubkeyInvalid,
|
||||
/// The signature is invalid.
|
||||
SignatureInvalid,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::errors::{BlockOperationError, IndexedAttestationInvalid as Invalid};
|
||||
use super::signature_sets::{get_pubkey_from_state, indexed_attestation_signature_set};
|
||||
use crate::VerifySignatures;
|
||||
use itertools::Itertools;
|
||||
use types::*;
|
||||
|
||||
type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
|
||||
@@ -10,8 +11,6 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
|
||||
}
|
||||
|
||||
/// Verify an `IndexedAttestation`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
pub fn is_valid_indexed_attestation<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
indexed_attestation: &IndexedAttestation<T>,
|
||||
@@ -25,13 +24,16 @@ pub fn is_valid_indexed_attestation<T: EthSpec>(
|
||||
|
||||
// Check that indices are sorted and unique
|
||||
let check_sorted = |list: &[u64]| -> Result<()> {
|
||||
list.windows(2).enumerate().try_for_each(|(i, pair)| {
|
||||
if pair[0] < pair[1] {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(error(Invalid::BadValidatorIndicesOrdering(i)))
|
||||
}
|
||||
})?;
|
||||
list.iter()
|
||||
.tuple_windows()
|
||||
.enumerate()
|
||||
.try_for_each(|(i, (x, y))| {
|
||||
if x < y {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(error(Invalid::BadValidatorIndicesOrdering(i)))
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
};
|
||||
check_sorted(indices)?;
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
use super::*;
|
||||
use crate::common::{
|
||||
altair::get_base_reward, get_attestation_participation_flag_indices, increase_balance,
|
||||
initiate_validator_exit, slash_validator,
|
||||
};
|
||||
use crate::per_block_processing::errors::{BlockProcessingError, IntoWithIndex};
|
||||
use crate::VerifySignatures;
|
||||
use safe_arith::SafeArith;
|
||||
use types::consts::altair::{PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, WEIGHT_DENOMINATOR};
|
||||
|
||||
pub fn process_operations<'a, T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
process_proposer_slashings(
|
||||
state,
|
||||
block_body.proposer_slashings(),
|
||||
verify_signatures,
|
||||
spec,
|
||||
)?;
|
||||
process_attester_slashings(
|
||||
state,
|
||||
block_body.attester_slashings(),
|
||||
verify_signatures,
|
||||
spec,
|
||||
)?;
|
||||
process_attestations(state, block_body, verify_signatures, spec)?;
|
||||
process_deposits(state, block_body.deposits(), spec)?;
|
||||
process_exits(state, block_body.voluntary_exits(), verify_signatures, spec)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub mod base {
|
||||
use super::*;
|
||||
|
||||
/// Validates each `Attestation` and updates the state, short-circuiting on an invalid object.
|
||||
///
|
||||
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||
/// an `Err` describing the invalid object or cause of failure.
|
||||
pub fn process_attestations<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
attestations: &[Attestation<T>],
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Ensure the previous epoch cache exists.
|
||||
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot(), spec)? as u64;
|
||||
|
||||
// Verify and apply each attestation.
|
||||
for (i, attestation) in attestations.iter().enumerate() {
|
||||
verify_attestation_for_block_inclusion(state, attestation, verify_signatures, spec)
|
||||
.map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
let pending_attestation = PendingAttestation {
|
||||
aggregation_bits: attestation.aggregation_bits.clone(),
|
||||
data: attestation.data.clone(),
|
||||
inclusion_delay: state.slot().safe_sub(attestation.data.slot)?.as_u64(),
|
||||
proposer_index,
|
||||
};
|
||||
|
||||
if attestation.data.target.epoch == state.current_epoch() {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.current_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
} else {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.previous_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod altair {
|
||||
use super::*;
|
||||
|
||||
pub fn process_attestations<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
attestations: &[Attestation<T>],
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
attestations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(i, attestation)| {
|
||||
process_attestation(state, attestation, i, verify_signatures, spec)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_attestation<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
attestation: &Attestation<T>,
|
||||
att_index: usize,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
||||
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
||||
|
||||
let indexed_attestation =
|
||||
verify_attestation_for_block_inclusion(state, attestation, verify_signatures, spec)
|
||||
.map_err(|e| e.into_with_index(att_index))?;
|
||||
|
||||
// Matching roots, participation flag indices
|
||||
let data = &attestation.data;
|
||||
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();
|
||||
let participation_flag_indices =
|
||||
get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?;
|
||||
|
||||
// Update epoch participation flags.
|
||||
let total_active_balance = state.get_total_active_balance(spec)?;
|
||||
let mut proposer_reward_numerator = 0;
|
||||
for index in &indexed_attestation.attesting_indices {
|
||||
let index = *index as usize;
|
||||
|
||||
for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {
|
||||
let epoch_participation = state.get_epoch_participation_mut(data.target.epoch)?;
|
||||
let validator_participation = epoch_participation
|
||||
.get_mut(index)
|
||||
.ok_or(BeaconStateError::ParticipationOutOfBounds(index))?;
|
||||
|
||||
if participation_flag_indices.contains(&flag_index)
|
||||
&& !validator_participation.has_flag(flag_index)?
|
||||
{
|
||||
validator_participation.add_flag(flag_index)?;
|
||||
proposer_reward_numerator.safe_add_assign(
|
||||
get_base_reward(state, index, total_active_balance, spec)?
|
||||
.safe_mul(weight)?,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let proposer_reward_denominator = WEIGHT_DENOMINATOR
|
||||
.safe_sub(PROPOSER_WEIGHT)?
|
||||
.safe_mul(WEIGHT_DENOMINATOR)?
|
||||
.safe_div(PROPOSER_WEIGHT)?;
|
||||
let proposer_reward = proposer_reward_numerator.safe_div(proposer_reward_denominator)?;
|
||||
// FIXME(altair): optimise by passing in proposer_index
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot(), spec)?;
|
||||
increase_balance(state, proposer_index, proposer_reward)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates each `ProposerSlashing` and updates the state, short-circuiting on an invalid object.
|
||||
///
|
||||
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||
/// an `Err` describing the invalid object or cause of failure.
|
||||
pub fn process_proposer_slashings<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
proposer_slashings: &[ProposerSlashing],
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Verify and apply proposer slashings in series.
|
||||
// We have to verify in series because an invalid block may contain multiple slashings
|
||||
// for the same validator, and we need to correctly detect and reject that.
|
||||
proposer_slashings
|
||||
.iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(i, proposer_slashing)| {
|
||||
verify_proposer_slashing(proposer_slashing, &state, verify_signatures, spec)
|
||||
.map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
slash_validator(
|
||||
state,
|
||||
proposer_slashing.signed_header_1.message.proposer_index as usize,
|
||||
None,
|
||||
spec,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Validates each `AttesterSlashing` and updates the state, short-circuiting on an invalid object.
|
||||
///
|
||||
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||
/// an `Err` describing the invalid object or cause of failure.
|
||||
pub fn process_attester_slashings<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
attester_slashings: &[AttesterSlashing<T>],
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
for (i, attester_slashing) in attester_slashings.iter().enumerate() {
|
||||
verify_attester_slashing(&state, &attester_slashing, verify_signatures, spec)
|
||||
.map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
let slashable_indices =
|
||||
get_slashable_indices(&state, &attester_slashing).map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
for i in slashable_indices {
|
||||
slash_validator(state, i as usize, None, spec)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Wrapper function to handle calling the correct version of `process_attestations` based on
|
||||
/// the fork.
|
||||
pub fn process_attestations<'a, T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
block_body: BeaconBlockBodyRef<'a, T>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
match block_body {
|
||||
BeaconBlockBodyRef::Base(_) => {
|
||||
base::process_attestations(state, block_body.attestations(), verify_signatures, spec)?;
|
||||
}
|
||||
BeaconBlockBodyRef::Altair(_) => {
|
||||
altair::process_attestations(
|
||||
state,
|
||||
block_body.attestations(),
|
||||
verify_signatures,
|
||||
spec,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates each `Exit` and updates the state, short-circuiting on an invalid object.
|
||||
///
|
||||
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||
/// an `Err` describing the invalid object or cause of failure.
|
||||
pub fn process_exits<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
voluntary_exits: &[SignedVoluntaryExit],
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
// Verify and apply each exit in series. We iterate in series because higher-index exits may
|
||||
// become invalid due to the application of lower-index ones.
|
||||
for (i, exit) in voluntary_exits.iter().enumerate() {
|
||||
verify_exit(&state, exit, verify_signatures, spec).map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
initiate_validator_exit(state, exit.message.validator_index as usize, spec)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
|
||||
///
|
||||
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||
/// an `Err` describing the invalid object or cause of failure.
|
||||
pub fn process_deposits<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
deposits: &[Deposit],
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
let expected_deposit_len = std::cmp::min(
|
||||
T::MaxDeposits::to_u64(),
|
||||
state.get_outstanding_deposit_len()?,
|
||||
);
|
||||
block_verify!(
|
||||
deposits.len() as u64 == expected_deposit_len,
|
||||
BlockProcessingError::DepositCountInvalid {
|
||||
expected: expected_deposit_len as usize,
|
||||
found: deposits.len(),
|
||||
}
|
||||
);
|
||||
|
||||
// Verify merkle proofs in parallel.
|
||||
deposits
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(i, deposit)| {
|
||||
verify_deposit_merkle_proof(
|
||||
state,
|
||||
deposit,
|
||||
state.eth1_deposit_index().safe_add(i as u64)?,
|
||||
spec,
|
||||
)
|
||||
.map_err(|e| e.into_with_index(i))
|
||||
})?;
|
||||
|
||||
// Update the state in series.
|
||||
for deposit in deposits {
|
||||
process_deposit(state, deposit, spec, false)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process a single deposit, optionally verifying its merkle proof.
|
||||
pub fn process_deposit<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
deposit: &Deposit,
|
||||
spec: &ChainSpec,
|
||||
verify_merkle_proof: bool,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
let deposit_index = state.eth1_deposit_index() as usize;
|
||||
if verify_merkle_proof {
|
||||
verify_deposit_merkle_proof(state, deposit, state.eth1_deposit_index(), spec)
|
||||
.map_err(|e| e.into_with_index(deposit_index))?;
|
||||
}
|
||||
|
||||
state.eth1_deposit_index_mut().safe_add_assign(1)?;
|
||||
|
||||
// Get an `Option<u64>` where `u64` is the validator index if this deposit public key
|
||||
// already exists in the beacon_state.
|
||||
let validator_index = get_existing_validator_index(state, &deposit.data.pubkey)
|
||||
.map_err(|e| e.into_with_index(deposit_index))?;
|
||||
|
||||
let amount = deposit.data.amount;
|
||||
|
||||
if let Some(index) = validator_index {
|
||||
// Update the existing validator balance.
|
||||
increase_balance(state, index as usize, amount)?;
|
||||
} else {
|
||||
// The signature should be checked for new validators. Return early for a bad
|
||||
// signature.
|
||||
if verify_deposit_signature(&deposit.data, spec).is_err() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Create a new validator.
|
||||
let validator = Validator {
|
||||
pubkey: deposit.data.pubkey,
|
||||
withdrawal_credentials: deposit.data.withdrawal_credentials,
|
||||
activation_eligibility_epoch: spec.far_future_epoch,
|
||||
activation_epoch: spec.far_future_epoch,
|
||||
exit_epoch: spec.far_future_epoch,
|
||||
withdrawable_epoch: spec.far_future_epoch,
|
||||
effective_balance: std::cmp::min(
|
||||
amount.safe_sub(amount.safe_rem(spec.effective_balance_increment)?)?,
|
||||
spec.max_effective_balance,
|
||||
),
|
||||
slashed: false,
|
||||
};
|
||||
state.validators_mut().push(validator)?;
|
||||
state.balances_mut().push(deposit.data.amount)?;
|
||||
|
||||
// Altair-specific initializations.
|
||||
if let BeaconState::Altair(altair_state) = state {
|
||||
altair_state
|
||||
.previous_epoch_participation
|
||||
.push(ParticipationFlags::default())?;
|
||||
altair_state
|
||||
.current_epoch_participation
|
||||
.push(ParticipationFlags::default())?;
|
||||
altair_state.inactivity_scores.push(0)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -7,10 +7,10 @@ use ssz::DecodeError;
|
||||
use std::borrow::Cow;
|
||||
use tree_hash::TreeHash;
|
||||
use types::{
|
||||
AggregateSignature, AttesterSlashing, BeaconBlock, BeaconState, BeaconStateError, ChainSpec,
|
||||
DepositData, Domain, EthSpec, Fork, Hash256, IndexedAttestation, ProposerSlashing, PublicKey,
|
||||
Signature, SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockHeader, SignedRoot,
|
||||
SignedVoluntaryExit, SigningData,
|
||||
AggregateSignature, AttesterSlashing, BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec,
|
||||
DepositData, Domain, EthSpec, Fork, Hash256, InconsistentFork, IndexedAttestation,
|
||||
ProposerSlashing, PublicKey, Signature, SignedAggregateAndProof, SignedBeaconBlock,
|
||||
SignedBeaconBlockHeader, SignedRoot, SignedVoluntaryExit, SigningData,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -35,6 +35,8 @@ pub enum Error {
|
||||
/// The public key bytes stored in the `BeaconState` were not valid. This is a serious internal
|
||||
/// error.
|
||||
BadBlsBytes { validator_index: u64 },
|
||||
/// The block structure is not appropriate for the fork at `block.slot()`.
|
||||
InconsistentBlockFork(InconsistentFork),
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for Error {
|
||||
@@ -52,7 +54,7 @@ where
|
||||
T: EthSpec,
|
||||
{
|
||||
state
|
||||
.validators
|
||||
.validators()
|
||||
.get(validator_index)
|
||||
.and_then(|v| {
|
||||
let pk: Option<PublicKey> = v.pubkey.decompress().ok();
|
||||
@@ -73,21 +75,26 @@ where
|
||||
T: EthSpec,
|
||||
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let block = &signed_block.message;
|
||||
let proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
|
||||
// Verify that the `SignedBeaconBlock` instantiation matches the fork at `signed_block.slot()`.
|
||||
signed_block
|
||||
.fork_name(spec)
|
||||
.map_err(Error::InconsistentBlockFork)?;
|
||||
|
||||
if proposer_index as u64 != block.proposer_index {
|
||||
let block = signed_block.message();
|
||||
let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?;
|
||||
|
||||
if proposer_index as u64 != block.proposer_index() {
|
||||
return Err(Error::IncorrectBlockProposer {
|
||||
block: block.proposer_index,
|
||||
block: block.proposer_index(),
|
||||
local_shuffling: proposer_index as u64,
|
||||
});
|
||||
}
|
||||
|
||||
let domain = spec.get_domain(
|
||||
block.slot.epoch(T::slots_per_epoch()),
|
||||
block.slot().epoch(T::slots_per_epoch()),
|
||||
Domain::BeaconProposer,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = if let Some(root) = block_root {
|
||||
@@ -101,7 +108,7 @@ where
|
||||
};
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
&signed_block.signature,
|
||||
signed_block.signature(),
|
||||
get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
message,
|
||||
))
|
||||
@@ -111,26 +118,29 @@ where
|
||||
pub fn randao_signature_set<'a, T, F>(
|
||||
state: &'a BeaconState<T>,
|
||||
get_pubkey: F,
|
||||
block: &'a BeaconBlock<T>,
|
||||
block: BeaconBlockRef<'a, T>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
T: EthSpec,
|
||||
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
|
||||
let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?;
|
||||
|
||||
let domain = spec.get_domain(
|
||||
block.slot.epoch(T::slots_per_epoch()),
|
||||
block.slot().epoch(T::slots_per_epoch()),
|
||||
Domain::Randao,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = block.slot.epoch(T::slots_per_epoch()).signing_root(domain);
|
||||
let message = block
|
||||
.slot()
|
||||
.epoch(T::slots_per_epoch())
|
||||
.signing_root(domain);
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
&block.body.randao_reveal,
|
||||
block.body().randao_reveal(),
|
||||
get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
|
||||
message,
|
||||
))
|
||||
@@ -177,8 +187,8 @@ fn block_header_signature_set<'a, T: EthSpec>(
|
||||
let domain = spec.get_domain(
|
||||
signed_header.message.slot.epoch(T::slots_per_epoch()),
|
||||
Domain::BeaconProposer,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = signed_header.message.signing_root(domain);
|
||||
@@ -208,8 +218,8 @@ where
|
||||
let domain = spec.get_domain(
|
||||
indexed_attestation.data.target.epoch,
|
||||
Domain::BeaconAttester,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = indexed_attestation.data.signing_root(domain);
|
||||
@@ -309,8 +319,8 @@ where
|
||||
let domain = spec.get_domain(
|
||||
exit.epoch,
|
||||
Domain::VoluntaryExit,
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = exit.signing_root(domain);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,28 +15,26 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
|
||||
/// to `state`. Otherwise, returns a descriptive `Err`.
|
||||
///
|
||||
/// Optionally verifies the aggregate signature, depending on `verify_signatures`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
attestation: &Attestation<T>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<()> {
|
||||
) -> Result<IndexedAttestation<T>> {
|
||||
let data = &attestation.data;
|
||||
|
||||
verify!(
|
||||
data.slot.safe_add(spec.min_attestation_inclusion_delay)? <= state.slot,
|
||||
data.slot.safe_add(spec.min_attestation_inclusion_delay)? <= state.slot(),
|
||||
Invalid::IncludedTooEarly {
|
||||
state: state.slot,
|
||||
state: state.slot(),
|
||||
delay: spec.min_attestation_inclusion_delay,
|
||||
attestation: data.slot,
|
||||
}
|
||||
);
|
||||
verify!(
|
||||
state.slot <= data.slot.safe_add(T::slots_per_epoch())?,
|
||||
state.slot() <= data.slot.safe_add(T::slots_per_epoch())?,
|
||||
Invalid::IncludedTooLate {
|
||||
state: state.slot,
|
||||
state: state.slot(),
|
||||
attestation: data.slot,
|
||||
}
|
||||
);
|
||||
@@ -56,7 +54,7 @@ pub fn verify_attestation_for_state<T: EthSpec>(
|
||||
attestation: &Attestation<T>,
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<()> {
|
||||
) -> Result<IndexedAttestation<T>> {
|
||||
let data = &attestation.data;
|
||||
|
||||
verify!(
|
||||
@@ -72,7 +70,7 @@ pub fn verify_attestation_for_state<T: EthSpec>(
|
||||
let indexed_attestation = get_indexed_attestation(committee.committee, attestation)?;
|
||||
is_valid_indexed_attestation(state, &indexed_attestation, verify_signatures, spec)?;
|
||||
|
||||
Ok(())
|
||||
Ok(indexed_attestation)
|
||||
}
|
||||
|
||||
/// Check target epoch and source checkpoint.
|
||||
@@ -92,9 +90,9 @@ fn verify_casper_ffg_vote<T: EthSpec>(
|
||||
);
|
||||
if data.target.epoch == state.current_epoch() {
|
||||
verify!(
|
||||
data.source == state.current_justified_checkpoint,
|
||||
data.source == state.current_justified_checkpoint(),
|
||||
Invalid::WrongJustifiedCheckpoint {
|
||||
state: state.current_justified_checkpoint,
|
||||
state: state.current_justified_checkpoint(),
|
||||
attestation: data.source,
|
||||
is_current: true,
|
||||
}
|
||||
@@ -102,9 +100,9 @@ fn verify_casper_ffg_vote<T: EthSpec>(
|
||||
Ok(())
|
||||
} else if data.target.epoch == state.previous_epoch() {
|
||||
verify!(
|
||||
data.source == state.previous_justified_checkpoint,
|
||||
data.source == state.previous_justified_checkpoint(),
|
||||
Invalid::WrongJustifiedCheckpoint {
|
||||
state: state.previous_justified_checkpoint,
|
||||
state: state.previous_justified_checkpoint(),
|
||||
attestation: data.source,
|
||||
is_current: false,
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ where
|
||||
|
||||
for index in &attesting_indices_1 & &attesting_indices_2 {
|
||||
let validator = state
|
||||
.validators
|
||||
.validators()
|
||||
.get(index as usize)
|
||||
.ok_or_else(|| error(Invalid::UnknownValidator(index)))?;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ pub fn verify_deposit_merkle_proof<T: EthSpec>(
|
||||
&deposit.proof[..],
|
||||
spec.deposit_contract_tree_depth.safe_add(1)? as usize,
|
||||
deposit_index as usize,
|
||||
state.eth1_data.deposit_root,
|
||||
state.eth1_data().deposit_root,
|
||||
),
|
||||
DepositInvalid::BadMerkleProof
|
||||
);
|
||||
|
||||
@@ -52,7 +52,7 @@ fn verify_exit_parametric<T: EthSpec>(
|
||||
let exit = &signed_exit.message;
|
||||
|
||||
let validator = state
|
||||
.validators
|
||||
.validators()
|
||||
.get(exit.validator_index as usize)
|
||||
.ok_or_else(|| error(ExitInvalid::ValidatorUnknown(exit.validator_index)))?;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn verify_proposer_slashing<T: EthSpec>(
|
||||
|
||||
// Check proposer is slashable
|
||||
let proposer = state
|
||||
.validators
|
||||
.validators()
|
||||
.get(header_1.proposer_index as usize)
|
||||
.ok_or_else(|| error(Invalid::ProposerUnknown(header_1.proposer_index)))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user