process_payload_attestation()

This commit is contained in:
Mark Mackey
2024-09-24 12:41:05 -05:00
parent 56e2ed5d75
commit 559ea055c2
6 changed files with 199 additions and 14 deletions

View File

@@ -86,8 +86,8 @@ fn update_flag_total_balances(
Ok(())
}
/// Updates the `ProgressiveBalancesCache` when a new target attestation has been processed.
pub fn update_progressive_balances_on_attestation<E: EthSpec>(
/// Updates the `ProgressiveBalancesCache` when a particiation flag is added to a validator.
pub fn update_progressive_balances_on_flag_added<E: EthSpec>(
state: &mut BeaconState<E>,
epoch: Epoch,
flag_index: usize,
@@ -95,7 +95,26 @@ pub fn update_progressive_balances_on_attestation<E: EthSpec>(
validator_slashed: bool,
) -> Result<(), BlockProcessingError> {
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,
validator_slashed,
flag_index,

View File

@@ -1,4 +1,7 @@
use super::*;
use crate::common::update_progressive_balances_cache::{
update_progressive_balances_on_flag_added, update_progressive_balances_on_flag_removed,
};
use crate::common::{
get_attestation_participation_flag_indices, increase_balance, initiate_validator_exit,
slash_validator,
@@ -131,7 +134,6 @@ pub mod base {
pub mod altair_deneb {
use super::*;
use crate::common::update_progressive_balances_cache::update_progressive_balances_on_attestation;
pub fn process_attestations<'a, E: EthSpec, I>(
state: &mut BeaconState<E>,
@@ -200,7 +202,7 @@ pub mod altair_deneb {
proposer_reward_numerator
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
update_progressive_balances_on_attestation(
update_progressive_balances_on_flag_added(
state,
data.target.epoch,
flag_index,
@@ -723,11 +725,103 @@ pub fn process_payload_attestation<E: EthSpec>(
ctxt: &mut ConsensusContext<E>,
spec: &ChainSpec,
) -> 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)
.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(())
}
@@ -743,9 +837,12 @@ where
I: Iterator<Item = &'a PayloadAttestation<E>>,
{
// 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::Previous, spec)?;
initialize_epoch_cache(state, spec)?;
initialize_progressive_balances_cache(state, spec)?;
state.build_slashings_cache()?;
payload_attestations
.enumerate()

View File

@@ -31,6 +31,7 @@ pub fn verify_payload_attestation<'ctxt, E: EthSpec>(
let indexed_payload_attestation =
ctxt.get_indexed_payload_attestation(state, data.slot, &payload_attestation)?;
is_valid_indexed_payload_attestation(
state,
&indexed_payload_attestation,

View File

@@ -60,7 +60,7 @@ impl EpochTotalBalances {
.ok_or(BeaconStateError::InvalidFlagIndex(flag_index))
}
pub fn on_new_attestation(
pub fn on_flag_added(
&mut self,
is_slashed: bool,
flag_index: usize,
@@ -77,6 +77,23 @@ impl EpochTotalBalances {
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(
&mut self,
participation_flags: ParticipationFlags,
@@ -148,10 +165,12 @@ impl ProgressiveBalancesCache {
.map_or(false, |inner| inner.current_epoch == epoch)
}
/// When a new target attestation has been processed, we update the cached
/// `current_epoch_target_attesting_balance` to include the validator effective balance.
/// Updates the `ProgressiveBalancesCache` when a participation flag is added for a validator.
///
/// 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.
pub fn on_new_attestation(
pub fn on_flag_added(
&mut self,
epoch: Epoch,
is_slashed: bool,
@@ -161,13 +180,46 @@ impl ProgressiveBalancesCache {
let cache = self.get_inner_mut()?;
if epoch == cache.current_epoch {
cache.current_epoch_cache.on_new_attestation(
cache.current_epoch_cache.on_flag_added(
is_slashed,
flag_index,
validator_effective_balance,
)?;
} 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,
flag_index,
validator_effective_balance,

View File

@@ -1,5 +1,6 @@
use crate::test_utils::TestRandom;
use crate::*;
use core::slice::Iter;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
@@ -26,6 +27,12 @@ pub struct IndexedPayloadAttestation<E: EthSpec> {
pub signature: AggregateSignature,
}
impl<E: EthSpec> IndexedPayloadAttestation<E> {
pub fn attesting_indices_iter(&self) -> Iter<'_, u64> {
self.attesting_indices.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -22,6 +22,15 @@ impl ParticipationFlags {
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> {
if flag_index >= NUM_FLAG_INDICES {
return Err(ArithError::Overflow);