From a627a5b0e1b2440d5bea7f5bb3f553247a75c6e2 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 18 Apr 2024 11:56:33 -0600 Subject: [PATCH] Write helpers for electra --- .../src/electra/block_processing.rs | 114 + ethereum-consensus/src/electra/fork.rs | 62 +- ethereum-consensus/src/electra/genesis.rs | 57 + ethereum-consensus/src/electra/helpers.rs | 709 ++- ethereum-consensus/src/electra/mod.rs | 2 + .../src/electra/presets/mainnet.rs | 2 +- .../src/electra/presets/minimal.rs | 2 +- ethereum-consensus/src/electra/spec/mod.rs | 4035 ++++++++++++++++- spec-gen/src/generator.rs | 13 +- 9 files changed, 4949 insertions(+), 47 deletions(-) create mode 100644 ethereum-consensus/src/electra/block_processing.rs create mode 100644 ethereum-consensus/src/electra/genesis.rs diff --git a/ethereum-consensus/src/electra/block_processing.rs b/ethereum-consensus/src/electra/block_processing.rs new file mode 100644 index 000000000..2de95162f --- /dev/null +++ b/ethereum-consensus/src/electra/block_processing.rs @@ -0,0 +1,114 @@ +use crate::{ + electra::{Attestation, BeaconBlockBody, BeaconState}, + state_transition::Context, + Error, +}; + +pub fn process_attestation< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_COMMITTEES_PER_SLOT: usize, +>( + _state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + _attestation: &Attestation, + _context: &Context, +) -> Result<(), Error> { + todo!() +} + +pub fn process_execution_payload< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + _state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + _body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + _context: &Context, +) -> Result<(), Error> { + todo!(); +} diff --git a/ethereum-consensus/src/electra/fork.rs b/ethereum-consensus/src/electra/fork.rs index b98667664..dcba352d3 100644 --- a/ethereum-consensus/src/electra/fork.rs +++ b/ethereum-consensus/src/electra/fork.rs @@ -13,6 +13,7 @@ use crate::{ phase0::{helpers::compute_activation_exit_epoch, Fork}, primitives::FAR_FUTURE_EPOCH, state_transition::Context, + Error, }; pub fn upgrade_to_electra< @@ -43,20 +44,23 @@ pub fn upgrade_to_electra< MAX_EXTRA_DATA_BYTES, >, context: &Context, -) -> BeaconState< - SLOTS_PER_HISTORICAL_ROOT, - HISTORICAL_ROOTS_LIMIT, - ETH1_DATA_VOTES_BOUND, - VALIDATOR_REGISTRY_LIMIT, - EPOCHS_PER_HISTORICAL_VECTOR, - EPOCHS_PER_SLASHINGS_VECTOR, - MAX_VALIDATORS_PER_COMMITTEE, - SYNC_COMMITTEE_SIZE, - BYTES_PER_LOGS_BLOOM, - MAX_EXTRA_DATA_BYTES, - PENDING_BALANCE_DEPOSITS_LIMIT, - PENDING_PARTIAL_WITHDRAWALS_LIMIT, - PENDING_CONSOLIDATIONS_LIMIT, +) -> Result< + BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + Error, > { let epoch = deneb::get_current_epoch(state, context); let latest_execution_payload_header = &state.latest_execution_payload_header; @@ -90,7 +94,7 @@ pub fn upgrade_to_electra< .or(Some(epoch)); let earliest_exit_epoch = exit_epoch.unwrap() + 1; - let post = BeaconState { + let mut post = BeaconState { genesis_time: state.genesis_time, genesis_validators_root: state.genesis_validators_root, slot: state.slot, @@ -125,14 +129,16 @@ pub fn upgrade_to_electra< historical_summaries: state.historical_summaries.clone(), deposit_receipts_start_index: UNSET_DEPOSIT_RECEIPTS_START_INDEX, deposit_balance_to_consume: 0, - exit_balance_to_consume: get_activation_exit_churn_limit(), + exit_balance_to_consume: 0, earliest_exit_epoch, - consolidation_balance_to_consume: get_consolidation_churn_limit(), + consolidation_balance_to_consume: 0, earliest_consolidation_epoch: compute_activation_exit_epoch(epoch, context), pending_balance_deposits: Default::default(), pending_partial_withdrawals: Default::default(), pending_consolidations: Default::default(), }; + post.exit_balance_to_consume = get_activation_exit_churn_limit(&post, context)?; + post.consolidation_balance_to_consume = get_consolidation_churn_limit(&post, context)?; let mut pre_activation_validators = post .validators @@ -149,14 +155,24 @@ pub fn upgrade_to_electra< pre_activation_validators.sort(); for (_, index) in pre_activation_validators { - queue_entire_balance_and_reset_validator(index); + queue_entire_balance_and_reset_validator(&mut post, index); } - for (index, validator) in post.validators.iter().enumerate() { - if has_compounding_withdrawal_credential(validator) { - queue_excess_active_balance(index); - } + let indices_to_queue = post + .validators + .iter() + .enumerate() + .filter_map(|(index, validator)| { + if has_compounding_withdrawal_credential(validator) { + Some(index) + } else { + None + } + }) + .collect::>(); + for index in indices_to_queue { + queue_excess_active_balance(&mut post, index, context)?; } - post + Ok(post) } diff --git a/ethereum-consensus/src/electra/genesis.rs b/ethereum-consensus/src/electra/genesis.rs new file mode 100644 index 000000000..2c4625713 --- /dev/null +++ b/ethereum-consensus/src/electra/genesis.rs @@ -0,0 +1,57 @@ +use crate::{ + electra::{BeaconState, Deposit, ExecutionPayloadHeader}, + primitives::Hash32, + state_transition::{Context, Result}, +}; + +pub fn initialize_beacon_state_from_eth1< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, +>( + _eth1_block_hash: Hash32, + _eth1_timestamp: u64, + _deposits: &[Deposit], + _execution_payload_header: Option< + &ExecutionPayloadHeader, + >, + _context: &Context, +) -> Result< + BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, +> { + todo!() +} diff --git a/ethereum-consensus/src/electra/helpers.rs b/ethereum-consensus/src/electra/helpers.rs index 16298d18b..491f5da92 100644 --- a/ethereum-consensus/src/electra/helpers.rs +++ b/ethereum-consensus/src/electra/helpers.rs @@ -1,31 +1,714 @@ use crate::{ - phase0::Validator, - primitives::{CommitteeIndex, Gwei, ValidatorIndex}, + altair::{PROPOSER_WEIGHT, WEIGHT_DENOMINATOR}, + capella::has_eth1_withdrawal_credential, + electra::{ + beacon_state::{BeaconState, PendingBalanceDeposit}, + decrease_balance, get_beacon_committee, get_beacon_proposer_index, get_current_epoch, + get_total_active_balance, increase_balance, + operations::{Attestation, IndexedAttestation}, + }, + phase0::{compute_activation_exit_epoch, Validator}, + primitives::{ + Bytes32, CommitteeIndex, Epoch, Gwei, ValidatorIndex, COMPOUNDING_WITHDRAWAL_PREFIX, + FAR_FUTURE_EPOCH, + }, ssz::prelude::*, + state_transition::Context, + Error, }; +use std::collections::HashSet; + +pub fn is_eligible_for_activation_queue(validator: &Validator, context: &Context) -> bool { + let is_not_yet_eligible = validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH; + let has_min_activation_balance = validator.effective_balance >= context.min_activation_balance; + is_not_yet_eligible && has_min_activation_balance +} + +pub fn is_compounding_withdrawal_credential(withdrawal_credentials: &Bytes32) -> bool { + withdrawal_credentials[0] == COMPOUNDING_WITHDRAWAL_PREFIX +} + +pub fn has_compounding_withdrawal_credential(validator: &Validator) -> bool { + is_compounding_withdrawal_credential(&validator.withdrawal_credentials) +} + +pub fn has_execution_withdrawal_credential(validator: &Validator) -> bool { + has_compounding_withdrawal_credential(validator) || has_eth1_withdrawal_credential(validator) +} + +pub fn is_fully_withdrawable_validator(validator: &Validator, balance: Gwei, epoch: Epoch) -> bool { + has_execution_withdrawal_credential(validator) && + validator.withdrawable_epoch <= epoch && + balance > 0 +} + +pub fn is_partially_withdrawable_validator( + validator: &Validator, + balance: Gwei, + context: &Context, +) -> bool { + let max_effective_balance = get_validator_max_effective_balance(validator, context); + let has_max_effective_balance = validator.effective_balance == max_effective_balance; + let has_excess_balance = balance > max_effective_balance; + has_execution_withdrawal_credential(validator) && + has_max_effective_balance && + has_excess_balance +} pub fn get_committee_indices( - committee_bits: Bitvector, + committee_bits: &Bitvector, ) -> Vec { committee_bits.iter().enumerate().flat_map(|(i, bit)| bit.then_some(i)).collect() } -pub fn get_activation_exit_churn_limit() -> Gwei { - todo!() +pub fn get_validator_max_effective_balance(validator: &Validator, context: &Context) -> Gwei { + if has_compounding_withdrawal_credential(validator) { + context.max_effective_balance_electra + } else { + context.min_activation_balance + } } -pub fn get_consolidation_churn_limit() -> Gwei { - todo!() +pub fn get_balance_churn_limit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + let churn_limit = get_total_active_balance(state, context)? / context.churn_limit_quotient; + let churn = context.min_per_epoch_churn_limit_electra.max(churn_limit); + Ok(churn - churn % context.effective_balance_increment) } -pub fn queue_entire_balance_and_reset_validator(_index: ValidatorIndex) { - todo!() +pub fn get_activation_exit_churn_limit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + get_balance_churn_limit(state, context) + .map(|churn_limit| context.max_per_epoch_activation_exit_churn_limit.min(churn_limit)) } -pub fn has_compounding_withdrawal_credential(_validator: &Validator) -> bool { - todo!() +pub fn get_consolidation_churn_limit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + Ok(get_balance_churn_limit(state, context)? - get_activation_exit_churn_limit(state, context)?) +} + +pub fn get_active_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + validator_index: ValidatorIndex, + context: &Context, +) -> Gwei { + let max_effective_balance = + get_validator_max_effective_balance(&state.validators[validator_index], context); + state.balances[validator_index].min(max_effective_balance) +} + +pub fn get_pending_balance_to_withdraw< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + validator_index: ValidatorIndex, +) -> Gwei { + state + .pending_partial_withdrawals + .iter() + .filter_map(|withdrawal| { + if withdrawal.index == validator_index { + Some(withdrawal.amount) + } else { + None + } + }) + .sum() +} + +pub fn get_attesting_indices< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_COMMITTEES_PER_SLOT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + attestation: &Attestation, + context: &Context, +) -> Result, Error> { + let committee_indices = get_committee_indices(&attestation.committee_bits); + + let mut indices = HashSet::with_capacity(MAX_VALIDATORS_PER_SLOT); + + let mut committee_offset = 0; + + for index in committee_indices { + let committee = get_beacon_committee(state, attestation.data.slot, index, context)?; + for (i, validator_index) in committee.iter().enumerate() { + if attestation.aggregation_bits[committee_offset + i] { + indices.insert(*validator_index); + } + } + committee_offset += 1; + } + + Ok(indices) +} + +pub fn get_indexed_attestation< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_COMMITTEES_PER_SLOT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + attestation: &Attestation, + context: &Context, +) -> Result, Error> { + let mut attesting_indices = + get_attesting_indices(state, &attestation, context)?.into_iter().collect::>(); + // NOTE: `attesting_indices` has no duplicates by contract, and so unstable sort is fine. + attesting_indices.sort_unstable(); + let attesting_indices = attesting_indices.try_into().map_err(|(_, err)| err)?; + Ok(IndexedAttestation { + attesting_indices, + data: attestation.data.clone(), + signature: attestation.signature.clone(), + }) +} + +pub fn initiate_validator_exit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + context: &Context, +) -> Result<(), Error> { + if state.validators[index].exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()) + } + + let exit_queue_epoch = compute_exit_epoch_and_update_churn( + state, + state.validators[index].effective_balance, + context, + )?; + + state.validators[index].exit_epoch = exit_queue_epoch; + state.validators[index].withdrawable_epoch = state.validators[index] + .exit_epoch + .checked_add(context.min_validator_withdrawability_delay) + .ok_or(Error::Overflow)?; + Ok(()) +} + +pub fn switch_to_compounding_validator< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_COMMITTEES_PER_SLOT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + context: &Context, +) -> Result<(), Error> { + if has_eth1_withdrawal_credential(&state.validators[index]) { + state.validators[index].withdrawal_credentials[0] = COMPOUNDING_WITHDRAWAL_PREFIX; + queue_excess_active_balance(state, index, context)?; + } + Ok(()) +} + +pub fn queue_excess_active_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + context: &Context, +) -> Result<(), Error> { + let balance = state.balances[index]; + if balance > context.min_activation_balance { + let excess_balance = + balance.checked_sub(context.min_activation_balance).ok_or(Error::Underflow)?; + state.balances[index] = context.min_activation_balance; + state.pending_balance_deposits.push(PendingBalanceDeposit { index, amount: excess_balance }) + } + Ok(()) +} + +pub fn queue_entire_balance_and_reset_validator< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, +) { + let balance = state.balances[index]; + state.balances[index] = 0; + + let validator = &mut state.validators[index]; + validator.effective_balance = 0; + validator.activation_eligibility_epoch = FAR_FUTURE_EPOCH; + state.pending_balance_deposits.push(PendingBalanceDeposit { index, amount: balance }); +} + +pub fn compute_exit_epoch_and_update_churn< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + exit_balance: Gwei, + context: &Context, +) -> Result { + let current_epoch = get_current_epoch(state, context); + let activation_exit_epoch = compute_activation_exit_epoch(current_epoch, context); + let mut earliest_exit_epoch = state.earliest_exit_epoch.max(activation_exit_epoch); + let per_epoch_churn = get_activation_exit_churn_limit(state, context)?; + let mut exit_balance_to_consume = if state.earliest_exit_epoch < earliest_exit_epoch { + per_epoch_churn + } else { + state.exit_balance_to_consume + }; + + if exit_balance > exit_balance_to_consume { + let balance_to_process = exit_balance - exit_balance_to_consume; + let additional_epochs = (balance_to_process - 1) / per_epoch_churn + 1; + earliest_exit_epoch += additional_epochs; + exit_balance_to_consume += additional_epochs * per_epoch_churn; + } + + state.exit_balance_to_consume = exit_balance_to_consume - exit_balance; + state.earliest_exit_epoch = earliest_exit_epoch; + + Ok(state.earliest_exit_epoch) +} + +pub fn compute_consolidation_epoch_and_update_churn< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + consolidation_balance: Gwei, + context: &Context, +) -> Result { + let current_epoch = get_current_epoch(state, context); + let activation_exit_epoch = compute_activation_exit_epoch(current_epoch, context); + let mut earliest_consolidation_epoch = + state.earliest_consolidation_epoch.max(activation_exit_epoch); + let per_epoch_churn = get_activation_exit_churn_limit(state, context)?; + let mut consolidation_balance_to_consume = + if state.earliest_consolidation_epoch < earliest_consolidation_epoch { + per_epoch_churn + } else { + state.consolidation_balance_to_consume + }; + + if consolidation_balance > consolidation_balance_to_consume { + let balance_to_process = consolidation_balance - consolidation_balance_to_consume; + let additional_epochs = (balance_to_process - 1) / per_epoch_churn + 1; + earliest_consolidation_epoch += additional_epochs; + consolidation_balance_to_consume += additional_epochs * per_epoch_churn; + } + + state.consolidation_balance_to_consume = + consolidation_balance_to_consume - consolidation_balance; + state.earliest_consolidation_epoch = earliest_consolidation_epoch; + + Ok(state.earliest_consolidation_epoch) } -pub fn queue_excess_active_balance(_index: ValidatorIndex) { - todo!() +pub fn slash_validator< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + slashed_index: ValidatorIndex, + whistleblower_index: Option, + context: &Context, +) -> Result<(), Error> { + let epoch = get_current_epoch(state, context); + initiate_validator_exit(state, slashed_index, context)?; + state.validators[slashed_index].slashed = true; + state.validators[slashed_index].withdrawable_epoch = u64::max( + state.validators[slashed_index].withdrawable_epoch, + epoch + context.epochs_per_slashings_vector, + ); + let slashings_index = epoch as usize % EPOCHS_PER_SLASHINGS_VECTOR; + state.slashings[slashings_index] += state.validators[slashed_index].effective_balance; + decrease_balance( + state, + slashed_index, + state.validators[slashed_index].effective_balance / + context.min_slashing_penalty_quotient_electra, + ); + let proposer_index = get_beacon_proposer_index(state, context)?; + let whistleblower_index = whistleblower_index.unwrap_or(proposer_index); + let whistleblower_reward = state.validators[slashed_index].effective_balance / + context.whistleblower_reward_quotient_electra; + let proposer_reward_scaling_factor = PROPOSER_WEIGHT / WEIGHT_DENOMINATOR; + let proposer_reward = whistleblower_reward * proposer_reward_scaling_factor; + increase_balance(state, proposer_index, proposer_reward); + increase_balance(state, whistleblower_index, whistleblower_reward - proposer_reward); + Ok(()) } diff --git a/ethereum-consensus/src/electra/mod.rs b/ethereum-consensus/src/electra/mod.rs index bf2f0397d..d833169c2 100644 --- a/ethereum-consensus/src/electra/mod.rs +++ b/ethereum-consensus/src/electra/mod.rs @@ -1,8 +1,10 @@ pub mod beacon_block; pub mod beacon_state; +pub mod block_processing; pub mod constants; pub mod execution_payload; pub mod fork; +pub mod genesis; pub mod helpers; pub mod operations; pub mod presets; diff --git a/ethereum-consensus/src/electra/presets/mainnet.rs b/ethereum-consensus/src/electra/presets/mainnet.rs index 33dc9bbd1..3a0061c0c 100644 --- a/ethereum-consensus/src/electra/presets/mainnet.rs +++ b/ethereum-consensus/src/electra/presets/mainnet.rs @@ -1,5 +1,5 @@ pub use crate::electra::presets::Preset; -use crate::{electra::spec, primitives::Gwei}; +use crate::electra::spec; pub use spec::*; diff --git a/ethereum-consensus/src/electra/presets/minimal.rs b/ethereum-consensus/src/electra/presets/minimal.rs index 5e9ebbc39..690cb99b5 100644 --- a/ethereum-consensus/src/electra/presets/minimal.rs +++ b/ethereum-consensus/src/electra/presets/minimal.rs @@ -1,5 +1,5 @@ pub use crate::electra::presets::Preset; -use crate::{electra::spec, primitives::Gwei}; +use crate::electra::spec; pub use spec::*; diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs index d1e2b7847..29dd19c77 100644 --- a/ethereum-consensus/src/electra/spec/mod.rs +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -1,8 +1,4029 @@ -pub use crate::electra::{ - beacon_block::{BeaconBlock, BeaconBlockBody, SignedBeaconBlock}, - beacon_state::{BeaconState, DepositReceipt, ExecutionLayerWithdrawalRequest}, - constants::UNSET_DEPOSIT_RECEIPTS_START_INDEX, - execution_payload::{ExecutionPayload, ExecutionPayloadHeader}, - helpers::get_committee_indices, - operations::{Attestation, IndexedAttestation}, +//! WARNING: This file was derived by the `spec-gen` utility. DO NOT EDIT MANUALLY. +pub use crate::{ + altair::{ + constants::{ + PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, SYNC_COMMITTEE_SUBNET_COUNT, + SYNC_REWARD_WEIGHT, TIMELY_HEAD_FLAG_INDEX, TIMELY_HEAD_WEIGHT, + TIMELY_SOURCE_FLAG_INDEX, TIMELY_SOURCE_WEIGHT, TIMELY_TARGET_FLAG_INDEX, + TIMELY_TARGET_WEIGHT, WEIGHT_DENOMINATOR, + }, + helpers::{add_flag, has_flag}, + light_client::{ + CURRENT_SYNC_COMMITTEE_INDEX, CURRENT_SYNC_COMMITTEE_INDEX_FLOOR_LOG_2, + FINALIZED_ROOT_INDEX, FINALIZED_ROOT_INDEX_FLOOR_LOG_2, NEXT_SYNC_COMMITTEE_INDEX, + NEXT_SYNC_COMMITTEE_INDEX_FLOOR_LOG_2, + }, + sync::{SyncAggregate, SyncCommittee}, + validator::{ + ContributionAndProof, SignedContributionAndProof, SyncAggregatorSelectionData, + SyncCommitteeContribution, SyncCommitteeMessage, + }, + }, + bellatrix::{execution_payload::Transaction, fork_choice::PowBlock}, + capella::{ + bls_to_execution_change::{BlsToExecutionChange, SignedBlsToExecutionChange}, + helpers::has_eth1_withdrawal_credential, + light_client::{EXECUTION_PAYLOAD_INDEX, EXECUTION_PAYLOAD_INDEX_FLOOR_LOG_2}, + withdrawal::Withdrawal, + }, + deneb::{ + blinded_beacon_block::{ + BlindedBeaconBlock, BlindedBeaconBlockBody, SignedBlindedBeaconBlock, + }, + blob_sidecar::{ + verify_blob_sidecar_inclusion_proof, Blob, BlobIdentifier, BlobSidecar, BlobsBundle, + VERSIONED_HASH_VERSION_KZG, + }, + execution_engine::NewPayloadRequest, + helpers::kzg_commitment_to_versioned_hash, + light_client::{ + LightClientBootstrap, LightClientFinalityUpdate, LightClientHeader, + LightClientOptimisticUpdate, LightClientUpdate, + }, + }, + electra::{ + beacon_block::{BeaconBlock, BeaconBlockBody, SignedBeaconBlock}, + beacon_state::{ + BeaconState, DepositReceipt, ExecutionLayerWithdrawalRequest, PendingBalanceDeposit, + PendingConsolidation, PendingPartialWithdrawal, + }, + block_processing::{process_attestation, process_execution_payload}, + constants::{FULL_EXIT_REQUEST_AMOUNT, UNSET_DEPOSIT_RECEIPTS_START_INDEX}, + execution_payload::{ExecutionPayload, ExecutionPayloadHeader}, + fork::upgrade_to_electra, + genesis::initialize_beacon_state_from_eth1, + helpers::{ + compute_consolidation_epoch_and_update_churn, compute_exit_epoch_and_update_churn, + get_activation_exit_churn_limit, get_active_balance, get_attesting_indices, + get_balance_churn_limit, get_committee_indices, get_consolidation_churn_limit, + get_indexed_attestation, get_pending_balance_to_withdraw, + get_validator_max_effective_balance, has_compounding_withdrawal_credential, + has_execution_withdrawal_credential, initiate_validator_exit, + is_compounding_withdrawal_credential, is_eligible_for_activation_queue, + is_fully_withdrawable_validator, is_partially_withdrawable_validator, + queue_entire_balance_and_reset_validator, queue_excess_active_balance, slash_validator, + switch_to_compounding_validator, + }, + operations::{ + Attestation, AttesterSlashing, Consolidation, IndexedAttestation, SignedConsolidation, + }, + }, + error::*, + phase0::{ + beacon_block::{BeaconBlockHeader, SignedBeaconBlockHeader}, + beacon_state::{Fork, ForkData, HistoricalBatch, HistoricalSummary}, + block_processing::{get_validator_from_deposit, xor}, + constants::{ + BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, + JUSTIFICATION_BITS_LENGTH, + }, + helpers::{ + compute_activation_exit_epoch, compute_committee, compute_domain, + compute_epoch_at_slot, compute_fork_data_root, compute_fork_digest, + compute_shuffled_index, compute_shuffled_indices, compute_start_slot_at_epoch, + is_active_validator, is_slashable_attestation_data, is_slashable_validator, + }, + operations::{ + AttestationData, Checkpoint, Deposit, DepositData, DepositMessage, Eth1Data, + PendingAttestation, ProposerSlashing, SignedVoluntaryExit, VoluntaryExit, + }, + validator::{AggregateAndProof, Eth1Block, SignedAggregateAndProof, Validator}, + }, + primitives::*, + signing::*, + state_transition::{Context, Result, Validation}, }; +use crate::{ + crypto::{eth_aggregate_public_keys, eth_fast_aggregate_verify, fast_aggregate_verify, hash}, + ssz::prelude::*, +}; +use integer_sqrt::IntegerSquareRoot; +use std::{ + collections::{HashMap, HashSet}, + iter::zip, + mem, +}; +pub fn process_voluntary_exit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + signed_voluntary_exit: &SignedVoluntaryExit, + context: &Context, +) -> Result<()> { + let voluntary_exit = &signed_voluntary_exit.message; + let validator = state.validators.get(voluntary_exit.validator_index).ok_or_else(|| { + invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::InvalidIndex(voluntary_exit.validator_index), + )) + })?; + let current_epoch = get_current_epoch(state, context); + if !is_active_validator(validator, current_epoch) { + return Err(invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::InactiveValidator(current_epoch), + ))); + } + if validator.exit_epoch != FAR_FUTURE_EPOCH { + return Err(invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::ValidatorAlreadyExited { + index: voluntary_exit.validator_index, + epoch: validator.exit_epoch, + }, + ))); + } + if current_epoch < voluntary_exit.epoch { + return Err(invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::EarlyExit { current_epoch, exit_epoch: voluntary_exit.epoch }, + ))); + } + let minimum_time_active = + validator.activation_eligibility_epoch + context.shard_committee_period; + if current_epoch < minimum_time_active { + return Err(invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::ValidatorIsNotActiveForLongEnough { + current_epoch, + minimum_time_active, + }, + ))); + } + let domain = compute_domain( + DomainType::VoluntaryExit, + Some(context.capella_fork_version), + Some(state.genesis_validators_root), + context, + )?; + let public_key = &validator.public_key; + verify_signed_data(voluntary_exit, &signed_voluntary_exit.signature, public_key, domain) + .map_err(|_| { + invalid_operation_error(InvalidOperation::VoluntaryExit( + InvalidVoluntaryExit::InvalidSignature(signed_voluntary_exit.signature.clone()), + )) + })?; + initiate_validator_exit(state, voluntary_exit.validator_index, context)?; + Ok(()) +} +pub fn process_block< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + block: &BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) -> Result<()> { + process_block_header(state, block, context)?; + process_withdrawals(state, &block.body.execution_payload, context)?; + process_execution_payload(state, &block.body, context)?; + process_randao(state, &block.body, context)?; + process_eth1_data(state, &block.body, context); + process_operations(state, &block.body, context)?; + process_sync_aggregate(state, &block.body.sync_aggregate, context)?; + Ok(()) +} +pub fn process_bls_to_execution_change< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + signed_address_change: &SignedBlsToExecutionChange, + context: &Context, +) -> Result<()> { + let address_change = &signed_address_change.message; + let signature = &signed_address_change.signature; + if address_change.validator_index >= state.validators.len() { + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::ValidatorIndexOutOfBounds(address_change.validator_index), + ))); + } + let withdrawal_credentials = + &mut state.validators[address_change.validator_index].withdrawal_credentials; + if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]), + ))); + } + let domain = compute_domain( + DomainType::BlsToExecutionChange, + None, + Some(state.genesis_validators_root), + context, + )?; + let signing_root = compute_signing_root(address_change, domain)?; + let public_key = &address_change.from_bls_public_key; + if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), + ))); + } + verify_signature(public_key, signing_root.as_ref(), signature)?; + withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; + withdrawal_credentials[1..12].fill(0); + withdrawal_credentials[12..].copy_from_slice(address_change.to_execution_address.as_ref()); + Ok(()) +} +pub fn process_operations< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) -> Result<()> { + let expected_deposit_count = usize::min( + context.max_deposits, + (state.eth1_data.deposit_count - state.eth1_deposit_index) as usize, + ); + if body.deposits.len() != expected_deposit_count { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::IncorrectCount { + expected: expected_deposit_count, + count: body.deposits.len(), + }, + ))); + } + body.proposer_slashings + .iter() + .try_for_each(|op| process_proposer_slashing(state, op, context))?; + body.attester_slashings + .iter() + .try_for_each(|op| process_attester_slashing(state, op, context))?; + body.attestations.iter().try_for_each(|op| process_attestation(state, op, context))?; + body.deposits.iter().try_for_each(|op| process_deposit(state, op, context))?; + body.voluntary_exits.iter().try_for_each(|op| process_voluntary_exit(state, op, context))?; + body.bls_to_execution_changes + .iter() + .try_for_each(|op| process_bls_to_execution_change(state, op, context))?; + Ok(()) +} +pub fn process_withdrawals< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + execution_payload: &ExecutionPayload< + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + >, + context: &Context, +) -> Result<()> { + let expected_withdrawals = get_expected_withdrawals(state, context); + if execution_payload.withdrawals.as_ref() != expected_withdrawals { + return Err(invalid_operation_error(InvalidOperation::Withdrawal( + InvalidWithdrawals::IncorrectWithdrawals { + provided: execution_payload.withdrawals.to_vec(), + expected: expected_withdrawals, + }, + ))); + } + for withdrawal in &expected_withdrawals { + decrease_balance(state, withdrawal.validator_index, withdrawal.amount); + } + if let Some(latest_withdrawal) = expected_withdrawals.last() { + state.next_withdrawal_index = latest_withdrawal.index + 1; + } + if expected_withdrawals.len() == context.max_withdrawals_per_payload { + let latest_withdrawal = expected_withdrawals.last().expect("empty withdrawals"); + let next_validator_index = (latest_withdrawal.validator_index + 1) % state.validators.len(); + state.next_withdrawal_validator_index = next_validator_index; + } else { + let next_index = + state.next_withdrawal_validator_index + context.max_validators_per_withdrawals_sweep; + state.next_withdrawal_validator_index = next_index % state.validators.len(); + } + Ok(()) +} +pub fn get_expected_withdrawals< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Vec { + let epoch = get_current_epoch(state, context); + let mut withdrawal_index = state.next_withdrawal_index; + let mut validator_index = state.next_withdrawal_validator_index; + let mut withdrawals = vec![]; + let bound = state.validators.len().min(context.max_validators_per_withdrawals_sweep); + for _ in 0..bound { + let validator = &state.validators[validator_index]; + let balance = state.balances[validator_index]; + if is_fully_withdrawable_validator(validator, balance, epoch) { + let address = + ExecutionAddress::try_from(&validator.withdrawal_credentials.as_slice()[12..]) + .expect("providing the correct amount of input to type"); + withdrawals.push(Withdrawal { + index: withdrawal_index, + validator_index, + address, + amount: balance, + }); + withdrawal_index += 1; + } else if is_partially_withdrawable_validator(validator, balance, context) { + let address = + ExecutionAddress::try_from(&validator.withdrawal_credentials.as_slice()[12..]) + .expect("providing the correct amount of input to type"); + withdrawals.push(Withdrawal { + index: withdrawal_index, + validator_index, + address, + amount: balance - context.max_effective_balance, + }); + withdrawal_index += 1; + } + if withdrawals.len() == context.max_withdrawals_per_payload { + break; + } + validator_index = (validator_index + 1) % state.validators.len(); + } + withdrawals +} +pub fn add_validator_to_registry< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: Gwei, + context: &Context, +) { + state.validators.push(get_validator_from_deposit( + public_key, + withdrawal_credentials, + amount, + context, + )); + state.balances.push(amount); + state.previous_epoch_participation.push(ParticipationFlags::default()); + state.current_epoch_participation.push(ParticipationFlags::default()); + state.inactivity_scores.push(0); +} +pub fn process_sync_aggregate< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + sync_aggregate: &SyncAggregate, + context: &Context, +) -> Result<()> { + let committee_public_keys = &state.current_sync_committee.public_keys; + let participant_public_keys = + zip(committee_public_keys.iter(), sync_aggregate.sync_committee_bits.iter()) + .filter_map(|(public_key, bit)| if *bit { Some(public_key) } else { None }) + .collect::>(); + let previous_slot = u64::max(state.slot, 1) - 1; + let domain = get_domain( + state, + DomainType::SyncCommittee, + Some(compute_epoch_at_slot(previous_slot, context)), + context, + )?; + let root_at_slot = *get_block_root_at_slot(state, previous_slot)?; + let signing_root = compute_signing_root(&root_at_slot, domain)?; + if eth_fast_aggregate_verify( + participant_public_keys.as_slice(), + signing_root.as_ref(), + &sync_aggregate.sync_committee_signature, + ) + .is_err() + { + return Err(invalid_operation_error(InvalidOperation::SyncAggregate( + InvalidSyncAggregate::InvalidSignature { + signature: sync_aggregate.sync_committee_signature.clone(), + root: signing_root, + }, + ))); + } + let total_active_increments = + get_total_active_balance(state, context)? / context.effective_balance_increment; + let total_base_rewards = + get_base_reward_per_increment(state, context)? * total_active_increments; + let max_participant_rewards = + total_base_rewards * SYNC_REWARD_WEIGHT / WEIGHT_DENOMINATOR / context.slots_per_epoch; + let participant_reward = max_participant_rewards / context.sync_committee_size as u64; + let proposer_reward = + participant_reward * PROPOSER_WEIGHT / (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT); + let all_public_keys = state + .validators + .iter() + .enumerate() + .map(|(i, v)| (&v.public_key, i)) + .collect::>(); + let mut committee_indices: Vec = Vec::default(); + for public_key in state.current_sync_committee.public_keys.iter() { + committee_indices + .push(*all_public_keys.get(public_key).expect("validator public_key should exist")); + } + for (participant_index, participation_bit) in + zip(committee_indices.iter(), sync_aggregate.sync_committee_bits.iter()) + { + if *participation_bit { + increase_balance(state, *participant_index, participant_reward); + increase_balance(state, get_beacon_proposer_index(state, context)?, proposer_reward); + } else { + decrease_balance(state, *participant_index, participant_reward); + } + } + Ok(()) +} +pub fn process_proposer_slashing< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + proposer_slashing: &ProposerSlashing, + context: &Context, +) -> Result<()> { + let header_1 = &proposer_slashing.signed_header_1.message; + let header_2 = &proposer_slashing.signed_header_2.message; + if header_1.slot != header_2.slot { + return Err(invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::SlotMismatch(header_1.slot, header_2.slot), + ))); + } + if header_1.proposer_index != header_2.proposer_index { + return Err(invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::ProposerMismatch( + header_1.proposer_index, + header_2.proposer_index, + ), + ))); + } + if header_1 == header_2 { + return Err(invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::HeadersAreEqual(header_1.clone()), + ))); + } + let proposer_index = header_1.proposer_index; + let proposer = state.validators.get(proposer_index).ok_or_else(|| { + invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::InvalidIndex(proposer_index), + )) + })?; + if !is_slashable_validator(proposer, get_current_epoch(state, context)) { + return Err(invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::ProposerIsNotSlashable(header_1.proposer_index), + ))); + } + let epoch = compute_epoch_at_slot(header_1.slot, context); + let domain = get_domain(state, DomainType::BeaconProposer, Some(epoch), context)?; + for signed_header in [&proposer_slashing.signed_header_1, &proposer_slashing.signed_header_2] { + let signing_root = compute_signing_root(&signed_header.message, domain)?; + let public_key = &proposer.public_key; + if verify_signature(public_key, signing_root.as_ref(), &signed_header.signature).is_err() { + return Err(invalid_operation_error(InvalidOperation::ProposerSlashing( + InvalidProposerSlashing::InvalidSignature(signed_header.signature.clone()), + ))); + } + } + slash_validator(state, proposer_index, None, context) +} +pub fn process_attester_slashing< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + attester_slashing: &AttesterSlashing, + context: &Context, +) -> Result<()> { + let attestation_1 = &attester_slashing.attestation_1; + let attestation_2 = &attester_slashing.attestation_2; + if !is_slashable_attestation_data(&attestation_1.data, &attestation_2.data) { + return Err(invalid_operation_error(InvalidOperation::AttesterSlashing( + InvalidAttesterSlashing::NotSlashable( + Box::new(attestation_1.data.clone()), + Box::new(attestation_2.data.clone()), + ), + ))); + } + is_valid_indexed_attestation(state, attestation_1, context)?; + is_valid_indexed_attestation(state, attestation_2, context)?; + let indices_1: HashSet = + HashSet::from_iter(attestation_1.attesting_indices.iter().cloned()); + let indices_2 = HashSet::from_iter(attestation_2.attesting_indices.iter().cloned()); + let mut indices = indices_1.intersection(&indices_2).cloned().collect::>(); + indices.sort_unstable(); + let mut slashed_any = false; + let current_epoch = get_current_epoch(state, context); + for &index in &indices { + if is_slashable_validator(&state.validators[index], current_epoch) { + slash_validator(state, index, None, context)?; + slashed_any = true; + } + } + if !slashed_any { + Err(invalid_operation_error(InvalidOperation::AttesterSlashing( + InvalidAttesterSlashing::NoSlashings(indices), + ))) + } else { + Ok(()) + } +} +pub fn apply_deposit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: Gwei, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state.validators.iter().position(|v| v.public_key == *public_key); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let deposit_message = DepositMessage { + public_key: public_key.clone(), + withdrawal_credentials: withdrawal_credentials.clone(), + amount, + }; + let domain = compute_domain(DomainType::Deposit, None, None, context)?; + let signing_root = compute_signing_root(&deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + return Ok(()); + } + add_validator_to_registry( + state, + deposit_message.public_key, + deposit_message.withdrawal_credentials, + amount, + context, + ); + Ok(()) +} +pub fn process_deposit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + deposit: &Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let depth = DEPOSIT_CONTRACT_TREE_DEPTH + 1; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, depth, index, root).is_err() { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::InvalidProof { leaf, branch: branch.to_vec(), depth, index, root }, + ))); + } + state.eth1_deposit_index += 1; + let public_key = &deposit.data.public_key; + let withdrawal_credentials = &deposit.data.withdrawal_credentials; + let amount = deposit.data.amount; + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) +} +pub fn process_block_header< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + block: &BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) -> Result<()> { + if block.slot != state.slot { + return Err(invalid_header_error(InvalidBeaconBlockHeader::StateSlotMismatch { + state_slot: state.slot, + block_slot: block.slot, + })); + } + if block.slot <= state.latest_block_header.slot { + return Err(invalid_header_error(InvalidBeaconBlockHeader::OlderThanLatestBlockHeader { + block_slot: block.slot, + latest_block_header_slot: state.latest_block_header.slot, + })); + } + let proposer_index = get_beacon_proposer_index(state, context)?; + if block.proposer_index != proposer_index { + return Err(invalid_header_error(InvalidBeaconBlockHeader::ProposerIndexMismatch { + block_proposer_index: block.proposer_index, + proposer_index, + })); + } + let expected_parent_root = state.latest_block_header.hash_tree_root()?; + if block.parent_root != expected_parent_root { + return Err(invalid_header_error(InvalidBeaconBlockHeader::ParentBlockRootMismatch { + expected: expected_parent_root, + provided: block.parent_root, + })); + } + state.latest_block_header = BeaconBlockHeader { + slot: block.slot, + proposer_index: block.proposer_index, + parent_root: block.parent_root, + body_root: block.body.hash_tree_root()?, + ..Default::default() + }; + let proposer = &state.validators[block.proposer_index]; + if proposer.slashed { + return Err(invalid_header_error(InvalidBeaconBlockHeader::ProposerSlashed(proposer_index))); + } + Ok(()) +} +pub fn process_randao< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) -> Result<()> { + let epoch = get_current_epoch(state, context); + let proposer_index = get_beacon_proposer_index(state, context)?; + let proposer = &state.validators[proposer_index]; + let domain = get_domain(state, DomainType::Randao, Some(epoch), context)?; + let signing_root = compute_signing_root(&epoch, domain)?; + if verify_signature(&proposer.public_key, signing_root.as_ref(), &body.randao_reveal).is_err() { + return Err(invalid_operation_error(InvalidOperation::Randao(body.randao_reveal.clone()))); + } + let mix = xor(get_randao_mix(state, epoch), &hash(body.randao_reveal.as_ref())); + let mix_index = epoch % context.epochs_per_historical_vector; + state.randao_mixes[mix_index as usize] = mix; + Ok(()) +} +pub fn process_eth1_data< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) { + state.eth1_data_votes.push(body.eth1_data.clone()); + let votes_count = + state.eth1_data_votes.iter().filter(|&vote| *vote == body.eth1_data).count() as u64; + if votes_count * 2 > context.epochs_per_eth1_voting_period * context.slots_per_epoch { + state.eth1_data = body.eth1_data.clone(); + } +} +pub fn process_registry_updates< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let current_epoch = get_current_epoch(state, context); + for i in 0..state.validators.len() { + let validator = &mut state.validators[i]; + if is_eligible_for_activation_queue(validator, context) { + validator.activation_eligibility_epoch = current_epoch + 1; + } + if is_active_validator(validator, current_epoch) && + validator.effective_balance <= context.ejection_balance + { + initiate_validator_exit(state, i, context)?; + } + } + let mut activation_queue = + state + .validators + .iter() + .enumerate() + .filter_map(|(index, validator)| { + if is_eligible_for_activation(state, validator) { + Some(index) + } else { + None + } + }) + .collect::>(); + activation_queue.sort_by(|&i, &j| { + let a = &state.validators[i]; + let b = &state.validators[j]; + (a.activation_eligibility_epoch, i).cmp(&(b.activation_eligibility_epoch, j)) + }); + let activation_exit_epoch = compute_activation_exit_epoch(current_epoch, context); + for i in activation_queue.into_iter().take(get_validator_activation_churn_limit(state, context)) + { + let validator = &mut state.validators[i]; + validator.activation_epoch = activation_exit_epoch; + } + Ok(()) +} +pub fn process_historical_summaries_update< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let next_epoch = get_current_epoch(state, context) + 1; + if (next_epoch % (context.slots_per_historical_root / context.slots_per_epoch)) == 0 { + let historical_summary = HistoricalSummary { + block_summary_root: state.block_roots.hash_tree_root()?, + state_summary_root: state.state_roots.hash_tree_root()?, + }; + state.historical_summaries.push(historical_summary); + } + Ok(()) +} +pub fn process_epoch< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + process_justification_and_finalization(state, context)?; + process_inactivity_updates(state, context)?; + process_rewards_and_penalties(state, context)?; + process_registry_updates(state, context)?; + process_slashings(state, context)?; + process_eth1_data_reset(state, context); + process_effective_balance_updates(state, context); + process_slashings_reset(state, context); + process_randao_mixes_reset(state, context); + process_historical_summaries_update(state, context)?; + process_participation_flag_updates(state)?; + process_sync_committee_updates(state, context)?; + Ok(()) +} +pub fn process_slashings< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let epoch = get_current_epoch(state, context); + let total_balance = get_total_active_balance(state, context)?; + let adjusted_total_slashing_balance = Gwei::min( + state.slashings.iter().sum::() * context.proportional_slashing_multiplier_bellatrix, + total_balance, + ); + for i in 0..state.validators.len() { + let validator = &state.validators[i]; + if validator.slashed && + (epoch + context.epochs_per_slashings_vector / 2) == validator.withdrawable_epoch + { + let increment = context.effective_balance_increment; + let penalty_numerator = + validator.effective_balance / increment * adjusted_total_slashing_balance; + let penalty = penalty_numerator / total_balance * increment; + decrease_balance(state, i, penalty); + } + } + Ok(()) +} +pub fn get_base_reward< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + context: &Context, +) -> Result { + let increments = + state.validators[index].effective_balance / context.effective_balance_increment; + Ok(increments * get_base_reward_per_increment(state, context)?) +} +pub fn process_justification_and_finalization< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let current_epoch = get_current_epoch(state, context); + if current_epoch <= GENESIS_EPOCH + 1 { + return Ok(()); + } + let previous_indices = get_unslashed_participating_indices( + state, + TIMELY_TARGET_FLAG_INDEX, + get_previous_epoch(state, context), + context, + )?; + let current_indices = get_unslashed_participating_indices( + state, + TIMELY_TARGET_FLAG_INDEX, + current_epoch, + context, + )?; + let total_active_balance = get_total_active_balance(state, context)?; + let previous_target_balance = get_total_balance(state, &previous_indices, context)?; + let current_target_balance = get_total_balance(state, ¤t_indices, context)?; + weigh_justification_and_finalization( + state, + total_active_balance, + previous_target_balance, + current_target_balance, + context, + ) +} +pub fn process_inactivity_updates< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let current_epoch = get_current_epoch(state, context); + if current_epoch == GENESIS_EPOCH { + return Ok(()); + } + let eligible_validator_indices = + get_eligible_validator_indices(state, context).collect::>(); + let unslashed_participating_indices = get_unslashed_participating_indices( + state, + TIMELY_TARGET_FLAG_INDEX, + get_previous_epoch(state, context), + context, + )?; + let not_is_leaking = !is_in_inactivity_leak(state, context); + for index in eligible_validator_indices { + if unslashed_participating_indices.contains(&index) { + state.inactivity_scores[index] -= u64::min(1, state.inactivity_scores[index]); + } else { + state.inactivity_scores[index] += context.inactivity_score_bias; + } + if not_is_leaking { + state.inactivity_scores[index] -= + u64::min(context.inactivity_score_recovery_rate, state.inactivity_scores[index]); + } + } + Ok(()) +} +pub fn process_rewards_and_penalties< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let current_epoch = get_current_epoch(state, context); + if current_epoch == GENESIS_EPOCH { + return Ok(()); + } + let mut deltas = Vec::new(); + for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() { + let flag_index_delta = get_flag_index_deltas(state, flag_index, context)?; + deltas.push(flag_index_delta); + } + deltas.push(get_inactivity_penalty_deltas(state, context)?); + for (rewards, penalties) in deltas { + for index in 0..state.validators.len() { + increase_balance(state, index, rewards[index]); + decrease_balance(state, index, penalties[index]); + } + } + Ok(()) +} +pub fn process_participation_flag_updates< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, +) -> Result<()> { + let current_participation = mem::take(&mut state.current_epoch_participation); + state.previous_epoch_participation = current_participation; + let rotate_participation = vec![ParticipationFlags::default(); state.validators.len()]; + state.current_epoch_participation = + rotate_participation.try_into().expect("should convert from Vec to List"); + Ok(()) +} +pub fn process_sync_committee_updates< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let next_epoch = get_current_epoch(state, context) + 1; + if next_epoch % context.epochs_per_sync_committee_period == 0 { + let next_sync_committee = get_next_sync_committee(state, context)?; + let current_sync_committee = + mem::replace(&mut state.next_sync_committee, next_sync_committee); + state.current_sync_committee = current_sync_committee; + } + Ok(()) +} +pub fn process_eth1_data_reset< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) { + let next_epoch = get_current_epoch(state, context) + 1; + if next_epoch % context.epochs_per_eth1_voting_period == 0 { + state.eth1_data_votes.clear(); + } +} +pub fn process_effective_balance_updates< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) { + let hysteresis_increment = context.effective_balance_increment / context.hysteresis_quotient; + let downward_threshold = hysteresis_increment * context.hysteresis_downward_multiplier; + let upward_threshold = hysteresis_increment * context.hysteresis_upward_multiplier; + for i in 0..state.validators.len() { + let validator = &mut state.validators[i]; + let balance = state.balances[i]; + if balance + downward_threshold < validator.effective_balance || + validator.effective_balance + upward_threshold < balance + { + validator.effective_balance = Gwei::min( + balance - balance % context.effective_balance_increment, + context.max_effective_balance, + ); + } + } +} +pub fn process_slashings_reset< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) { + let next_epoch = get_current_epoch(state, context) + 1; + let slashings_index = next_epoch % context.epochs_per_slashings_vector; + state.slashings[slashings_index as usize] = 0; +} +pub fn process_randao_mixes_reset< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) { + let current_epoch = get_current_epoch(state, context); + let next_epoch = current_epoch + 1; + let mix_index = next_epoch % context.epochs_per_historical_vector; + state.randao_mixes[mix_index as usize] = get_randao_mix(state, current_epoch).clone(); +} +pub fn process_historical_roots_update< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let next_epoch = get_current_epoch(state, context) + 1; + let epochs_per_historical_root = context.slots_per_historical_root / context.slots_per_epoch; + if next_epoch % epochs_per_historical_root == 0 { + let historical_batch = HistoricalSummary { + block_summary_root: state.block_roots.hash_tree_root()?, + state_summary_root: state.state_roots.hash_tree_root()?, + }; + state.historical_roots.push(historical_batch.hash_tree_root()?) + } + Ok(()) +} +pub fn weigh_justification_and_finalization< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + total_active_balance: Gwei, + previous_epoch_target_balance: Gwei, + current_epoch_target_balance: Gwei, + context: &Context, +) -> Result<()> { + let previous_epoch = get_previous_epoch(state, context); + let current_epoch = get_current_epoch(state, context); + let old_previous_justified_checkpoint = state.previous_justified_checkpoint.clone(); + let old_current_justified_checkpoint = state.current_justified_checkpoint.clone(); + state.previous_justified_checkpoint = state.current_justified_checkpoint.clone(); + state.justification_bits.copy_within(..JUSTIFICATION_BITS_LENGTH - 1, 1); + state.justification_bits.set(0, false); + if previous_epoch_target_balance * 3 >= total_active_balance * 2 { + state.current_justified_checkpoint = Checkpoint { + epoch: previous_epoch, + root: *get_block_root(state, previous_epoch, context)?, + }; + state.justification_bits.set(1, true); + } + if current_epoch_target_balance * 3 >= total_active_balance * 2 { + state.current_justified_checkpoint = Checkpoint { + epoch: current_epoch, + root: *get_block_root(state, current_epoch, context)?, + }; + state.justification_bits.set(0, true); + } + let bits = &state.justification_bits; + if bits[1..4].all() && old_previous_justified_checkpoint.epoch + 3 == current_epoch { + state.finalized_checkpoint = old_previous_justified_checkpoint.clone(); + } + if bits[1..3].all() && old_previous_justified_checkpoint.epoch + 2 == current_epoch { + state.finalized_checkpoint = old_previous_justified_checkpoint; + } + if bits[0..3].all() && old_current_justified_checkpoint.epoch + 2 == current_epoch { + state.finalized_checkpoint = old_current_justified_checkpoint.clone(); + } + if bits[0..2].all() && old_current_justified_checkpoint.epoch + 1 == current_epoch { + state.finalized_checkpoint = old_current_justified_checkpoint; + } + Ok(()) +} +pub fn get_proposer_reward< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + attesting_index: ValidatorIndex, + context: &Context, +) -> Result { + Ok(get_base_reward(state, attesting_index, context)? / context.proposer_reward_quotient) +} +pub fn get_finality_delay< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Epoch { + get_previous_epoch(state, context) - state.finalized_checkpoint.epoch +} +pub fn is_in_inactivity_leak< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> bool { + get_finality_delay(state, context) > context.min_epochs_to_inactivity_penalty +} +pub fn is_valid_genesis_state< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> bool { + if state.genesis_time < context.min_genesis_time { + return false; + } + get_active_validator_indices(state, GENESIS_EPOCH).len() >= + context.min_genesis_active_validator_count +} +pub fn get_genesis_block< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + genesis_state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, +) -> Result< + BeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, +> { + Ok(BeaconBlock { state_root: genesis_state.hash_tree_root()?, ..Default::default() }) +} +pub fn get_attestation_participation_flag_indices< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + data: &AttestationData, + inclusion_delay: u64, + context: &Context, +) -> Result> { + let justified_checkpoint = if data.target.epoch == get_current_epoch(state, context) { + &state.current_justified_checkpoint + } else { + &state.previous_justified_checkpoint + }; + let is_matching_source = data.source == *justified_checkpoint; + if !is_matching_source { + return Err(invalid_operation_error(InvalidOperation::Attestation( + InvalidAttestation::InvalidSource { + expected: justified_checkpoint.clone(), + source_checkpoint: data.source.clone(), + current: get_current_epoch(state, context), + }, + ))); + } + let is_matching_target = is_matching_source && + (data.target.root == *get_block_root(state, data.target.epoch, context)?); + let is_matching_head = is_matching_target && + (data.beacon_block_root == *get_block_root_at_slot(state, data.slot)?); + let mut participation_flag_indices = Vec::new(); + if is_matching_source && inclusion_delay <= context.slots_per_epoch.integer_sqrt() { + participation_flag_indices.push(TIMELY_SOURCE_FLAG_INDEX); + } + if is_matching_target { + participation_flag_indices.push(TIMELY_TARGET_FLAG_INDEX); + } + if is_matching_head && inclusion_delay == context.min_attestation_inclusion_delay { + participation_flag_indices.push(TIMELY_HEAD_FLAG_INDEX); + } + Ok(participation_flag_indices) +} +pub fn get_validator_activation_churn_limit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> usize { + let limit = context.max_per_epoch_activation_churn_limit as usize; + limit.min(get_validator_churn_limit(state, context)) +} +pub fn get_inactivity_penalty_deltas< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<(Vec, Vec)> { + let validator_count = state.validators.len(); + let rewards = vec![0; validator_count]; + let mut penalties = vec![0; validator_count]; + let previous_epoch = get_previous_epoch(state, context); + let matching_target_indices = get_unslashed_participating_indices( + state, + TIMELY_TARGET_FLAG_INDEX, + previous_epoch, + context, + )?; + for i in get_eligible_validator_indices(state, context) { + if !matching_target_indices.contains(&i) { + let penalty_numerator = + state.validators[i].effective_balance * state.inactivity_scores[i]; + let penalty_denominator = + context.inactivity_score_bias * context.inactivity_penalty_quotient_bellatrix; + penalties[i] += penalty_numerator / penalty_denominator; + } + } + Ok((rewards, penalties)) +} +pub fn is_merge_transition_complete< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, +) -> bool { + state.latest_execution_payload_header != ExecutionPayloadHeader::default() +} +pub fn is_merge_transition_block< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, +) -> bool { + let transition_is_not_complete = !is_merge_transition_complete(state); + let nonempty_payload = body.execution_payload != ExecutionPayload::default(); + transition_is_not_complete && nonempty_payload +} +pub fn is_execution_enabled< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + body: &BeaconBlockBody< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, +) -> bool { + let is_transition_block = is_merge_transition_block(state, body); + let transition_is_complete = is_merge_transition_complete(state); + is_transition_block || transition_is_complete +} +pub fn compute_timestamp_at_slot< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + slot: Slot, + context: &Context, +) -> Result { + let slots_since_genesis = slot.checked_sub(GENESIS_SLOT).ok_or(Error::Underflow)?; + let timestamp = state.genesis_time + slots_since_genesis * context.seconds_per_slot; + Ok(timestamp) +} +pub fn get_next_sync_committee_indices< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result> { + let epoch = get_current_epoch(state, context) + 1; + let max_random_byte = u8::MAX as u64; + let active_validator_indices = get_active_validator_indices(state, epoch); + let active_validator_count = active_validator_indices.len(); + let seed = get_seed(state, epoch, DomainType::SyncCommittee, context); + let mut i: usize = 0; + let mut sync_committee_indices = vec![]; + let mut hash_input = [0u8; 40]; + hash_input[..32].copy_from_slice(seed.as_ref()); + while sync_committee_indices.len() < context.sync_committee_size { + let shuffled_index = compute_shuffled_index( + i % active_validator_count, + active_validator_count, + &seed, + context, + )?; + let candidate_index = active_validator_indices[shuffled_index]; + let i_bytes: [u8; 8] = ((i / 32) as u64).to_le_bytes(); + hash_input[32..].copy_from_slice(&i_bytes); + let random_byte = hash(hash_input).as_ref()[i % 32] as u64; + let effective_balance = state.validators[candidate_index].effective_balance; + if effective_balance * max_random_byte >= context.max_effective_balance * random_byte { + sync_committee_indices.push(candidate_index); + } + i += 1; + } + Ok(sync_committee_indices) +} +pub fn get_next_sync_committee< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result> { + let indices = get_next_sync_committee_indices(state, context)?; + let public_keys = + indices.into_iter().map(|i| state.validators[i].public_key.clone()).collect::>(); + let public_keys = Vector::::try_from(public_keys) + .map_err(|(_, err)| err)?; + let aggregate_public_key = eth_aggregate_public_keys(&public_keys)?; + Ok(SyncCommittee { public_keys, aggregate_public_key }) +} +pub fn get_base_reward_per_increment< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + Ok(context.effective_balance_increment * context.base_reward_factor / + get_total_active_balance(state, context)?.integer_sqrt()) +} +pub fn get_unslashed_participating_indices< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + flag_index: usize, + epoch: Epoch, + context: &Context, +) -> Result> { + let previous_epoch = get_previous_epoch(state, context); + let current_epoch = get_current_epoch(state, context); + let is_current = epoch == current_epoch; + if previous_epoch != epoch && current_epoch != epoch { + return Err(Error::InvalidEpoch { + requested: epoch, + previous: previous_epoch, + current: current_epoch, + }); + } + let epoch_participation = if is_current { + &state.current_epoch_participation + } else { + &state.previous_epoch_participation + }; + Ok(get_active_validator_indices(state, epoch) + .into_iter() + .filter(|&i| { + let did_participate = has_flag(epoch_participation[i], flag_index); + let not_slashed = !state.validators[i].slashed; + did_participate && not_slashed + }) + .collect::>()) +} +pub fn get_flag_index_deltas< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + flag_index: usize, + context: &Context, +) -> Result<(Vec, Vec)> { + let validator_count = state.validators.len(); + let mut rewards = vec![0; validator_count]; + let mut penalties = vec![0; validator_count]; + let previous_epoch = get_previous_epoch(state, context); + let unslashed_participating_indices = + get_unslashed_participating_indices(state, flag_index, previous_epoch, context)?; + let weight = PARTICIPATION_FLAG_WEIGHTS[flag_index]; + let unslashed_participating_balance = + get_total_balance(state, &unslashed_participating_indices, context)?; + let unslashed_participating_increments = + unslashed_participating_balance / context.effective_balance_increment; + let active_increments = + get_total_active_balance(state, context)? / context.effective_balance_increment; + let not_leaking = !is_in_inactivity_leak(state, context); + for index in get_eligible_validator_indices(state, context) { + let base_reward = get_base_reward(state, index, context)?; + if unslashed_participating_indices.contains(&index) { + if not_leaking { + let reward_numerator = base_reward * weight * unslashed_participating_increments; + rewards[index] += reward_numerator / (active_increments * WEIGHT_DENOMINATOR); + } + } else if flag_index != TIMELY_HEAD_FLAG_INDEX { + penalties[index] += base_reward * weight / WEIGHT_DENOMINATOR; + } + } + Ok((rewards, penalties)) +} +pub fn is_eligible_for_activation< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + validator: &Validator, +) -> bool { + validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch && + validator.activation_epoch == FAR_FUTURE_EPOCH +} +pub fn is_valid_indexed_attestation< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + indexed_attestation: &IndexedAttestation, + context: &Context, +) -> Result<()> { + let attesting_indices = &indexed_attestation.attesting_indices; + if attesting_indices.is_empty() { + return Err(invalid_operation_error(InvalidOperation::IndexedAttestation( + InvalidIndexedAttestation::AttestingIndicesEmpty, + ))); + } + let mut prev = attesting_indices[0]; + let mut duplicates = HashSet::new(); + for &index in &attesting_indices[1..] { + if index < prev { + return Err(invalid_operation_error(InvalidOperation::IndexedAttestation( + InvalidIndexedAttestation::AttestingIndicesNotSorted, + ))); + } + if index == prev { + duplicates.insert(index); + } + prev = index; + } + if !duplicates.is_empty() { + return Err(invalid_operation_error(InvalidOperation::IndexedAttestation( + InvalidIndexedAttestation::DuplicateIndices(Vec::from_iter(duplicates)), + ))); + } + let mut public_keys = vec![]; + for &index in &attesting_indices[..] { + let public_key = state.validators.get(index).map(|v| &v.public_key).ok_or_else(|| { + invalid_operation_error(InvalidOperation::IndexedAttestation( + InvalidIndexedAttestation::InvalidIndex(index), + )) + })?; + public_keys.push(public_key); + } + let domain = get_domain( + state, + DomainType::BeaconAttester, + Some(indexed_attestation.data.target.epoch), + context, + )?; + let signing_root = compute_signing_root(&indexed_attestation.data, domain)?; + fast_aggregate_verify(&public_keys, signing_root.as_ref(), &indexed_attestation.signature) + .map_err(Into::into) +} +pub fn verify_block_signature< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + signed_block: &SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + context: &Context, +) -> Result<()> { + let proposer_index = signed_block.message.proposer_index; + let proposer = state + .validators + .get(proposer_index) + .ok_or(Error::OutOfBounds { requested: proposer_index, bound: state.validators.len() })?; + let domain = get_domain(state, DomainType::BeaconProposer, None, context)?; + let signing_root = compute_signing_root(&signed_block.message, domain)?; + let public_key = &proposer.public_key; + verify_signature(public_key, signing_root.as_ref(), &signed_block.signature).map_err(Into::into) +} +pub fn get_domain< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + domain_type: DomainType, + epoch: Option, + context: &Context, +) -> Result { + let epoch = epoch.unwrap_or_else(|| get_current_epoch(state, context)); + let fork_version = if epoch < state.fork.epoch { + state.fork.previous_version + } else { + state.fork.current_version + }; + compute_domain(domain_type, Some(fork_version), Some(state.genesis_validators_root), context) +} +pub fn get_current_epoch< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Epoch { + compute_epoch_at_slot(state.slot, context) +} +pub fn sample_proposer_index< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + candidate_index: ValidatorIndex, + round: usize, + hash_input: &mut [u8], + context: &Context, +) -> Option { + let max_byte = u8::MAX as u64; + let round_bytes: [u8; 8] = (round / 32).to_le_bytes(); + hash_input[32..].copy_from_slice(&round_bytes); + let random_byte = hash(hash_input).as_ref()[round % 32] as u64; + let effective_balance = state.validators[candidate_index].effective_balance; + if effective_balance * max_byte >= context.max_effective_balance * random_byte { + Some(candidate_index) + } else { + None + } +} +pub fn compute_proposer_index< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> Result { + if indices.is_empty() { + return Err(Error::CollectionCannotBeEmpty); + } + let mut round = 0; + let total = indices.len(); + let mut hash_input = [0u8; 40]; + hash_input[..32].copy_from_slice(seed.as_ref()); + if cfg!(feature = "shuffling") { + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + loop { + let candidate_index = shuffled_indices[round % total]; + if let Some(candidate_index) = + sample_proposer_index(state, candidate_index, round, &mut hash_input, context) + { + return Ok(candidate_index); + } + round += 1; + } + } else { + loop { + let shuffled_index = compute_shuffled_index(round % total, total, seed, context)?; + let candidate_index = indices[shuffled_index]; + if let Some(candidate_index) = + sample_proposer_index(state, candidate_index, round, &mut hash_input, context) + { + return Ok(candidate_index); + } + round += 1; + } + } +} +pub fn get_previous_epoch< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Epoch { + let current_epoch = get_current_epoch(state, context); + if current_epoch == GENESIS_EPOCH { + GENESIS_EPOCH + } else { + current_epoch - 1 + } +} +pub fn get_block_root< + 'a, + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &'a BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + epoch: Epoch, + context: &Context, +) -> Result<&'a Root> { + get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch, context)) +} +pub fn get_block_root_at_slot< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + slot: Slot, +) -> Result<&Root> { + if slot >= state.slot || state.slot > (slot + SLOTS_PER_HISTORICAL_ROOT as Slot) { + return Err(Error::SlotOutOfRange { + requested: slot, + lower_bound: state.slot - 1, + upper_bound: state.slot + SLOTS_PER_HISTORICAL_ROOT as Slot, + }); + } + Ok(&state.block_roots[slot as usize % SLOTS_PER_HISTORICAL_ROOT]) +} +pub fn get_randao_mix< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + epoch: Epoch, +) -> &Bytes32 { + let epoch = epoch as usize % EPOCHS_PER_HISTORICAL_VECTOR; + &state.randao_mixes[epoch] +} +pub fn get_active_validator_indices< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + epoch: Epoch, +) -> Vec { + let mut active = Vec::with_capacity(state.validators.len()); + for (i, v) in state.validators.iter().enumerate() { + if is_active_validator(v, epoch) { + active.push(i) + } + } + active +} +pub fn get_validator_churn_limit< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> usize { + let active_validator_indices = + get_active_validator_indices(state, get_current_epoch(state, context)); + u64::max( + context.min_per_epoch_churn_limit, + active_validator_indices.len() as u64 / context.churn_limit_quotient, + ) as usize +} +pub fn get_seed< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + epoch: Epoch, + domain_type: DomainType, + context: &Context, +) -> Bytes32 { + let mix_epoch = epoch + (context.epochs_per_historical_vector - context.min_seed_lookahead) - 1; + let mix = get_randao_mix(state, mix_epoch); + let mut input = [0u8; 44]; + input[..4].copy_from_slice(&domain_type.as_bytes()); + input[4..12].copy_from_slice(&epoch.to_le_bytes()); + input[12..].copy_from_slice(mix.as_ref()); + hash(input) +} +pub fn get_committee_count_per_slot< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + epoch: Epoch, + context: &Context, +) -> usize { + u64::max( + 1, + u64::min( + context.max_committees_per_slot, + get_active_validator_indices(state, epoch).len() as u64 / + context.slots_per_epoch / + context.target_committee_size, + ), + ) as usize +} +pub fn get_beacon_committee< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + slot: Slot, + index: CommitteeIndex, + context: &Context, +) -> Result> { + let epoch = compute_epoch_at_slot(slot, context); + let committees_per_slot = get_committee_count_per_slot(state, epoch, context); + let indices = get_active_validator_indices(state, epoch); + let seed = get_seed(state, epoch, DomainType::BeaconAttester, context); + let index = (slot % context.slots_per_epoch) * committees_per_slot as u64 + index as u64; + let count = committees_per_slot as u64 * context.slots_per_epoch; + compute_committee(&indices, &seed, index as usize, count as usize, context) +} +pub fn get_beacon_proposer_index< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + let epoch = get_current_epoch(state, context); + let mut input = [0u8; 40]; + input[..32] + .copy_from_slice(get_seed(state, epoch, DomainType::BeaconProposer, context).as_ref()); + input[32..40].copy_from_slice(&state.slot.to_le_bytes()); + let seed = hash(input); + let indices = get_active_validator_indices(state, epoch); + compute_proposer_index(state, &indices, &seed, context) +} +pub fn get_total_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + indices: &HashSet, + context: &Context, +) -> Result { + let total_balance = indices + .iter() + .try_fold(Gwei::default(), |acc, i| acc.checked_add(state.validators[*i].effective_balance)) + .ok_or(Error::Overflow)?; + Ok(u64::max(total_balance, context.effective_balance_increment)) +} +pub fn get_total_active_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result { + let indices = get_active_validator_indices(state, get_current_epoch(state, context)); + get_total_balance(state, &HashSet::from_iter(indices), context) +} +pub fn increase_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + delta: Gwei, +) { + state.balances[index] += delta; +} +pub fn decrease_balance< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + index: ValidatorIndex, + delta: Gwei, +) { + if delta > state.balances[index] { + state.balances[index] = 0 + } else { + state.balances[index] -= delta + } +} +pub fn get_eligible_validator_indices< + 'a, + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &'a BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> impl Iterator + 'a { + let previous_epoch = get_previous_epoch(state, context); + state.validators.iter().enumerate().filter_map(move |(i, validator)| { + if is_active_validator(validator, previous_epoch) || + (validator.slashed && previous_epoch + 1 < validator.withdrawable_epoch) + { + Some(i) + } else { + None + } + }) +} +pub fn process_slots< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + slot: Slot, + context: &Context, +) -> Result<()> { + if state.slot >= slot { + return Err(Error::TransitionToPreviousSlot { requested: slot, current: state.slot }); + } + while state.slot < slot { + process_slot(state, context)?; + if (state.slot + 1) % context.slots_per_epoch == 0 { + process_epoch(state, context)?; + } + state.slot += 1; + } + Ok(()) +} +pub fn process_slot< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + context: &Context, +) -> Result<()> { + let previous_state_root = state.hash_tree_root()?; + let root_index = state.slot % context.slots_per_historical_root; + state.state_roots[root_index as usize] = previous_state_root; + if state.latest_block_header.state_root == Root::default() { + state.latest_block_header.state_root = previous_state_root; + } + let previous_block_root = state.latest_block_header.hash_tree_root()?; + let root_index = state.slot % context.slots_per_historical_root; + state.block_roots[root_index as usize] = previous_block_root; + Ok(()) +} +pub fn state_transition_block_in_slot< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + signed_block: &SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + validation: Validation, + context: &Context, +) -> Result<()> { + let validate_result = match validation { + Validation::Enabled => true, + Validation::Disabled => false, + }; + if validate_result { + verify_block_signature(state, signed_block, context)?; + } + let block = &signed_block.message; + process_block(state, block, context)?; + if validate_result && block.state_root != state.hash_tree_root()? { + Err(Error::InvalidStateRoot) + } else { + Ok(()) + } +} +pub fn state_transition< + const SLOTS_PER_HISTORICAL_ROOT: usize, + const HISTORICAL_ROOTS_LIMIT: usize, + const ETH1_DATA_VOTES_BOUND: usize, + const VALIDATOR_REGISTRY_LIMIT: usize, + const EPOCHS_PER_HISTORICAL_VECTOR: usize, + const EPOCHS_PER_SLASHINGS_VECTOR: usize, + const MAX_VALIDATORS_PER_COMMITTEE: usize, + const SYNC_COMMITTEE_SIZE: usize, + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + const PENDING_BALANCE_DEPOSITS_LIMIT: usize, + const PENDING_PARTIAL_WITHDRAWALS_LIMIT: usize, + const PENDING_CONSOLIDATIONS_LIMIT: usize, + const MAX_PROPOSER_SLASHINGS: usize, + const MAX_ATTESTER_SLASHINGS: usize, + const MAX_ATTESTATIONS: usize, + const MAX_DEPOSITS: usize, + const MAX_VOLUNTARY_EXITS: usize, + const MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_PER_PAYLOAD: usize, + const MAX_BLS_TO_EXECUTION_CHANGES: usize, + const MAX_BLOB_COMMITMENTS_PER_BLOCK: usize, + const MAX_COMMITTEES_PER_SLOT: usize, + const MAX_VALIDATORS_PER_SLOT: usize, + const MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: usize, + const MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: usize, + const MAX_CONSOLIDATIONS: usize, +>( + state: &mut BeaconState< + SLOTS_PER_HISTORICAL_ROOT, + HISTORICAL_ROOTS_LIMIT, + ETH1_DATA_VOTES_BOUND, + VALIDATOR_REGISTRY_LIMIT, + EPOCHS_PER_HISTORICAL_VECTOR, + EPOCHS_PER_SLASHINGS_VECTOR, + MAX_VALIDATORS_PER_COMMITTEE, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + PENDING_BALANCE_DEPOSITS_LIMIT, + PENDING_PARTIAL_WITHDRAWALS_LIMIT, + PENDING_CONSOLIDATIONS_LIMIT, + >, + signed_block: &SignedBeaconBlock< + MAX_PROPOSER_SLASHINGS, + MAX_VALIDATORS_PER_COMMITTEE, + MAX_ATTESTER_SLASHINGS, + MAX_ATTESTATIONS, + MAX_DEPOSITS, + MAX_VOLUNTARY_EXITS, + SYNC_COMMITTEE_SIZE, + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BLOB_COMMITMENTS_PER_BLOCK, + MAX_COMMITTEES_PER_SLOT, + MAX_VALIDATORS_PER_SLOT, + MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD, + MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, + MAX_CONSOLIDATIONS, + >, + validation: Validation, + context: &Context, +) -> Result<()> { + process_slots(state, signed_block.message.slot, context)?; + state_transition_block_in_slot(state, signed_block, validation, context) +} diff --git a/spec-gen/src/generator.rs b/spec-gen/src/generator.rs index 4a2d8daff..c4767cf36 100644 --- a/spec-gen/src/generator.rs +++ b/spec-gen/src/generator.rs @@ -93,8 +93,16 @@ impl Fork { "helpers", "light_client", ], - // TODO: electra - Self::Electra => &[], + Self::Electra => &[ + "beacon_block", + "beacon_state", + "block_processing", + "constants", + "execution_payload", + "genesis", + "helpers", + "operations", + ], } } @@ -701,6 +709,7 @@ pub fn run() { Some(Fork::Bellatrix), Some(Fork::Capella), Some(Fork::Deneb), + Some(Fork::Electra), ]; let mut specs = HashMap::<_, Rc<_>>::new();