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
1 change: 1 addition & 0 deletions packages/beacon-node/src/chain/regen/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export enum RegenCaller {
validateGossipAttestation = "validateGossipAttestation",
validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
validateGossipPayloadAttestationMessage = "validateGossipPayloadAttestationMessage",
validateGossipProposerPreferences = "validateGossipProposerPreferences",
onForkChoiceFinalized = "onForkChoiceFinalized",
restApi = "restApi",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {RootHex, gloas, ssz} from "@lodestar/types";
import {toRootHex} from "@lodestar/utils";
import {GossipAction, PayloadAttestationError, PayloadAttestationErrorCode} from "../errors/index.js";
import {IBeaconChain} from "../index.js";
import {RegenCaller} from "../regen/index.js";

export type PayloadAttestationValidationResult = {
attDataRootHex: RootHex;
Expand Down Expand Up @@ -61,22 +62,32 @@ async function validatePayloadAttestationMessage(
// [IGNORE] The message's block `data.beacon_block_root` has been seen (via
// gossip or non-gossip sources) (a client MAY queue attestation for processing
// once the block is retrieved. Note a client might want to request payload after).
if (!chain.forkChoice.hasBlock(data.beaconBlockRoot)) {
const block = chain.forkChoice.getBlockDefaultStatus(data.beaconBlockRoot);
if (!block) {
throw new PayloadAttestationError(GossipAction.IGNORE, {
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
blockRoot: toRootHex(data.beaconBlockRoot),
});
}

const state = chain.getHeadState();
if (!isStatePostGloas(state)) {
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
}

// [REJECT] The message's block `data.beacon_block_root` passes validation.
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
// it is possible that the block didn't pass the validation

// Use the referenced block's branch state for the PTC committee check
const state = await chain.regen
.getBlockSlotState(block, data.slot, {dontTransferCache: true}, RegenCaller.validateGossipPayloadAttestationMessage)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject PTC messages whose slot differs from the block

When data.beaconBlockRoot points to any known Gloas block from an earlier slot, this regenerates that block's state forward to the current data.slot, so the PTC lookup can succeed and the gossip handler will call notifyPtcMessages for the old block root. The Gloas on_payload_attestation_message flow uses the stored state for data.beacon_block_root and returns without updating votes when data.slot != state.slot (specrefs/functions.yml), so advancing here accepts and applies votes that should be ignored; use the block's actual post-state/slot or explicitly reject/ignore slot mismatches before checking the PTC.

Useful? React with 👍 / 👎.

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.

.catch(() => {
throw new PayloadAttestationError(GossipAction.IGNORE, {
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
blockRoot: toRootHex(data.beaconBlockRoot),
});
});

if (!isStatePostGloas(state)) {
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
}

// [REJECT] The message's validator index is within the payload committee in
// `get_ptc(state, data.slot)`. The `state` is the head state corresponding to
// processing the block up to the current slot as determined by the fork choice.
Expand Down
Loading