mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 01:05:47 +00:00
process_payload_attestation()
This commit is contained in:
@@ -86,8 +86,8 @@ fn update_flag_total_balances(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the `ProgressiveBalancesCache` when a new target attestation has been processed.
|
/// Updates the `ProgressiveBalancesCache` when a particiation flag is added to a validator.
|
||||||
pub fn update_progressive_balances_on_attestation<E: EthSpec>(
|
pub fn update_progressive_balances_on_flag_added<E: EthSpec>(
|
||||||
state: &mut BeaconState<E>,
|
state: &mut BeaconState<E>,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
flag_index: usize,
|
flag_index: usize,
|
||||||
@@ -95,7 +95,26 @@ pub fn update_progressive_balances_on_attestation<E: EthSpec>(
|
|||||||
validator_slashed: bool,
|
validator_slashed: bool,
|
||||||
) -> Result<(), BlockProcessingError> {
|
) -> Result<(), BlockProcessingError> {
|
||||||
if is_progressive_balances_enabled(state) {
|
if is_progressive_balances_enabled(state) {
|
||||||
state.progressive_balances_cache_mut().on_new_attestation(
|
state.progressive_balances_cache_mut().on_flag_added(
|
||||||
|
epoch,
|
||||||
|
validator_slashed,
|
||||||
|
flag_index,
|
||||||
|
validator_effective_balance,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the `ProgressiveBalancesCache` when a particiation flag is removed from a validator.
|
||||||
|
pub fn update_progressive_balances_on_flag_removed<E: EthSpec>(
|
||||||
|
state: &mut BeaconState<E>,
|
||||||
|
epoch: Epoch,
|
||||||
|
flag_index: usize,
|
||||||
|
validator_effective_balance: u64,
|
||||||
|
validator_slashed: bool,
|
||||||
|
) -> Result<(), BlockProcessingError> {
|
||||||
|
if is_progressive_balances_enabled(state) {
|
||||||
|
state.progressive_balances_cache_mut().on_flag_removed(
|
||||||
epoch,
|
epoch,
|
||||||
validator_slashed,
|
validator_slashed,
|
||||||
flag_index,
|
flag_index,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::common::update_progressive_balances_cache::{
|
||||||
|
update_progressive_balances_on_flag_added, update_progressive_balances_on_flag_removed,
|
||||||
|
};
|
||||||
use crate::common::{
|
use crate::common::{
|
||||||
get_attestation_participation_flag_indices, increase_balance, initiate_validator_exit,
|
get_attestation_participation_flag_indices, increase_balance, initiate_validator_exit,
|
||||||
slash_validator,
|
slash_validator,
|
||||||
@@ -131,7 +134,6 @@ pub mod base {
|
|||||||
|
|
||||||
pub mod altair_deneb {
|
pub mod altair_deneb {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::common::update_progressive_balances_cache::update_progressive_balances_on_attestation;
|
|
||||||
|
|
||||||
pub fn process_attestations<'a, E: EthSpec, I>(
|
pub fn process_attestations<'a, E: EthSpec, I>(
|
||||||
state: &mut BeaconState<E>,
|
state: &mut BeaconState<E>,
|
||||||
@@ -200,7 +202,7 @@ pub mod altair_deneb {
|
|||||||
proposer_reward_numerator
|
proposer_reward_numerator
|
||||||
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
|
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
|
||||||
|
|
||||||
update_progressive_balances_on_attestation(
|
update_progressive_balances_on_flag_added(
|
||||||
state,
|
state,
|
||||||
data.target.epoch,
|
data.target.epoch,
|
||||||
flag_index,
|
flag_index,
|
||||||
@@ -723,11 +725,103 @@ pub fn process_payload_attestation<E: EthSpec>(
|
|||||||
ctxt: &mut ConsensusContext<E>,
|
ctxt: &mut ConsensusContext<E>,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), BlockProcessingError> {
|
) -> Result<(), BlockProcessingError> {
|
||||||
let _indexed =
|
let current_epoch = ctxt.current_epoch;
|
||||||
|
let previous_epoch = ctxt.previous_epoch;
|
||||||
|
let target_epoch = if state.slot() % E::slots_per_epoch() == Slot::new(0) {
|
||||||
|
previous_epoch
|
||||||
|
} else {
|
||||||
|
current_epoch
|
||||||
|
};
|
||||||
|
let proposer_index = ctxt.get_proposer_index(state, spec)? as usize;
|
||||||
|
|
||||||
|
let indexed_payload_attestation =
|
||||||
verify_payload_attestation(state, payload_attestation, ctxt, verify_signatures, spec)
|
verify_payload_attestation(state, payload_attestation, ctxt, verify_signatures, spec)
|
||||||
.map_err(|e| e.into_with_index(att_index))?;
|
.map_err(|e| e.into_with_index(att_index))?;
|
||||||
|
|
||||||
// TODO((EIP-7732): finish implementing this function
|
let data = &payload_attestation.data;
|
||||||
|
let payload_was_present = data.slot == state.latest_full_slot()?;
|
||||||
|
let voted_present = data.payload_status == PayloadStatus::PayloadPresent;
|
||||||
|
let proposer_reward_denominator = WEIGHT_DENOMINATOR
|
||||||
|
.safe_sub(PROPOSER_WEIGHT)?
|
||||||
|
.safe_mul(WEIGHT_DENOMINATOR)?
|
||||||
|
.safe_div(PROPOSER_WEIGHT)?;
|
||||||
|
|
||||||
|
if voted_present != payload_was_present {
|
||||||
|
// Unset the flags in case they were set by equivocating PTC attestation
|
||||||
|
let mut proposer_penalty_numerator = 0;
|
||||||
|
|
||||||
|
for index in indexed_payload_attestation.attesting_indices_iter() {
|
||||||
|
let index = *index as usize;
|
||||||
|
|
||||||
|
let validator_effective_balance = state.epoch_cache().get_effective_balance(index)?;
|
||||||
|
let validator_slashed = state.slashings_cache().is_slashed(index);
|
||||||
|
|
||||||
|
for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {
|
||||||
|
let epoch_participation = state.get_epoch_participation_mut(
|
||||||
|
target_epoch,
|
||||||
|
previous_epoch,
|
||||||
|
current_epoch,
|
||||||
|
)?;
|
||||||
|
let validator_participation = epoch_participation
|
||||||
|
.get_mut(index)
|
||||||
|
.ok_or(BeaconStateError::ParticipationOutOfBounds(index))?;
|
||||||
|
if validator_participation.has_flag(flag_index)? {
|
||||||
|
validator_participation.remove_flag(flag_index)?;
|
||||||
|
proposer_penalty_numerator
|
||||||
|
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
|
||||||
|
|
||||||
|
update_progressive_balances_on_flag_removed(
|
||||||
|
state,
|
||||||
|
target_epoch,
|
||||||
|
flag_index,
|
||||||
|
validator_effective_balance,
|
||||||
|
validator_slashed,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// penalize the proposer
|
||||||
|
let proposer_penalty = proposer_penalty_numerator
|
||||||
|
.safe_mul(2)?
|
||||||
|
.safe_div(proposer_reward_denominator)?;
|
||||||
|
decrease_balance(state, proposer_index, proposer_penalty)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reward the proposer and set all the participation flags in case of correct attestations
|
||||||
|
let mut proposer_reward_numerator = 0;
|
||||||
|
for index in indexed_payload_attestation.attesting_indices_iter() {
|
||||||
|
let index = *index as usize;
|
||||||
|
|
||||||
|
let validator_effective_balance = state.epoch_cache().get_effective_balance(index)?;
|
||||||
|
let validator_slashed = state.slashings_cache().is_slashed(index);
|
||||||
|
|
||||||
|
for (flag_index, &weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {
|
||||||
|
let epoch_participation =
|
||||||
|
state.get_epoch_participation_mut(target_epoch, previous_epoch, current_epoch)?;
|
||||||
|
let validator_participation = epoch_participation
|
||||||
|
.get_mut(index)
|
||||||
|
.ok_or(BeaconStateError::ParticipationOutOfBounds(index))?;
|
||||||
|
if !validator_participation.has_flag(flag_index)? {
|
||||||
|
validator_participation.add_flag(flag_index)?;
|
||||||
|
proposer_reward_numerator
|
||||||
|
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
|
||||||
|
|
||||||
|
update_progressive_balances_on_flag_added(
|
||||||
|
state,
|
||||||
|
target_epoch,
|
||||||
|
flag_index,
|
||||||
|
validator_effective_balance,
|
||||||
|
validator_slashed,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reward the proposer
|
||||||
|
let proposer_reward = proposer_reward_numerator.safe_div(proposer_reward_denominator)?;
|
||||||
|
increase_balance(state, proposer_index, proposer_reward)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -743,9 +837,12 @@ where
|
|||||||
I: Iterator<Item = &'a PayloadAttestation<E>>,
|
I: Iterator<Item = &'a PayloadAttestation<E>>,
|
||||||
{
|
{
|
||||||
// Ensure required caches are all built. These should be no-ops during regular operation.
|
// Ensure required caches are all built. These should be no-ops during regular operation.
|
||||||
// TODO(EIP-7732): check necessary caches
|
// TODO(EIP-7732): verify necessary caches
|
||||||
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
||||||
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
||||||
|
initialize_epoch_cache(state, spec)?;
|
||||||
|
initialize_progressive_balances_cache(state, spec)?;
|
||||||
|
state.build_slashings_cache()?;
|
||||||
|
|
||||||
payload_attestations
|
payload_attestations
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub fn verify_payload_attestation<'ctxt, E: EthSpec>(
|
|||||||
|
|
||||||
let indexed_payload_attestation =
|
let indexed_payload_attestation =
|
||||||
ctxt.get_indexed_payload_attestation(state, data.slot, &payload_attestation)?;
|
ctxt.get_indexed_payload_attestation(state, data.slot, &payload_attestation)?;
|
||||||
|
|
||||||
is_valid_indexed_payload_attestation(
|
is_valid_indexed_payload_attestation(
|
||||||
state,
|
state,
|
||||||
&indexed_payload_attestation,
|
&indexed_payload_attestation,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ impl EpochTotalBalances {
|
|||||||
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))
|
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_new_attestation(
|
pub fn on_flag_added(
|
||||||
&mut self,
|
&mut self,
|
||||||
is_slashed: bool,
|
is_slashed: bool,
|
||||||
flag_index: usize,
|
flag_index: usize,
|
||||||
@@ -77,6 +77,23 @@ impl EpochTotalBalances {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_flag_removed(
|
||||||
|
&mut self,
|
||||||
|
is_slashed: bool,
|
||||||
|
flag_index: usize,
|
||||||
|
validator_effective_balance: u64,
|
||||||
|
) -> Result<(), BeaconStateError> {
|
||||||
|
if is_slashed {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let balance = self
|
||||||
|
.total_flag_balances
|
||||||
|
.get_mut(flag_index)
|
||||||
|
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))?;
|
||||||
|
balance.safe_sub_assign(validator_effective_balance)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_slashing(
|
pub fn on_slashing(
|
||||||
&mut self,
|
&mut self,
|
||||||
participation_flags: ParticipationFlags,
|
participation_flags: ParticipationFlags,
|
||||||
@@ -148,10 +165,12 @@ impl ProgressiveBalancesCache {
|
|||||||
.map_or(false, |inner| inner.current_epoch == epoch)
|
.map_or(false, |inner| inner.current_epoch == epoch)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When a new target attestation has been processed, we update the cached
|
/// Updates the `ProgressiveBalancesCache` when a participation flag is added for a validator.
|
||||||
/// `current_epoch_target_attesting_balance` to include the validator effective balance.
|
///
|
||||||
|
/// This function increments the total balance associated with the specified `flag_index`
|
||||||
|
/// by the validator's `effective_balance`, provided the validator is not slashed.
|
||||||
/// If the epoch is neither the current epoch nor the previous epoch, an error is returned.
|
/// If the epoch is neither the current epoch nor the previous epoch, an error is returned.
|
||||||
pub fn on_new_attestation(
|
pub fn on_flag_added(
|
||||||
&mut self,
|
&mut self,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
is_slashed: bool,
|
is_slashed: bool,
|
||||||
@@ -161,13 +180,46 @@ impl ProgressiveBalancesCache {
|
|||||||
let cache = self.get_inner_mut()?;
|
let cache = self.get_inner_mut()?;
|
||||||
|
|
||||||
if epoch == cache.current_epoch {
|
if epoch == cache.current_epoch {
|
||||||
cache.current_epoch_cache.on_new_attestation(
|
cache.current_epoch_cache.on_flag_added(
|
||||||
is_slashed,
|
is_slashed,
|
||||||
flag_index,
|
flag_index,
|
||||||
validator_effective_balance,
|
validator_effective_balance,
|
||||||
)?;
|
)?;
|
||||||
} else if epoch.safe_add(1)? == cache.current_epoch {
|
} else if epoch.safe_add(1)? == cache.current_epoch {
|
||||||
cache.previous_epoch_cache.on_new_attestation(
|
cache.previous_epoch_cache.on_flag_added(
|
||||||
|
is_slashed,
|
||||||
|
flag_index,
|
||||||
|
validator_effective_balance,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
return Err(BeaconStateError::ProgressiveBalancesCacheInconsistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the `ProgressiveBalancesCache` when a participation flag is removed for a validator.
|
||||||
|
///
|
||||||
|
/// This function decrements the total balance associated with the specified `flag_index`
|
||||||
|
/// by the validator's `effective_balance`, provided the validator is not slashed.
|
||||||
|
/// If the epoch is neither the current epoch nor the previous epoch, an error is returned.
|
||||||
|
pub fn on_flag_removed(
|
||||||
|
&mut self,
|
||||||
|
epoch: Epoch,
|
||||||
|
is_slashed: bool,
|
||||||
|
flag_index: usize,
|
||||||
|
validator_effective_balance: u64,
|
||||||
|
) -> Result<(), BeaconStateError> {
|
||||||
|
let cache = self.get_inner_mut()?;
|
||||||
|
|
||||||
|
if epoch == cache.current_epoch {
|
||||||
|
cache.current_epoch_cache.on_flag_removed(
|
||||||
|
is_slashed,
|
||||||
|
flag_index,
|
||||||
|
validator_effective_balance,
|
||||||
|
)?;
|
||||||
|
} else if epoch.safe_add(1)? == cache.current_epoch {
|
||||||
|
cache.previous_epoch_cache.on_flag_removed(
|
||||||
is_slashed,
|
is_slashed,
|
||||||
flag_index,
|
flag_index,
|
||||||
validator_effective_balance,
|
validator_effective_balance,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
use core::slice::Iter;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
@@ -26,6 +27,12 @@ pub struct IndexedPayloadAttestation<E: EthSpec> {
|
|||||||
pub signature: AggregateSignature,
|
pub signature: AggregateSignature,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> IndexedPayloadAttestation<E> {
|
||||||
|
pub fn attesting_indices_iter(&self) -> Iter<'_, u64> {
|
||||||
|
self.attesting_indices.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ impl ParticipationFlags {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_flag(&mut self, flag_index: usize) -> Result<(), ArithError> {
|
||||||
|
if flag_index >= NUM_FLAG_INDICES {
|
||||||
|
return Err(ArithError::Overflow);
|
||||||
|
}
|
||||||
|
let mask = 1u8.safe_shl(flag_index as u32)?;
|
||||||
|
self.bits &= !mask;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, flag_index: usize) -> Result<bool, ArithError> {
|
pub fn has_flag(&self, flag_index: usize) -> Result<bool, ArithError> {
|
||||||
if flag_index >= NUM_FLAG_INDICES {
|
if flag_index >= NUM_FLAG_INDICES {
|
||||||
return Err(ArithError::Overflow);
|
return Err(ArithError::Overflow);
|
||||||
|
|||||||
Reference in New Issue
Block a user