Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions beacon_node/beacon_chain/src/beacon_block_reward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
BeaconChainError::BlockRewardAttestationError
})?
} else {
self.compute_beacon_block_attestation_reward_altair_deneb(block, state)
self.compute_beacon_block_attestation_reward_altair_and_later(block, state)
.map_err(|e| {
error!(
error = ?e,
Expand Down Expand Up @@ -249,7 +249,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Ok(block_reward)
}

fn compute_beacon_block_attestation_reward_altair_deneb<
fn compute_beacon_block_attestation_reward_altair_and_later<

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting here that this is a nice rename of the function

Payload: AbstractExecPayload<T::EthSpec>,
>(
&self,
Expand All @@ -267,13 +267,20 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut previous_epoch_participation =
state.previous_epoch_participation()?.to_owned_list();

let parent_slot = state

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex tells me that for gloas, we need to run process_parent_execution_payload first before this is run because it modifies state.execution_payload_availability which is used below in get_attestation_participation_flag_indices

@eserilev eserilev Aug 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i think we probably should have made a change here when we deferred payload processing to the next slot (ethereum/consensus-specs#5094) in alpha spec 5?

Anyways good catch, i opened a separate PR with these changes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks!

.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);

for attestation in block.body().attestations() {
let data = attestation.data();
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();

// [Modified in Deneb:EIP7045]
let participation_flag_indices = get_attestation_participation_flag_indices(
state,
data,
parent_slot,
inclusion_delay,
&self.spec,
)?;
Expand Down
6 changes: 6 additions & 0 deletions beacon_node/beacon_chain/src/validator_monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,10 +728,16 @@ impl<E: EthSpec> ValidatorMonitor<E> {

let data = unaggregated_attestation.data();

let parent_slot = state

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially same issue here? we might end up reporting the wrong thing here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah similar thing here, fix is in this PR #9828

.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);

// Get the reward indices for the unaggregated attestation or log an error
match get_attestation_participation_flag_indices(
state,
unaggregated_attestation.data(),
parent_slot,
inclusion_delay,
spec,
) {
Expand Down
16 changes: 13 additions & 3 deletions beacon_node/operation_pool/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,19 @@ impl<'a, E: EthSpec> AttMaxCover<'a, E> {
let att_data = att.attestation_data();

let inclusion_delay = state.slot().as_u64().checked_sub(att_data.slot.as_u64())?;
let att_participation_flags =
get_attestation_participation_flag_indices(state, &att_data, inclusion_delay, spec)
.ok()?;
let parent_slot = state
Comment thread
pawanjay176 marked this conversation as resolved.
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);

let att_participation_flags = get_attestation_participation_flag_indices(
state,
&att_data,
parent_slot,
inclusion_delay,
spec,
)
.ok()?;

let fresh_validators_rewards = att
.indexed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use integer_sqrt::IntegerSquareRoot;
use safe_arith::SafeArith;
use smallvec::SmallVec;
use types::{
AttestationData, BeaconState, BeaconStateError as Error, ChainSpec, EthSpec,
AttestationData, BeaconState, BeaconStateError as Error, ChainSpec, EthSpec, Slot,
consts::altair::{
NUM_FLAG_INDICES, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX,
TIMELY_TARGET_FLAG_INDEX,
Expand All @@ -21,6 +21,7 @@ use types::{
pub fn get_attestation_participation_flag_indices<E: EthSpec>(
state: &BeaconState<E>,
data: &AttestationData,
parent_slot: Option<Slot>,
inclusion_delay: u64,
spec: &ChainSpec,
) -> Result<SmallVec<[usize; NUM_FLAG_INDICES]>, Error> {
Expand All @@ -37,6 +38,8 @@ pub fn get_attestation_participation_flag_indices<E: EthSpec>(

// [New in Gloas:EIP7732]
let payload_matches = if state.fork_name_unchecked().gloas_enabled() {
let parent_slot = parent_slot.ok_or(Error::MissingParentSlot)?;

if state.is_attestation_same_slot(data)? {
// For same-slot attestations, data.index must be 0
if data.index != 0 {
Expand All @@ -45,8 +48,7 @@ pub fn get_attestation_participation_flag_indices<E: EthSpec>(
true
} else {
// For non same-slot attestations, check execution payload availability
let slot_index = data
.slot
let slot_index = parent_slot
.as_usize()
.safe_rem(E::slots_per_historical_root())?;
let payload_index = state
Expand Down
11 changes: 10 additions & 1 deletion consensus/state_processing/src/per_block_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ pub fn per_block_processing<E: EthSpec, Payload: AbstractExecPayload<E>>(
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
state.build_committee_cache(RelativeEpoch::Current, spec)?;

let mut parent_slot = None;
// The call to the `process_execution_payload` must happen before the call to the
// `process_randao` as the former depends on the `randao_mix` computed with the reveal of the
// previous block.
Expand All @@ -193,6 +194,7 @@ pub fn per_block_processing<E: EthSpec, Payload: AbstractExecPayload<E>>(
if state.fork_name_unchecked().gloas_enabled() {
withdrawals::gloas::process_withdrawals::<E>(state, spec)?;
let signed_bid = block.body().signed_execution_payload_bid()?;
parent_slot = Some(state.latest_execution_payload_bid()?.slot);
process_execution_payload_bid(state, signed_bid, verify_signatures, spec)?;
} else {
if state.fork_name_unchecked().capella_enabled() {
Expand All @@ -208,7 +210,14 @@ pub fn per_block_processing<E: EthSpec, Payload: AbstractExecPayload<E>>(

process_randao(state, block, verify_randao, ctxt, spec)?;
process_eth1_data(state, block.body().eth1_data())?;
process_operations(state, block.body(), verify_signatures, ctxt, spec)?;
process_operations(
state,
block.body(),
verify_signatures,
parent_slot,
ctxt,
spec,
)?;

if let Ok(sync_aggregate) = block.body().sync_aggregate() {
process_sync_aggregate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn process_operations<E: EthSpec, Payload: AbstractExecPayload<E>>(
state: &mut BeaconState<E>,
block_body: BeaconBlockBodyRef<E, Payload>,
verify_signatures: VerifySignatures,
parent_slot: Option<Slot>,
ctxt: &mut ConsensusContext<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
Expand All @@ -40,7 +41,14 @@ pub fn process_operations<E: EthSpec, Payload: AbstractExecPayload<E>>(
ctxt,
spec,
)?;
process_attestations(state, block_body, verify_signatures, ctxt, spec)?;
process_attestations(
state,
block_body,
verify_signatures,
parent_slot,
ctxt,
spec,
)?;
process_deposits(state, &block_body.deposits().to_cow_slice(), spec)?;
process_exits(
state,
Expand Down Expand Up @@ -247,7 +255,7 @@ pub mod altair_deneb {
let data = attestation.data();
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();
let participation_flag_indices =
get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?;
get_attestation_participation_flag_indices(state, data, None, inclusion_delay, spec)?;

// Update epoch participation flags.
let mut proposer_reward_numerator = 0;
Expand Down Expand Up @@ -304,23 +312,33 @@ pub mod gloas {
state: &mut BeaconState<E>,
attestations: I,
verify_signatures: VerifySignatures,
parent_slot: Option<Slot>,
ctxt: &mut ConsensusContext<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError>
where
I: Iterator<Item = AttestationRef<'a, E>>,
{
attestations.enumerate().try_for_each(|(i, attestation)| {
process_attestation(state, attestation, i, ctxt, verify_signatures, spec)
process_attestation(
state,
attestation,
i,
verify_signatures,
parent_slot,
ctxt,
spec,
)
})
}

pub fn process_attestation<E: EthSpec>(
state: &mut BeaconState<E>,
attestation: AttestationRef<E>,
att_index: usize,
ctxt: &mut ConsensusContext<E>,
verify_signatures: VerifySignatures,
parent_slot: Option<Slot>,
ctxt: &mut ConsensusContext<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
let proposer_index = ctxt.get_proposer_index(state, spec)?;
Expand All @@ -339,8 +357,13 @@ pub mod gloas {
// Matching roots, participation flag indices
let data = attestation.data();
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();
let participation_flag_indices =
get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?;
let participation_flag_indices = get_attestation_participation_flag_indices(
state,
data,
parent_slot,
inclusion_delay,
spec,
)?;

// [New in EIP-7732]
let current_epoch_target = data.target.epoch == state.current_epoch();
Expand Down Expand Up @@ -540,6 +563,7 @@ pub fn process_attestations<E: EthSpec, Payload: AbstractExecPayload<E>>(
state: &mut BeaconState<E>,
block_body: BeaconBlockBodyRef<E, Payload>,
verify_signatures: VerifySignatures,
parent_slot: Option<Slot>,
ctxt: &mut ConsensusContext<E>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
Expand All @@ -548,6 +572,7 @@ pub fn process_attestations<E: EthSpec, Payload: AbstractExecPayload<E>>(
state,
block_body.attestations(),
verify_signatures,
parent_slot,
ctxt,
spec,
)?;
Expand Down
30 changes: 30 additions & 0 deletions consensus/state_processing/src/per_block_processing/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,15 @@ async fn invalid_attestation_no_committee_for_index() {
.into_data_mut()
.index += 1;
let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down Expand Up @@ -491,10 +496,15 @@ async fn invalid_attestation_wrong_justified_checkpoint() {
.source = new_justified_checkpoint;

let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down Expand Up @@ -545,10 +555,15 @@ async fn invalid_attestation_bad_aggregation_bitfield_len() {
}

let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down Expand Up @@ -585,10 +600,15 @@ async fn invalid_attestation_bad_signature() {
.into_signature_mut() = AggregateSignature::empty();

let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down Expand Up @@ -629,10 +649,15 @@ async fn invalid_attestation_included_too_early() {
.slot = new_attesation_slot;

let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down Expand Up @@ -680,10 +705,15 @@ async fn invalid_attestation_target_epoch_slot_mismatch() {
.epoch += Epoch::new(1);

let mut ctxt = ConsensusContext::new(state.slot());
let parent_slot = state
.latest_execution_payload_bid()
.ok()
.map(|bid| bid.slot);
let result = process_operations::process_attestations(
&mut state,
head_block.body(),
VerifySignatures::True,
parent_slot,
&mut ctxt,
&spec,
);
Expand Down
2 changes: 1 addition & 1 deletion consensus/state_processing/src/upgrade/altair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn translate_participation<E: EthSpec>(

// Translate attestation inclusion info to flag indices.
let participation_flag_indices =
get_attestation_participation_flag_indices(state, data, inclusion_delay, spec)?;
get_attestation_participation_flag_indices(state, data, None, inclusion_delay, spec)?;

// Apply flags to all attesting validators.
let committee = state.get_beacon_committee(data.slot, data.index)?;
Expand Down
1 change: 1 addition & 0 deletions consensus/types/src/state/beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ pub enum BeaconStateError {
InvalidIndicesCount,
InvalidBuilderPendingPaymentsIndex(usize),
InvalidExecutionPayloadAvailabilityIndex(usize),
MissingParentSlot,
/// Merkle proofs against the `BeaconState` and `BeaconBlockBody` use progressive-container
/// generalized indices from Gloas (EIP-7688) onwards, which are not implemented yet.
ProgressiveMerkleProofNotSupported,
Expand Down
4 changes: 3 additions & 1 deletion testing/ef_tests/src/cases/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,14 @@ impl<E: EthSpec> Operation<E> for Attestation<E> {
initialize_progressive_balances_cache(state, spec)?;
let mut ctxt = ConsensusContext::new(state.slot());
if state.fork_name_unchecked().gloas_enabled() {
let parent_slot = Some(state.latest_execution_payload_bid()?.slot);
gloas::process_attestation(
state,
self.to_ref(),
0,
&mut ctxt,
VerifySignatures::True,
parent_slot,
&mut ctxt,
spec,
)
} else if state.fork_name_unchecked().altair_enabled() {
Expand Down
Loading