From 7b4bd2e11864bc245a8bdd13b472b9b2d6831438 Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Tue, 9 Apr 2024 13:23:32 -0600 Subject: [PATCH 1/5] feat: add auxiliary deposit functions --- .../src/altair/block_processing.rs | 134 +- ethereum-consensus/src/altair/spec/mod.rs | 15 +- ethereum-consensus/src/bellatrix/spec/mod.rs | 137 +- ethereum-consensus/src/capella/spec/mod.rs | 137 +- ethereum-consensus/src/deneb/spec/mod.rs | 137 +- ethereum-consensus/src/electra/spec/mod.rs | 4577 +++++++++++++++++ .../src/phase0/block_processing.rs | 138 +- ethereum-consensus/src/phase0/spec/mod.rs | 8 +- 8 files changed, 5131 insertions(+), 152 deletions(-) create mode 100644 ethereum-consensus/src/electra/spec/mod.rs diff --git a/ethereum-consensus/src/altair/block_processing.rs b/ethereum-consensus/src/altair/block_processing.rs index aa928cbaa..687704cbc 100644 --- a/ethereum-consensus/src/altair/block_processing.rs +++ b/ethereum-consensus/src/altair/block_processing.rs @@ -17,7 +17,7 @@ use crate::{ increase_balance, is_valid_indexed_attestation, process_block_header, process_eth1_data, process_operations, process_randao, sync::SyncAggregate, - Attestation, Deposit, DepositMessage, + Attestation, BlsSignature, Bytes32, Deposit, DepositMessage, }, crypto::{eth_fast_aggregate_verify, verify_signature}, domains::DomainType, @@ -30,10 +30,7 @@ use crate::{ ssz::prelude::*, state_transition::{Context, Result}, }; -use std::{ - collections::{HashMap, HashSet}, - iter::zip, -}; +use std::{collections::HashMap, iter::zip}; pub fn process_attestation< const SLOTS_PER_HISTORICAL_ROOT: usize, @@ -159,6 +156,103 @@ pub fn process_attestation< Ok(()) } +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, +>( + 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, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + 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 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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + // NOTE: explicitly return with no error and also no further mutations to `state` + return Ok(()); + } + + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + amount, + context, + ); + + Ok(()) +} + pub fn process_deposit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -196,34 +290,10 @@ pub fn process_deposit< 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 validator_public_keys: HashSet<&BlsPublicKey> = - HashSet::from_iter(state.validators.iter().map(|v| &v.public_key)); - if !validator_public_keys.contains(public_key) { - let mut deposit_message = DepositMessage { - public_key: public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), - amount, - }; - let domain = compute_domain(DomainType::Deposit, None, None, context)?; - let signing_root = compute_signing_root(&mut deposit_message, domain)?; - - if verify_signature(public_key, signing_root.as_ref(), &deposit.data.signature).is_err() { - // NOTE: explicitly return with no error and also no further mutations to `state` - return Ok(()) - } - state.validators.push(get_validator_from_deposit(deposit, context)); - state.balances.push(amount); - state.previous_epoch_participation.push(ParticipationFlags::default()); - state.current_epoch_participation.push(ParticipationFlags::default()); - state.inactivity_scores.push(0) - } else { - let index = state.validators.iter().position(|v| &v.public_key == public_key).unwrap(); - - increase_balance(state, index, amount); - } - - Ok(()) + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) } pub fn process_sync_aggregate< diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index f2ec0c855..b10b848e8 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -4,7 +4,8 @@ pub use crate::{ beacon_block::{BeaconBlock, BeaconBlockBody, SignedBeaconBlock}, beacon_state::BeaconState, block_processing::{ - process_attestation, process_block, process_deposit, process_sync_aggregate, + add_validator_to_registry, apply_deposit, process_attestation, process_block, + process_deposit, process_sync_aggregate, }, constants::{ PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, SYNC_COMMITTEE_SUBNET_COUNT, @@ -187,15 +188,19 @@ pub fn process_attester_slashing< Ok(()) } } -pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Validator { - let amount = deposit.data.amount; +pub fn get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { let effective_balance = Gwei::min( amount - amount % context.effective_balance_increment, context.max_effective_balance, ); Validator { - public_key: deposit.data.public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), + public_key, + withdrawal_credentials, effective_balance, activation_eligibility_epoch: FAR_FUTURE_EPOCH, activation_epoch: FAR_FUTURE_EPOCH, diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index c6a46d1e8..ddc90b439 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -182,6 +182,105 @@ pub fn process_attestation< increase_balance(state, get_beacon_proposer_index(state, context)?, proposer_reward); Ok(()) } +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, +>( + 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, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + 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 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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + return Ok(()); + } + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + amount, + context, + ); + Ok(()) +} pub fn process_deposit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -221,30 +320,10 @@ pub fn process_deposit< } 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 validator_public_keys: HashSet<&BlsPublicKey> = - HashSet::from_iter(state.validators.iter().map(|v| &v.public_key)); - if !validator_public_keys.contains(public_key) { - let mut deposit_message = DepositMessage { - public_key: public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), - amount, - }; - let domain = compute_domain(DomainType::Deposit, None, None, context)?; - let signing_root = compute_signing_root(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), &deposit.data.signature).is_err() { - return Ok(()); - } - state.validators.push(get_validator_from_deposit(deposit, context)); - state.balances.push(amount); - state.previous_epoch_participation.push(ParticipationFlags::default()); - state.current_epoch_participation.push(ParticipationFlags::default()); - state.inactivity_scores.push(0) - } else { - let index = state.validators.iter().position(|v| &v.public_key == public_key).unwrap(); - increase_balance(state, index, amount); - } - Ok(()) + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) } pub fn process_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, @@ -466,15 +545,19 @@ pub fn process_attester_slashing< Ok(()) } } -pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Validator { - let amount = deposit.data.amount; +pub fn get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { let effective_balance = Gwei::min( amount - amount % context.effective_balance_increment, context.max_effective_balance, ); Validator { - public_key: deposit.data.public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), + public_key, + withdrawal_credentials, effective_balance, activation_eligibility_epoch: FAR_FUTURE_EPOCH, activation_epoch: FAR_FUTURE_EPOCH, diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index 64fb9b617..0cce5910f 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -189,6 +189,105 @@ pub fn process_attestation< increase_balance(state, get_beacon_proposer_index(state, context)?, proposer_reward); Ok(()) } +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, +>( + 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, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + 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 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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + return Ok(()); + } + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + amount, + context, + ); + Ok(()) +} pub fn process_deposit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -228,30 +327,10 @@ pub fn process_deposit< } 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 validator_public_keys: HashSet<&BlsPublicKey> = - HashSet::from_iter(state.validators.iter().map(|v| &v.public_key)); - if !validator_public_keys.contains(public_key) { - let mut deposit_message = DepositMessage { - public_key: public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), - amount, - }; - let domain = compute_domain(DomainType::Deposit, None, None, context)?; - let signing_root = compute_signing_root(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), &deposit.data.signature).is_err() { - return Ok(()); - } - state.validators.push(get_validator_from_deposit(deposit, context)); - state.balances.push(amount); - state.previous_epoch_participation.push(ParticipationFlags::default()); - state.current_epoch_participation.push(ParticipationFlags::default()); - state.inactivity_scores.push(0) - } else { - let index = state.validators.iter().position(|v| &v.public_key == public_key).unwrap(); - increase_balance(state, index, amount); - } - Ok(()) + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) } pub fn process_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, @@ -473,15 +552,19 @@ pub fn process_attester_slashing< Ok(()) } } -pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Validator { - let amount = deposit.data.amount; +pub fn get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { let effective_balance = Gwei::min( amount - amount % context.effective_balance_increment, context.max_effective_balance, ); Validator { - public_key: deposit.data.public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), + public_key, + withdrawal_credentials, effective_balance, activation_eligibility_epoch: FAR_FUTURE_EPOCH, activation_epoch: FAR_FUTURE_EPOCH, diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index 7e702bb60..3c2240c26 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -347,6 +347,105 @@ pub fn get_expected_withdrawals< } 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, +>( + 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, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + 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 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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + return Ok(()); + } + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + amount, + context, + ); + Ok(()) +} pub fn process_deposit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -386,30 +485,10 @@ pub fn process_deposit< } 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 validator_public_keys: HashSet<&BlsPublicKey> = - HashSet::from_iter(state.validators.iter().map(|v| &v.public_key)); - if !validator_public_keys.contains(public_key) { - let mut deposit_message = DepositMessage { - public_key: public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), - amount, - }; - let domain = compute_domain(DomainType::Deposit, None, None, context)?; - let signing_root = compute_signing_root(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), &deposit.data.signature).is_err() { - return Ok(()); - } - state.validators.push(get_validator_from_deposit(deposit, context)); - state.balances.push(amount); - state.previous_epoch_participation.push(ParticipationFlags::default()); - state.current_epoch_participation.push(ParticipationFlags::default()); - state.inactivity_scores.push(0) - } else { - let index = state.validators.iter().position(|v| &v.public_key == public_key).unwrap(); - increase_balance(state, index, amount); - } - Ok(()) + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) } pub fn process_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, @@ -631,15 +710,19 @@ pub fn process_attester_slashing< Ok(()) } } -pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Validator { - let amount = deposit.data.amount; +pub fn get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { let effective_balance = Gwei::min( amount - amount % context.effective_balance_increment, context.max_effective_balance, ); Validator { - public_key: deposit.data.public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), + public_key, + withdrawal_credentials, effective_balance, activation_eligibility_epoch: FAR_FUTURE_EPOCH, activation_epoch: FAR_FUTURE_EPOCH, diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs new file mode 100644 index 000000000..b44a12b59 --- /dev/null +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -0,0 +1,4577 @@ +//! WARNING: This file was derived by the `spec-gen` utility. DO NOT EDIT MANUALLY. +pub use crate::primitives::*; +pub use crate::signing::*; +pub use crate::state_transition::{Result, Context, Validation}; +pub use crate::error::*; +use std::cmp; +use std::mem; +use std::collections::{HashSet, HashMap}; +use std::iter::zip; +use crate::ssz::prelude::*; +use integer_sqrt::IntegerSquareRoot; +use crate::crypto::{ + hash, fast_aggregate_verify, eth_aggregate_public_keys, eth_fast_aggregate_verify, +}; +pub use crate::deneb::blob_sidecar::VERSIONED_HASH_VERSION_KZG; +pub use crate::altair::constants::TIMELY_SOURCE_FLAG_INDEX; +pub use crate::altair::constants::TIMELY_TARGET_FLAG_INDEX; +pub use crate::altair::constants::TIMELY_HEAD_FLAG_INDEX; +pub use crate::altair::constants::TIMELY_SOURCE_WEIGHT; +pub use crate::altair::constants::TIMELY_TARGET_WEIGHT; +pub use crate::altair::constants::TIMELY_HEAD_WEIGHT; +pub use crate::altair::constants::SYNC_REWARD_WEIGHT; +pub use crate::altair::constants::PROPOSER_WEIGHT; +pub use crate::altair::constants::WEIGHT_DENOMINATOR; +pub use crate::altair::constants::PARTICIPATION_FLAG_WEIGHTS; +pub use crate::altair::constants::SYNC_COMMITTEE_SUBNET_COUNT; +pub use crate::phase0::constants::BASE_REWARDS_PER_EPOCH; +pub use crate::phase0::constants::DEPOSIT_CONTRACT_TREE_DEPTH; +pub use crate::phase0::constants::JUSTIFICATION_BITS_LENGTH; +pub use crate::phase0::constants::DEPOSIT_DATA_LIST_BOUND; +pub use crate::capella::light_client::EXECUTION_PAYLOAD_INDEX; +pub use crate::capella::light_client::EXECUTION_PAYLOAD_INDEX_FLOOR_LOG_2; +pub use crate::altair::light_client::FINALIZED_ROOT_INDEX; +pub use crate::altair::light_client::FINALIZED_ROOT_INDEX_FLOOR_LOG_2; +pub use crate::altair::light_client::CURRENT_SYNC_COMMITTEE_INDEX; +pub use crate::altair::light_client::CURRENT_SYNC_COMMITTEE_INDEX_FLOOR_LOG_2; +pub use crate::altair::light_client::NEXT_SYNC_COMMITTEE_INDEX; +pub use crate::altair::light_client::NEXT_SYNC_COMMITTEE_INDEX_FLOOR_LOG_2; +pub use crate::deneb::beacon_block::BeaconBlockBody; +pub use crate::deneb::beacon_block::BeaconBlock; +pub use crate::deneb::beacon_block::SignedBeaconBlock; +pub use crate::phase0::beacon_block::BeaconBlockHeader; +pub use crate::phase0::beacon_block::SignedBeaconBlockHeader; +pub use crate::deneb::beacon_state::BeaconState; +pub use crate::phase0::beacon_state::Fork; +pub use crate::phase0::beacon_state::ForkData; +pub use crate::phase0::beacon_state::HistoricalBatch; +pub use crate::phase0::beacon_state::HistoricalSummary; +pub use crate::deneb::blinded_beacon_block::BlindedBeaconBlockBody; +pub use crate::deneb::blinded_beacon_block::BlindedBeaconBlock; +pub use crate::deneb::blinded_beacon_block::SignedBlindedBeaconBlock; +pub use crate::deneb::blob_sidecar::BlobIdentifier; +pub use crate::deneb::blob_sidecar::BlobsBundle; +pub use crate::deneb::blob_sidecar::BlobSidecar; +pub use crate::capella::bls_to_execution_change::BlsToExecutionChange; +pub use crate::capella::bls_to_execution_change::SignedBlsToExecutionChange; +pub use crate::deneb::execution_engine::NewPayloadRequest; +pub use crate::deneb::execution_payload::ExecutionPayload; +pub use crate::deneb::execution_payload::ExecutionPayloadHeader; +pub use crate::bellatrix::fork_choice::PowBlock; +pub use crate::deneb::light_client::LightClientHeader; +pub use crate::deneb::light_client::LightClientBootstrap; +pub use crate::deneb::light_client::LightClientUpdate; +pub use crate::deneb::light_client::LightClientFinalityUpdate; +pub use crate::deneb::light_client::LightClientOptimisticUpdate; +pub use crate::phase0::operations::Checkpoint; +pub use crate::phase0::operations::AttestationData; +pub use crate::phase0::operations::IndexedAttestation; +pub use crate::phase0::operations::PendingAttestation; +pub use crate::phase0::operations::Attestation; +pub use crate::phase0::operations::Eth1Data; +pub use crate::phase0::operations::DepositMessage; +pub use crate::phase0::operations::DepositData; +pub use crate::phase0::operations::ProposerSlashing; +pub use crate::phase0::operations::AttesterSlashing; +pub use crate::phase0::operations::Deposit; +pub use crate::phase0::operations::VoluntaryExit; +pub use crate::phase0::operations::SignedVoluntaryExit; +pub use crate::altair::sync::SyncAggregate; +pub use crate::altair::sync::SyncCommittee; +pub use crate::altair::validator::SyncCommitteeMessage; +pub use crate::altair::validator::SyncCommitteeContribution; +pub use crate::altair::validator::ContributionAndProof; +pub use crate::altair::validator::SignedContributionAndProof; +pub use crate::altair::validator::SyncAggregatorSelectionData; +pub use crate::phase0::validator::Validator; +pub use crate::phase0::validator::Eth1Block; +pub use crate::phase0::validator::AggregateAndProof; +pub use crate::phase0::validator::SignedAggregateAndProof; +pub use crate::capella::withdrawal::Withdrawal; +pub use crate::deneb::blob_sidecar::Blob; +pub use crate::bellatrix::execution_payload::Transaction; +pub fn verify_blob_sidecar_inclusion_proof< + const BYTES_PER_BLOB: usize, + const KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: usize, + BlockBody: SimpleSerialize, +>( + blob_sidecar: &mut BlobSidecar, +) -> Result<(), Error> { + let path = &["blob_kzg_commitments".into(), blob_sidecar.index.into()]; + let g_index = BlockBody::generalized_index(path)?; + let subtree_index = get_subtree_index(g_index)?; + let leaf = blob_sidecar.kzg_commitment.hash_tree_root()?; + let branch = blob_sidecar.kzg_commitment_inclusion_proof.as_ref(); + let root = blob_sidecar.signed_block_header.message.body_root; + is_valid_merkle_branch( + leaf, + branch, + KZG_COMMITMENT_INCLUSION_PROOF_DEPTH, + subtree_index, + root, + ) + .map_err(Into::into) +} +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, +>( + 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, + >, + attestation: &Attestation, + context: &Context, +) -> Result<()> { + let data = &attestation.data; + let is_previous = data.target.epoch == get_previous_epoch(state, context); + let current_epoch = get_current_epoch(state, context); + let is_current = data.target.epoch == current_epoch; + let valid_target_epoch = is_previous || is_current; + if !valid_target_epoch { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::InvalidTargetEpoch { + target: data.target.epoch, + current: current_epoch, + }), + ), + ); + } + let attestation_epoch = compute_epoch_at_slot(data.slot, context); + if data.target.epoch != attestation_epoch { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::InvalidSlot { + slot: data.slot, + epoch: attestation_epoch, + target: data.target.epoch, + }), + ), + ); + } + let attestation_is_timely = data.slot + context.min_attestation_inclusion_delay + <= state.slot; + if !attestation_is_timely { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::NoDelay { + attestation_slot: data.slot, + state_slot: state.slot, + required_delay: context.min_attestation_inclusion_delay, + }), + ), + ); + } + let committee_count = get_committee_count_per_slot( + state, + data.target.epoch, + context, + ); + if data.index >= committee_count { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::InvalidIndex { + index: data.index, + upper_bound: committee_count, + }), + ), + ); + } + let committee = get_beacon_committee(state, data.slot, data.index, context)?; + if attestation.aggregation_bits.len() != committee.len() { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::Bitfield { + expected_length: committee.len(), + length: attestation.aggregation_bits.len(), + }), + ), + ); + } + let inclusion_delay = state.slot - data.slot; + let participation_flag_indices = get_attestation_participation_flag_indices( + state, + data, + inclusion_delay, + context, + )?; + is_valid_indexed_attestation( + state, + &mut get_indexed_attestation(state, attestation, context)?, + context, + )?; + let attesting_indices = get_attesting_indices( + state, + data, + &attestation.aggregation_bits, + context, + )?; + let mut proposer_reward_numerator = 0; + for index in attesting_indices { + for (flag_index, weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() { + if is_current { + if participation_flag_indices.contains(&flag_index) + && !has_flag(state.current_epoch_participation[index], flag_index) + { + state + .current_epoch_participation[index] = add_flag( + state.current_epoch_participation[index], + flag_index, + ); + proposer_reward_numerator + += get_base_reward(state, index, context)? * weight; + } + } else if participation_flag_indices.contains(&flag_index) + && !has_flag(state.previous_epoch_participation[index], flag_index) + { + state + .previous_epoch_participation[index] = add_flag( + state.previous_epoch_participation[index], + flag_index, + ); + proposer_reward_numerator + += get_base_reward(state, index, context)? * weight; + } + } + } + let proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) + * WEIGHT_DENOMINATOR / PROPOSER_WEIGHT; + let proposer_reward = proposer_reward_numerator / proposer_reward_denominator; + increase_balance(state, get_beacon_proposer_index(state, context)?, proposer_reward); + Ok(()) +} +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 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, +>( + 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, + >, + body: &mut 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, + >, + context: &Context, +) -> Result<()> { + let payload = &mut body.execution_payload; + let parent_hash_invalid = payload.parent_hash + != state.latest_execution_payload_header.block_hash; + if parent_hash_invalid { + return Err( + invalid_operation_error( + InvalidExecutionPayload::InvalidParentHash { + provided: payload.parent_hash.clone(), + expected: state.latest_execution_payload_header.block_hash.clone(), + } + .into(), + ), + ); + } + let current_epoch = get_current_epoch(state, context); + let randao_mix = get_randao_mix(state, current_epoch); + if &payload.prev_randao != randao_mix { + return Err( + invalid_operation_error( + InvalidExecutionPayload::InvalidPrevRandao { + provided: payload.prev_randao.clone(), + expected: randao_mix.clone(), + } + .into(), + ), + ); + } + let timestamp = compute_timestamp_at_slot(state, state.slot, context)?; + if payload.timestamp != timestamp { + return Err( + invalid_operation_error( + InvalidExecutionPayload::InvalidTimestamp { + provided: payload.timestamp, + expected: timestamp, + } + .into(), + ), + ); + } + if body.blob_kzg_commitments.len() > context.max_blobs_per_block { + return Err( + invalid_operation_error( + InvalidExecutionPayload::InvalidBlobCommitments { + provided: body.blob_kzg_commitments.len(), + limit: context.max_blobs_per_block, + } + .into(), + ), + ); + } + let versioned_hashes = body + .blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect::>(); + let execution_engine = context.execution_engine(); + let new_payload_request = NewPayloadRequest { + execution_payload: payload.clone(), + versioned_hashes, + parent_beacon_block_root: state.latest_block_header.parent_root, + }; + execution_engine.verify_and_notify_new_payload(&new_payload_request)?; + state + .latest_execution_payload_header = ExecutionPayloadHeader { + parent_hash: payload.parent_hash.clone(), + fee_recipient: payload.fee_recipient.clone(), + state_root: payload.state_root.clone(), + receipts_root: payload.receipts_root.clone(), + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao.clone(), + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash.clone(), + transactions_root: payload.transactions.hash_tree_root()?, + withdrawals_root: payload.withdrawals.hash_tree_root()?, + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + }; + Ok(()) +} +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, +>( + 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, + >, + signed_voluntary_exit: &mut SignedVoluntaryExit, + context: &Context, +) -> Result<()> { + let voluntary_exit = &mut 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 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, +>( + 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, + >, + block: &mut 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, + >, + context: &Context, +) -> Result<()> { + process_block_header(state, block, context)?; + process_withdrawals(state, &block.body.execution_payload, context)?; + process_execution_payload(state, &mut block.body, context)?; + process_randao(state, &block.body, context)?; + process_eth1_data(state, &block.body, context); + process_operations(state, &mut 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, +>( + 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, + >, + signed_address_change: &mut SignedBlsToExecutionChange, + context: &Context, +) -> Result<()> { + let address_change = &mut 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 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, +>( + 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, + >, + body: &mut 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, + >, + 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_mut() + .try_for_each(|op| process_proposer_slashing(state, op, context))?; + body.attester_slashings + .iter_mut() + .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_mut().try_for_each(|op| process_deposit(state, op, context))?; + body.voluntary_exits + .iter_mut() + .try_for_each(|op| process_voluntary_exit(state, op, context))?; + body.bls_to_execution_changes + .iter_mut() + .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 MAX_BYTES_PER_TRANSACTION: usize, + const MAX_TRANSACTIONS_PER_PAYLOAD: usize, + const MAX_WITHDRAWALS_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, + >, + execution_payload: &ExecutionPayload< + BYTES_PER_LOGS_BLOOM, + MAX_EXTRA_DATA_BYTES, + MAX_BYTES_PER_TRANSACTION, + MAX_TRANSACTIONS_PER_PAYLOAD, + MAX_WITHDRAWALS_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, +>( + 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, + >, + 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, +>( + 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, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + 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 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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + return Ok(()); + } + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; + 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_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, +>( + 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, + >, + 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 mut root_at_slot = *get_block_root_at_slot(state, previous_slot)?; + let signing_root = compute_signing_root(&mut 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, +>( + 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, + >, + proposer_slashing: &mut 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 [ + &mut proposer_slashing.signed_header_1, + &mut proposer_slashing.signed_header_2, + ] { + let signing_root = compute_signing_root(&mut 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, +>( + 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, + >, + attester_slashing: &mut AttesterSlashing, + context: &Context, +) -> Result<()> { + let attestation_1 = &mut attester_slashing.attestation_1; + let attestation_2 = &mut 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 get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { + let effective_balance = Gwei::min( + amount - amount % context.effective_balance_increment, + context.max_effective_balance, + ); + Validator { + public_key, + withdrawal_credentials, + effective_balance, + activation_eligibility_epoch: FAR_FUTURE_EPOCH, + activation_epoch: FAR_FUTURE_EPOCH, + exit_epoch: FAR_FUTURE_EPOCH, + withdrawable_epoch: FAR_FUTURE_EPOCH, + ..Default::default() + } +} +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 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, +>( + 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, + >, + block: &mut 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, + >, + 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 xor(a: &Bytes32, b: &Bytes32) -> Bytes32 { + let inner = a.iter().zip(b.iter()).map(|(a, b)| a ^ b).collect::>(); + ByteVector::<32>::try_from(inner.as_ref()).unwrap() +} +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 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, +>( + 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, + >, + 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, + >, + context: &Context, +) -> Result<()> { + let mut 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(&mut 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 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, +>( + 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, + >, + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, +) -> 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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 mut 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + context: &Context, +) -> bool { + get_finality_delay(state, context) > context.min_epochs_to_inactivity_penalty +} +pub fn initialize_beacon_state_from_eth1< + const BYTES_PER_LOGS_BLOOM: usize, + const MAX_EXTRA_DATA_BYTES: usize, + 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, +>( + eth1_block_hash: Hash32, + eth1_timestamp: u64, + deposits: &mut [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, + >, +> { + let fork = Fork { + previous_version: context.deneb_fork_version, + current_version: context.deneb_fork_version, + epoch: GENESIS_EPOCH, + }; + let eth1_data = Eth1Data { + block_hash: eth1_block_hash.clone(), + deposit_count: deposits.len() as u64, + ..Default::default() + }; + let mut latest_block_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, + >::default(); + let body_root = latest_block_body.hash_tree_root()?; + let latest_block_header = BeaconBlockHeader { + body_root, + ..Default::default() + }; + let randao_mixes = Vector::try_from( + std::iter::repeat(eth1_block_hash) + .take(context.epochs_per_historical_vector as usize) + .collect::>(), + ) + .map_err(|(_, err)| err)?; + let execution_payload_header = execution_payload_header.cloned().unwrap_or_default(); + let mut state = BeaconState { + genesis_time: eth1_timestamp + context.genesis_delay, + fork, + eth1_data, + latest_block_header, + randao_mixes, + latest_execution_payload_header: execution_payload_header, + ..Default::default() + }; + let mut leaves = List::::default(); + for deposit in deposits.iter_mut() { + leaves.push(deposit.data.clone()); + state.eth1_data.deposit_root = leaves.hash_tree_root()?; + process_deposit(&mut state, deposit, context)?; + } + for i in 0..state.validators.len() { + let validator = &mut state.validators[i]; + let balance = state.balances[i]; + let effective_balance = Gwei::min( + balance - balance % context.effective_balance_increment, + context.max_effective_balance, + ); + validator.effective_balance = effective_balance; + if validator.effective_balance == context.max_effective_balance { + validator.activation_eligibility_epoch = GENESIS_EPOCH; + validator.activation_epoch = GENESIS_EPOCH; + } + } + state.genesis_validators_root = state.validators.hash_tree_root()?; + let sync_committee = get_next_sync_committee(&state, context)?; + state.current_sync_committee = sync_committee.clone(); + state.next_sync_committee = sync_committee; + Ok(state) +} +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, +>( + 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, + >, + 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 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, +>( + genesis_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, + >, +) -> 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, + >, +> { + Ok(BeaconBlock { + state_root: genesis_state.hash_tree_root()?, + ..Default::default() + }) +} +pub fn kzg_commitment_to_versioned_hash( + kzg_commitment: &KzgCommitment, +) -> VersionedHash { + let mut result = VersionedHash::default(); + result[0] = VERSIONED_HASH_VERSION_KZG; + result[1..].copy_from_slice(&hash(kzg_commitment.as_ref())[1..]); + result +} +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, +>( + 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, + >, + 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, +>( + 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, + >, + context: &Context, +) -> usize { + let limit = context.max_per_epoch_activation_churn_limit as usize; + limit.min(get_validator_churn_limit(state, context)) +} +pub fn has_eth1_withdrawal_credential(validator: &Validator) -> bool { + validator.withdrawal_credentials[0] == ETH1_ADDRESS_WITHDRAWAL_PREFIX +} +pub fn is_fully_withdrawable_validator( + validator: &Validator, + balance: Gwei, + epoch: Epoch, +) -> bool { + has_eth1_withdrawal_credential(validator) && validator.withdrawable_epoch <= epoch + && balance > 0 +} +pub fn is_partially_withdrawable_validator( + validator: &Validator, + balance: Gwei, + context: &Context, +) -> bool { + let has_max_effective_balance = validator.effective_balance + == context.max_effective_balance; + let has_excess_balance = balance > context.max_effective_balance; + has_eth1_withdrawal_credential(validator) && has_max_effective_balance + && has_excess_balance +} +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, +>( + 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, + >, + 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 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, +>( + 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, + >, + slashed_index: ValidatorIndex, + whistleblower_index: Option, + context: &Context, +) -> Result<()> { + 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_bellatrix, + ); + 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; + 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(()) +} +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, +>( + 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, + >, +) -> 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 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, +>( + 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, + >, + 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, + >, +) -> 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 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, +>( + 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, + >, + 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, + >, +) -> 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, +>( + 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, + >, + 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 add_flag(flags: ParticipationFlags, flag_index: usize) -> ParticipationFlags { + let flag = 2u8.pow(flag_index as u32); + flags | flag +} +pub fn has_flag(flags: ParticipationFlags, flag_index: usize) -> bool { + let flag = 2u8.pow(flag_index as u32); + flags & flag == flag +} +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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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_active_validator(validator: &Validator, epoch: Epoch) -> bool { + validator.activation_epoch <= epoch && epoch < validator.exit_epoch +} +pub fn is_eligible_for_activation_queue( + validator: &Validator, + context: &Context, +) -> bool { + validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH + && validator.effective_balance == context.max_effective_balance +} +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, +>( + 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, + >, + validator: &Validator, +) -> bool { + validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch + && validator.activation_epoch == FAR_FUTURE_EPOCH +} +pub fn is_slashable_validator(validator: &Validator, epoch: Epoch) -> bool { + !validator.slashed && validator.activation_epoch <= epoch + && epoch < validator.withdrawable_epoch +} +pub fn is_slashable_attestation_data( + data_1: &AttestationData, + data_2: &AttestationData, +) -> bool { + let double_vote = data_1 != data_2 && data_1.target.epoch == data_2.target.epoch; + let surround_vote = data_1.source.epoch < data_2.source.epoch + && data_2.target.epoch < data_1.target.epoch; + double_vote || surround_vote +} +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, +>( + 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, + >, + indexed_attestation: &mut 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(&mut 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 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, +>( + 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, + >, + signed_block: &mut 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, + >, + 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(&mut 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, +>( + 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, + >, + 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, +>( + 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, + >, + context: &Context, +) -> Epoch { + compute_epoch_at_slot(state.slot, context) +} +pub fn compute_shuffled_index( + mut index: usize, + index_count: usize, + seed: &Bytes32, + context: &Context, +) -> Result { + if index >= index_count { + return Err(Error::InvalidShufflingIndex { + index, + total: index_count, + }); + } + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in 0..context.shuffle_round_count { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = (u64::from_le_bytes(pivot_bytes) as usize) % index_count; + let flip = (pivot + index_count - index) % index_count; + let position = cmp::max(index, flip); + let position_bytes: [u8; 4] = ((position / 256) as u32).to_le_bytes(); + source_input[32] = current_round as u8; + source_input[33..].copy_from_slice(&position_bytes); + let source = hash(source_input); + let byte = source.as_ref()[(position % 256) / 8]; + let bit = (byte >> (position % 8)) % 2; + index = if bit != 0 { flip } else { index }; + } + Ok(index) +} +pub fn compute_shuffled_indices( + indices: &[ValidatorIndex], + seed: &Bytes32, + context: &Context, +) -> ShuffledIndices { + let mut input = indices.to_vec(); + if input.is_empty() { + return input; + } + let index_count = input.len(); + let mut pivot_input = [0u8; 33]; + pivot_input[..32].copy_from_slice(seed.as_ref()); + let mut source_input = [0u8; 37]; + source_input[..32].copy_from_slice(seed.as_ref()); + for current_round in (0..=context.shuffle_round_count - 1).rev() { + pivot_input[32] = current_round as u8; + let pivot_bytes: [u8; 8] = hash(pivot_input).as_ref()[..8].try_into().unwrap(); + let pivot = u64::from_le_bytes(pivot_bytes) as usize % index_count; + source_input[32] = current_round as u8; + let position = (pivot >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + let mut source = hash(source_input); + let mut byte_source = source[(pivot & 0xff) >> 3]; + let mirror = (pivot + 1) >> 1; + for i in 0..mirror { + let j = pivot - i; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + let end = index_count - 1; + let position = (end >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + byte_source = source[(end & 0xff) >> 3]; + let mirror = (pivot + index_count + 1) >> 1; + for (k, i) in ((pivot + 1)..mirror).enumerate() { + let j = end - k; + if j & 0xff == 0xff { + let position = (j >> 8) as u32; + source_input[33..].copy_from_slice(&position.to_le_bytes()); + source = hash(source_input); + } + if j & 0x07 == 0x07 { + byte_source = source[(j & 0xff) >> 3]; + } + let bit_source = (byte_source >> (j & 0x07)) & 0x01; + if bit_source == 1 { + input.swap(i, j); + } + } + } + input +} +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, +>( + 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, + >, + 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, +>( + 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, + >, + 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 compute_committee( + indices: &[ValidatorIndex], + seed: &Bytes32, + index: usize, + count: usize, + context: &Context, +) -> Result> { + if cfg!(feature = "shuffling") { + let shuffled_indices = compute_shuffled_indices(indices, seed, context); + let index_count = indices.len(); + let start = index_count * index / count; + let end = index_count * (index + 1) / count; + let committee = shuffled_indices[start..end].to_vec(); + Ok(committee) + } else { + let start = indices.len() * index / count; + let end = indices.len() * (index + 1) / count; + let mut committee = vec![0usize; end - start]; + for i in start..end { + let index = compute_shuffled_index(i, indices.len(), seed, context)?; + committee[i - start] = indices[index]; + } + Ok(committee) + } +} +pub fn compute_epoch_at_slot(slot: Slot, context: &Context) -> Epoch { + slot / context.slots_per_epoch +} +pub fn compute_start_slot_at_epoch(epoch: Epoch, context: &Context) -> Slot { + epoch * context.slots_per_epoch +} +pub fn compute_activation_exit_epoch(epoch: Epoch, context: &Context) -> Epoch { + epoch + 1 + context.max_seed_lookahead +} +pub fn compute_fork_digest( + current_version: Version, + genesis_validators_root: Root, +) -> Result { + let fork_data_root = compute_fork_data_root( + current_version, + genesis_validators_root, + )?; + let digest = &fork_data_root[..4]; + Ok(digest.try_into().expect("should not fail")) +} +pub fn compute_domain( + domain_type: DomainType, + fork_version: Option, + genesis_validators_root: Option, + context: &Context, +) -> Result { + let fork_version = fork_version.unwrap_or(context.genesis_fork_version); + let genesis_validators_root = genesis_validators_root.unwrap_or_default(); + let fork_data_root = compute_fork_data_root(fork_version, genesis_validators_root)?; + let mut domain = Domain::default(); + domain[..4].copy_from_slice(&domain_type.as_bytes()); + domain[4..].copy_from_slice(&fork_data_root[..28]); + Ok(domain) +} +pub fn compute_fork_data_root( + current_version: Version, + genesis_validators_root: Root, +) -> Result { + ForkData { + current_version, + genesis_validators_root, + } + .hash_tree_root() + .map_err(Error::Merkleization) +} +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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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 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, +>( + 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, + >, + attestation: &Attestation, + context: &Context, +) -> Result> { + let bits = &attestation.aggregation_bits; + let mut attesting_indices = get_attesting_indices( + state, + &attestation.data, + bits, + context, + )? + .into_iter() + .collect::>(); + 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 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, +>( + 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, + >, + data: &AttestationData, + bits: &Bitlist, + context: &Context, +) -> Result> { + let committee = get_beacon_committee(state, data.slot, data.index, context)?; + if bits.len() != committee.len() { + return Err( + invalid_operation_error( + InvalidOperation::Attestation(InvalidAttestation::Bitfield { + expected_length: committee.len(), + length: bits.len(), + }), + ), + ); + } + let mut indices = HashSet::with_capacity(bits.capacity()); + for (i, validator_index) in committee.iter().enumerate() { + if bits[i] { + indices.insert(*validator_index); + } + } + Ok(indices) +} +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, +>( + 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, + >, + 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, +>( + 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, + >, + index: ValidatorIndex, + delta: Gwei, +) { + if delta > state.balances[index] { + state.balances[index] = 0 + } else { + state.balances[index] -= delta + } +} +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, +>( + 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, + >, + index: ValidatorIndex, + context: &Context, +) -> Result<()> { + if state.validators[index].exit_epoch != FAR_FUTURE_EPOCH { + return Ok(()); + } + let mut exit_epochs: Vec = state + .validators + .iter() + .filter(|v| v.exit_epoch != FAR_FUTURE_EPOCH) + .map(|v| v.exit_epoch) + .collect(); + exit_epochs + .push(compute_activation_exit_epoch(get_current_epoch(state, context), context)); + let mut exit_queue_epoch = *exit_epochs.iter().max().unwrap(); + let exit_queue_churn = state + .validators + .iter() + .filter(|v| v.exit_epoch == exit_queue_epoch) + .count(); + if exit_queue_churn >= get_validator_churn_limit(state, context) { + exit_queue_epoch += 1; + } + 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 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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, +>( + 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, + >, + 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 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, +>( + 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, + >, + signed_block: &mut 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, + >, + 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 = &mut 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 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, +>( + 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, + >, + signed_block: &mut 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, + >, + 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/ethereum-consensus/src/phase0/block_processing.rs b/ethereum-consensus/src/phase0/block_processing.rs index 9763867be..c5dd1ca77 100644 --- a/ethereum-consensus/src/phase0/block_processing.rs +++ b/ethereum-consensus/src/phase0/block_processing.rs @@ -22,7 +22,9 @@ use crate::{ }, validator::Validator, }, - primitives::{BlsPublicKey, Bytes32, DomainType, Gwei, ValidatorIndex, FAR_FUTURE_EPOCH}, + primitives::{ + BlsPublicKey, BlsSignature, Bytes32, DomainType, Gwei, ValidatorIndex, FAR_FUTURE_EPOCH, + }, signing::{compute_signing_root, verify_signed_data}, ssz::prelude::*, state_transition::{Context, Result}, @@ -290,16 +292,20 @@ pub fn process_attestation< Ok(()) } -pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Validator { - let amount = deposit.data.amount; +pub fn get_validator_from_deposit( + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) -> Validator { let effective_balance = Gwei::min( amount - amount % context.effective_balance_increment, context.max_effective_balance, ); Validator { - public_key: deposit.data.public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), + public_key, + withdrawal_credentials, effective_balance, activation_eligibility_epoch: FAR_FUTURE_EPOCH, activation_epoch: FAR_FUTURE_EPOCH, @@ -311,6 +317,100 @@ pub fn get_validator_from_deposit(deposit: &Deposit, context: &Context) -> Valid pub(crate) const DEPOSIT_MERKLE_DEPTH: usize = DEPOSIT_CONTRACT_TREE_DEPTH + 1; +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 PENDING_ATTESTATIONS_BOUND: 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, + PENDING_ATTESTATIONS_BOUND, + >, + public_key: BlsPublicKey, + withdrawal_credentials: Bytes32, + amount: u64, + context: &Context, +) { + state.validators.push(get_validator_from_deposit( + public_key, + withdrawal_credentials, + amount, + context, + )); + state.balances.push(amount); +} + +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 PENDING_ATTESTATIONS_BOUND: 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, + PENDING_ATTESTATIONS_BOUND, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + + let mut 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(&mut deposit_message, domain)?; + if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { + // NOTE: explicitly return with no error and also no further mutations to `state` + return Ok(()); + } + + add_validator_to_registry( + state, + public_key.clone(), + withdrawal_credentials.clone(), + amount, + context, + ); + + Ok(()) +} + pub fn process_deposit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -353,32 +453,10 @@ pub fn process_deposit< 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 validator_public_keys: HashSet<&BlsPublicKey> = - HashSet::from_iter(state.validators.iter().map(|v| &v.public_key)); - if !validator_public_keys.contains(public_key) { - let mut deposit_message = DepositMessage { - public_key: public_key.clone(), - withdrawal_credentials: deposit.data.withdrawal_credentials.clone(), - amount, - }; - let domain = compute_domain(DomainType::Deposit, None, None, context)?; - let signing_root = compute_signing_root(&mut deposit_message, domain)?; - - if verify_signature(public_key, signing_root.as_ref(), &deposit.data.signature).is_err() { - // NOTE: explicitly return with no error and also no further mutations to `state` - return Ok(()) - } - - state.validators.push(get_validator_from_deposit(deposit, context)); - state.balances.push(amount); - } else { - let index = state.validators.iter().position(|v| &v.public_key == public_key).unwrap(); - - increase_balance(state, index, amount); - } - - Ok(()) + let signature = &deposit.data.signature; + apply_deposit(state, public_key, withdrawal_credentials, amount, signature, context) } pub fn process_voluntary_exit< diff --git a/ethereum-consensus/src/phase0/spec/mod.rs b/ethereum-consensus/src/phase0/spec/mod.rs index 831187e39..69a6a4f1a 100644 --- a/ethereum-consensus/src/phase0/spec/mod.rs +++ b/ethereum-consensus/src/phase0/spec/mod.rs @@ -8,10 +8,10 @@ pub use crate::{ }, beacon_state::{BeaconState, Fork, ForkData, HistoricalBatch, HistoricalSummary}, block_processing::{ - get_validator_from_deposit, process_attestation, process_attester_slashing, - process_block, process_block_header, process_deposit, process_eth1_data, - process_operations, process_proposer_slashing, process_randao, process_voluntary_exit, - xor, + add_validator_to_registry, apply_deposit, get_validator_from_deposit, + process_attestation, process_attester_slashing, process_block, process_block_header, + process_deposit, process_eth1_data, process_operations, process_proposer_slashing, + process_randao, process_voluntary_exit, xor, }, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, From fc3b796dc1f2b232c87a56defa2c4dde93dbc574 Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Wed, 10 Apr 2024 11:03:22 -0600 Subject: [PATCH 2/5] minor changes from PR comments --- .../src/altair/block_processing.rs | 115 +-------- ethereum-consensus/src/altair/genesis.rs | 6 +- ethereum-consensus/src/altair/spec/mod.rs | 104 +++++++- ethereum-consensus/src/bellatrix/spec/mod.rs | 212 +++++++++-------- ethereum-consensus/src/capella/spec/mod.rs | 212 +++++++++-------- ethereum-consensus/src/deneb/spec/mod.rs | 212 +++++++++-------- ethereum-consensus/src/electra/spec/mod.rs | 222 +++++++++--------- .../src/phase0/block_processing.rs | 6 +- ethereum-consensus/src/phase0/spec/mod.rs | 2 +- 9 files changed, 551 insertions(+), 540 deletions(-) diff --git a/ethereum-consensus/src/altair/block_processing.rs b/ethereum-consensus/src/altair/block_processing.rs index 687704cbc..b675c1a52 100644 --- a/ethereum-consensus/src/altair/block_processing.rs +++ b/ethereum-consensus/src/altair/block_processing.rs @@ -2,7 +2,7 @@ use crate::{ altair::{ beacon_block::BeaconBlock, beacon_state::BeaconState, - compute_domain, compute_epoch_at_slot, + compute_epoch_at_slot, constants::{ PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, SYNC_REWARD_WEIGHT, WEIGHT_DENOMINATOR, }, @@ -17,17 +17,13 @@ use crate::{ increase_balance, is_valid_indexed_attestation, process_block_header, process_eth1_data, process_operations, process_randao, sync::SyncAggregate, - Attestation, BlsSignature, Bytes32, Deposit, DepositMessage, + Attestation, Bytes32, }, - crypto::{eth_fast_aggregate_verify, verify_signature}, + crypto::eth_fast_aggregate_verify, domains::DomainType, - error::{ - invalid_operation_error, InvalidAttestation, InvalidDeposit, InvalidOperation, - InvalidSyncAggregate, - }, + error::{invalid_operation_error, InvalidAttestation, InvalidOperation, InvalidSyncAggregate}, primitives::{BlsPublicKey, ParticipationFlags, ValidatorIndex}, signing::compute_signing_root, - ssz::prelude::*, state_transition::{Context, Result}, }; use std::{collections::HashMap, iter::zip}; @@ -193,109 +189,6 @@ pub fn add_validator_to_registry< state.inactivity_scores.push(0) } -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, ->( - 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, - >, - public_key: &BlsPublicKey, - withdrawal_credentials: &Bytes32, - amount: u64, - signature: &BlsSignature, - context: &Context, -) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); - if let Some(index) = index { - increase_balance(state, index, amount); - return Ok(()); - } - - let mut 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(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { - // NOTE: explicitly return with no error and also no further mutations to `state` - return Ok(()); - } - - add_validator_to_registry( - state, - public_key.clone(), - withdrawal_credentials.clone(), - 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, ->( - 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, - >, - deposit: &mut Deposit, - context: &Context, -) -> Result<()> { - let leaf = deposit.data.hash_tree_root()?; - let branch = &deposit.proof; - let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; - 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_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/altair/genesis.rs b/ethereum-consensus/src/altair/genesis.rs index 6f9332130..1de94a433 100644 --- a/ethereum-consensus/src/altair/genesis.rs +++ b/ethereum-consensus/src/altair/genesis.rs @@ -1,8 +1,8 @@ use crate::{ altair::{ - beacon_block::BeaconBlockBody, beacon_state::BeaconState, - block_processing::process_deposit, helpers::get_next_sync_committee, BeaconBlockHeader, - Deposit, DepositData, Eth1Data, Fork, DEPOSIT_DATA_LIST_BOUND, + beacon_block::BeaconBlockBody, beacon_state::BeaconState, helpers::get_next_sync_committee, + process_deposit, BeaconBlockHeader, Deposit, DepositData, Eth1Data, Fork, + DEPOSIT_DATA_LIST_BOUND, }, primitives::{Gwei, Hash32, GENESIS_EPOCH}, ssz::prelude::*, diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index b10b848e8..289cce777 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -4,8 +4,7 @@ pub use crate::{ beacon_block::{BeaconBlock, BeaconBlockBody, SignedBeaconBlock}, beacon_state::BeaconState, block_processing::{ - add_validator_to_registry, apply_deposit, process_attestation, process_block, - process_deposit, process_sync_aggregate, + add_validator_to_registry, process_attestation, process_block, process_sync_aggregate, }, constants::{ PARTICIPATION_FLAG_WEIGHTS, PROPOSER_WEIGHT, SYNC_COMMITTEE_SUBNET_COUNT, @@ -43,6 +42,7 @@ pub use crate::{ phase0::{ beacon_block::{BeaconBlockHeader, SignedBeaconBlockHeader}, beacon_state::{Fork, ForkData, HistoricalBatch, HistoricalSummary}, + block_processing::DEPOSIT_MERKLE_DEPTH, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, JUSTIFICATION_BITS_LENGTH, @@ -209,6 +209,106 @@ pub fn get_validator_from_deposit( ..Default::default() } } +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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, DEPOSIT_MERKLE_DEPTH, index, root).is_err() { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::InvalidProof { + leaf, + branch: branch.to_vec(), + depth: DEPOSIT_MERKLE_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_voluntary_exit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index ddc90b439..5365885b1 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -42,6 +42,7 @@ pub use crate::{ phase0::{ beacon_block::{BeaconBlockHeader, SignedBeaconBlockHeader}, beacon_state::{Fork, ForkData, HistoricalBatch, HistoricalSummary}, + block_processing::DEPOSIT_MERKLE_DEPTH, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, JUSTIFICATION_BITS_LENGTH, @@ -222,109 +223,6 @@ pub fn add_validator_to_registry< state.current_epoch_participation.push(ParticipationFlags::default()); state.inactivity_scores.push(0) } -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, ->( - 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, - >, - public_key: &BlsPublicKey, - withdrawal_credentials: &Bytes32, - amount: u64, - signature: &BlsSignature, - context: &Context, -) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); - if let Some(index) = index { - increase_balance(state, index, amount); - return Ok(()); - } - let mut 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(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { - return Ok(()); - } - add_validator_to_registry( - state, - public_key.clone(), - withdrawal_credentials.clone(), - 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, ->( - 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, - >, - deposit: &mut Deposit, - context: &Context, -) -> Result<()> { - let leaf = deposit.data.hash_tree_root()?; - let branch = &deposit.proof; - let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; - 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_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -566,6 +464,114 @@ pub fn get_validator_from_deposit( ..Default::default() } } +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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, DEPOSIT_MERKLE_DEPTH, index, root).is_err() { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::InvalidProof { + leaf, + branch: branch.to_vec(), + depth: DEPOSIT_MERKLE_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_voluntary_exit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index 0cce5910f..b77cf3c23 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -49,6 +49,7 @@ pub use crate::{ phase0::{ beacon_block::{BeaconBlockHeader, SignedBeaconBlockHeader}, beacon_state::{Fork, ForkData, HistoricalBatch, HistoricalSummary}, + block_processing::DEPOSIT_MERKLE_DEPTH, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, JUSTIFICATION_BITS_LENGTH, @@ -229,109 +230,6 @@ pub fn add_validator_to_registry< state.current_epoch_participation.push(ParticipationFlags::default()); state.inactivity_scores.push(0) } -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, ->( - 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, - >, - public_key: &BlsPublicKey, - withdrawal_credentials: &Bytes32, - amount: u64, - signature: &BlsSignature, - context: &Context, -) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); - if let Some(index) = index { - increase_balance(state, index, amount); - return Ok(()); - } - let mut 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(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { - return Ok(()); - } - add_validator_to_registry( - state, - public_key.clone(), - withdrawal_credentials.clone(), - 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, ->( - 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, - >, - deposit: &mut Deposit, - context: &Context, -) -> Result<()> { - let leaf = deposit.data.hash_tree_root()?; - let branch = &deposit.proof; - let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; - 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_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -573,6 +471,114 @@ pub fn get_validator_from_deposit( ..Default::default() } } +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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, DEPOSIT_MERKLE_DEPTH, index, root).is_err() { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::InvalidProof { + leaf, + branch: branch.to_vec(), + depth: DEPOSIT_MERKLE_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_voluntary_exit< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index 3c2240c26..e52f71026 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -55,6 +55,7 @@ pub use crate::{ phase0::{ beacon_block::{BeaconBlockHeader, SignedBeaconBlockHeader}, beacon_state::{Fork, ForkData, HistoricalBatch, HistoricalSummary}, + block_processing::DEPOSIT_MERKLE_DEPTH, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, JUSTIFICATION_BITS_LENGTH, @@ -387,109 +388,6 @@ pub fn add_validator_to_registry< state.current_epoch_participation.push(ParticipationFlags::default()); state.inactivity_scores.push(0) } -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, ->( - 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, - >, - public_key: &BlsPublicKey, - withdrawal_credentials: &Bytes32, - amount: u64, - signature: &BlsSignature, - context: &Context, -) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); - if let Some(index) = index { - increase_balance(state, index, amount); - return Ok(()); - } - let mut 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(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { - return Ok(()); - } - add_validator_to_registry( - state, - public_key.clone(), - withdrawal_credentials.clone(), - 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, ->( - 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, - >, - deposit: &mut Deposit, - context: &Context, -) -> Result<()> { - let leaf = deposit.data.hash_tree_root()?; - let branch = &deposit.proof; - let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; - 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_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -731,6 +629,114 @@ pub fn get_validator_from_deposit( ..Default::default() } } +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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, DEPOSIT_MERKLE_DEPTH, index, root).is_err() { + return Err(invalid_operation_error(InvalidOperation::Deposit( + InvalidDeposit::InvalidProof { + leaf, + branch: branch.to_vec(), + depth: DEPOSIT_MERKLE_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, diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs index b44a12b59..85f474a76 100644 --- a/ethereum-consensus/src/electra/spec/mod.rs +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -13,6 +13,7 @@ use crate::crypto::{ hash, fast_aggregate_verify, eth_aggregate_public_keys, eth_fast_aggregate_verify, }; pub use crate::deneb::blob_sidecar::VERSIONED_HASH_VERSION_KZG; +pub use crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; pub use crate::altair::constants::TIMELY_SOURCE_FLAG_INDEX; pub use crate::altair::constants::TIMELY_TARGET_FLAG_INDEX; pub use crate::altair::constants::TIMELY_HEAD_FLAG_INDEX; @@ -896,117 +897,6 @@ pub fn add_validator_to_registry< state.current_epoch_participation.push(ParticipationFlags::default()); state.inactivity_scores.push(0) } -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, ->( - 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, - >, - public_key: &BlsPublicKey, - withdrawal_credentials: &Bytes32, - amount: u64, - signature: &BlsSignature, - context: &Context, -) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); - if let Some(index) = index { - increase_balance(state, index, amount); - return Ok(()); - } - let mut 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(&mut deposit_message, domain)?; - if verify_signature(public_key, signing_root.as_ref(), signature).is_err() { - return Ok(()); - } - add_validator_to_registry( - state, - public_key.clone(), - withdrawal_credentials.clone(), - 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, ->( - 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, - >, - deposit: &mut Deposit, - context: &Context, -) -> Result<()> { - let leaf = deposit.data.hash_tree_root()?; - let branch = &deposit.proof; - let depth = crate::phase0::block_processing::DEPOSIT_MERKLE_DEPTH; - 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_sync_aggregate< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -1303,6 +1193,116 @@ pub fn get_validator_from_deposit( ..Default::default() } } +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, +>( + 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, + >, + public_key: &BlsPublicKey, + withdrawal_credentials: &Bytes32, + amount: u64, + signature: &BlsSignature, + context: &Context, +) -> Result<()> { + let index = state + .validators + .iter() + .enumerate() + .find(|(_, v)| v.public_key == *public_key) + .map(|(i, _)| i); + if let Some(index) = index { + increase_balance(state, index, amount); + return Ok(()); + } + let mut 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(&mut 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, +>( + 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, + >, + deposit: &mut Deposit, + context: &Context, +) -> Result<()> { + let leaf = deposit.data.hash_tree_root()?; + let branch = &deposit.proof; + let index = state.eth1_deposit_index as usize; + let root = state.eth1_data.deposit_root; + if is_valid_merkle_branch(leaf, branch, DEPOSIT_MERKLE_DEPTH, index, root).is_err() { + return Err( + invalid_operation_error( + InvalidOperation::Deposit(InvalidDeposit::InvalidProof { + leaf, + branch: branch.to_vec(), + depth: DEPOSIT_MERKLE_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, diff --git a/ethereum-consensus/src/phase0/block_processing.rs b/ethereum-consensus/src/phase0/block_processing.rs index c5dd1ca77..bcb62d8a9 100644 --- a/ethereum-consensus/src/phase0/block_processing.rs +++ b/ethereum-consensus/src/phase0/block_processing.rs @@ -315,7 +315,7 @@ pub fn get_validator_from_deposit( } } -pub(crate) const DEPOSIT_MERKLE_DEPTH: usize = DEPOSIT_CONTRACT_TREE_DEPTH + 1; +pub const DEPOSIT_MERKLE_DEPTH: usize = DEPOSIT_CONTRACT_TREE_DEPTH + 1; pub fn add_validator_to_registry< const SLOTS_PER_HISTORICAL_ROOT: usize, @@ -402,8 +402,8 @@ pub fn apply_deposit< add_validator_to_registry( state, - public_key.clone(), - withdrawal_credentials.clone(), + deposit_message.public_key, + deposit_message.withdrawal_credentials, amount, context, ); diff --git a/ethereum-consensus/src/phase0/spec/mod.rs b/ethereum-consensus/src/phase0/spec/mod.rs index 69a6a4f1a..f33ab7104 100644 --- a/ethereum-consensus/src/phase0/spec/mod.rs +++ b/ethereum-consensus/src/phase0/spec/mod.rs @@ -11,7 +11,7 @@ pub use crate::{ add_validator_to_registry, apply_deposit, get_validator_from_deposit, process_attestation, process_attester_slashing, process_block, process_block_header, process_deposit, process_eth1_data, process_operations, process_proposer_slashing, - process_randao, process_voluntary_exit, xor, + process_randao, process_voluntary_exit, xor, DEPOSIT_MERKLE_DEPTH, }, constants::{ BASE_REWARDS_PER_EPOCH, DEPOSIT_CONTRACT_TREE_DEPTH, DEPOSIT_DATA_LIST_BOUND, From 5c100c85648d57352ce851b50fcebd27ef221a5a Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Wed, 10 Apr 2024 11:06:34 -0600 Subject: [PATCH 3/5] type deposit amount in 'Gwei' in aux deposit functions --- ethereum-consensus/src/altair/spec/mod.rs | 2 +- ethereum-consensus/src/bellatrix/spec/mod.rs | 2 +- ethereum-consensus/src/capella/spec/mod.rs | 2 +- ethereum-consensus/src/deneb/spec/mod.rs | 2 +- ethereum-consensus/src/electra/spec/mod.rs | 2 +- ethereum-consensus/src/phase0/block_processing.rs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index 289cce777..dfb0d0767 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -231,7 +231,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index 5365885b1..ffdc7d99c 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -490,7 +490,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index b77cf3c23..a365d0459 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -497,7 +497,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index e52f71026..19100ad7f 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -655,7 +655,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs index 85f474a76..994426e67 100644 --- a/ethereum-consensus/src/electra/spec/mod.rs +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -1219,7 +1219,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { diff --git a/ethereum-consensus/src/phase0/block_processing.rs b/ethereum-consensus/src/phase0/block_processing.rs index bcb62d8a9..bb1508437 100644 --- a/ethereum-consensus/src/phase0/block_processing.rs +++ b/ethereum-consensus/src/phase0/block_processing.rs @@ -339,7 +339,7 @@ pub fn add_validator_to_registry< >, public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) { state.validators.push(get_validator_from_deposit( @@ -373,7 +373,7 @@ pub fn apply_deposit< >, public_key: &BlsPublicKey, withdrawal_credentials: &Bytes32, - amount: u64, + amount: Gwei, signature: &BlsSignature, context: &Context, ) -> Result<()> { From fcb7c736ae0a943461f619eff134d48f25c976f6 Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Wed, 10 Apr 2024 11:23:33 -0600 Subject: [PATCH 4/5] use 'position' to find validator index for deposit --- ethereum-consensus/src/altair/spec/mod.rs | 7 +------ ethereum-consensus/src/bellatrix/spec/mod.rs | 7 +------ ethereum-consensus/src/capella/spec/mod.rs | 7 +------ ethereum-consensus/src/deneb/spec/mod.rs | 7 +------ ethereum-consensus/src/electra/spec/mod.rs | 7 +------ ethereum-consensus/src/phase0/block_processing.rs | 7 +------ 6 files changed, 6 insertions(+), 36 deletions(-) diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index dfb0d0767..212fb80af 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -235,12 +235,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index ffdc7d99c..42cf79252 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -494,12 +494,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index a365d0459..ebba876af 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -501,12 +501,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index 19100ad7f..e5416d19f 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -659,12 +659,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs index 994426e67..1a607c619 100644 --- a/ethereum-consensus/src/electra/spec/mod.rs +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -1223,12 +1223,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); diff --git a/ethereum-consensus/src/phase0/block_processing.rs b/ethereum-consensus/src/phase0/block_processing.rs index bb1508437..306d55769 100644 --- a/ethereum-consensus/src/phase0/block_processing.rs +++ b/ethereum-consensus/src/phase0/block_processing.rs @@ -377,12 +377,7 @@ pub fn apply_deposit< signature: &BlsSignature, context: &Context, ) -> Result<()> { - let index = state - .validators - .iter() - .enumerate() - .find(|(_, v)| v.public_key == *public_key) - .map(|(i, _)| i); + let index = state.validators.iter().position(|v| v.public_key == *public_key); if let Some(index) = index { increase_balance(state, index, amount); return Ok(()); From 92b92dd650f077e9490e91779a490649021462dc Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Fri, 12 Apr 2024 14:18:04 -0600 Subject: [PATCH 5/5] refactor: use Gwei type alias --- ethereum-consensus/src/altair/spec/mod.rs | 2 +- ethereum-consensus/src/bellatrix/spec/mod.rs | 2 +- ethereum-consensus/src/capella/spec/mod.rs | 2 +- ethereum-consensus/src/deneb/spec/mod.rs | 2 +- ethereum-consensus/src/electra/spec/mod.rs | 2 +- ethereum-consensus/src/phase0/block_processing.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ethereum-consensus/src/altair/spec/mod.rs b/ethereum-consensus/src/altair/spec/mod.rs index 212fb80af..673166a78 100644 --- a/ethereum-consensus/src/altair/spec/mod.rs +++ b/ethereum-consensus/src/altair/spec/mod.rs @@ -191,7 +191,7 @@ pub fn process_attester_slashing< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min( diff --git a/ethereum-consensus/src/bellatrix/spec/mod.rs b/ethereum-consensus/src/bellatrix/spec/mod.rs index 42cf79252..a4eba2927 100644 --- a/ethereum-consensus/src/bellatrix/spec/mod.rs +++ b/ethereum-consensus/src/bellatrix/spec/mod.rs @@ -446,7 +446,7 @@ pub fn process_attester_slashing< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min( diff --git a/ethereum-consensus/src/capella/spec/mod.rs b/ethereum-consensus/src/capella/spec/mod.rs index ebba876af..d15ab328f 100644 --- a/ethereum-consensus/src/capella/spec/mod.rs +++ b/ethereum-consensus/src/capella/spec/mod.rs @@ -453,7 +453,7 @@ pub fn process_attester_slashing< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min( diff --git a/ethereum-consensus/src/deneb/spec/mod.rs b/ethereum-consensus/src/deneb/spec/mod.rs index e5416d19f..d96763e13 100644 --- a/ethereum-consensus/src/deneb/spec/mod.rs +++ b/ethereum-consensus/src/deneb/spec/mod.rs @@ -611,7 +611,7 @@ pub fn process_attester_slashing< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min( diff --git a/ethereum-consensus/src/electra/spec/mod.rs b/ethereum-consensus/src/electra/spec/mod.rs index 1a607c619..c0dd54ea2 100644 --- a/ethereum-consensus/src/electra/spec/mod.rs +++ b/ethereum-consensus/src/electra/spec/mod.rs @@ -1175,7 +1175,7 @@ pub fn process_attester_slashing< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min( diff --git a/ethereum-consensus/src/phase0/block_processing.rs b/ethereum-consensus/src/phase0/block_processing.rs index 306d55769..f2266720a 100644 --- a/ethereum-consensus/src/phase0/block_processing.rs +++ b/ethereum-consensus/src/phase0/block_processing.rs @@ -295,7 +295,7 @@ pub fn process_attestation< pub fn get_validator_from_deposit( public_key: BlsPublicKey, withdrawal_credentials: Bytes32, - amount: u64, + amount: Gwei, context: &Context, ) -> Validator { let effective_balance = Gwei::min(