fix: resolve PTC committee against the referenced block state#9426
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the payload attestation validation logic to use the referenced block's branch state instead of the head state. It retrieves the block from fork choice and fetches the corresponding state using chain.regen.getBlockSlotState. The feedback highlights an improvement opportunity: if the attestation's slot is strictly less than the referenced block's slot, it represents a protocol violation. Instead of letting this trigger a caught error in getBlockSlotState that results in an IGNORE action, the code should explicitly check this condition and REJECT the message to prevent spam and avoid unnecessary overhead.
| const block = chain.forkChoice.getBlockHexDefaultStatus(toRootHex(data.beaconBlockRoot)); | ||
| if (block === null) { | ||
| throw new PayloadAttestationError(GossipAction.IGNORE, { | ||
| code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT, | ||
| blockRoot: toRootHex(data.beaconBlockRoot), | ||
| }); | ||
| } |
There was a problem hiding this comment.
If the payload attestation's slot (data.slot) is strictly less than the referenced block's slot (block.slot), it represents a static protocol violation (an attestation cannot target a block from a future slot relative to itself). Currently, this case will cause getBlockSlotState to throw a SLOT_BEFORE_BLOCK_SLOT error, which is caught and mapped to UNKNOWN_BLOCK_ROOT with GossipAction.IGNORE.
To prevent peers from spamming these invalid attestations without being penalized, and to avoid the overhead of calling getBlockSlotState for an obviously invalid attestation, we should explicitly check this condition and REJECT the message.
const block = chain.forkChoice.getBlockHexDefaultStatus(toRootHex(data.beaconBlockRoot));
if (block === null) {
throw new PayloadAttestationError(GossipAction.IGNORE, {
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
blockRoot: toRootHex(data.beaconBlockRoot),
});
}
if (data.slot < block.slot) {
throw new PayloadAttestationError(GossipAction.REJECT, {
code: PayloadAttestationErrorCode.INVALID_BLOCK,
blockRoot: toRootHex(data.beaconBlockRoot),
});
}There was a problem hiding this comment.
- will be addressed by fix: ignore PTC attestations for empty assigned slots #9427
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d3549511a3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| // 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) |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
- will be addressed by fix: ignore PTC attestations for empty assigned slots #9427
Performance Report🚀🚀 Significant benchmark improvement detected
Full benchmark results
|
same as #9409