fix: only require parent envelope when bid references parent's payload

The previous check triggered ParentEnvelopeUnknown for any block whose
parent didn't have its envelope received, even when the block's bid
didn't actually reference that parent's payload (e.g. building on
grandparent's execution state).

This caused a permanent stall when an envelope was rejected (e.g.
WithdrawalsRootMismatch from a buggy proposer): the parent's
payload_received stayed false, and all subsequent child blocks would
trigger infinite lookup retries for the broken envelope.

Fix: only require the parent's envelope if the block's bid
parent_block_hash matches the parent's execution_payload_block_hash,
meaning this block directly depends on the parent's payload.
This commit is contained in:
Eitan Seri-Levi
2026-05-08 11:37:22 +00:00
committed by Devnet Bot
parent b53a969c30
commit 7aec7a768e

View File

@@ -983,10 +983,15 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
.gloas_enabled();
let parent_is_anchor = parent_block.parent_root.is_none();
// Check if this block's bid references a payload envelope we haven't received.
// Only trigger a lookup if the bid's parent_block_hash matches the parent block's
// committed execution_payload_block_hash (meaning this block builds directly on
// the parent's payload). If they don't match, the block is building on an older
// execution state (e.g. grandparent's) and doesn't need the parent's envelope.
if parent_is_gloas
&& !parent_is_anchor
&& Some(bid.message.parent_block_hash) == parent_block.execution_payload_block_hash
&& !fork_choice_read_lock.is_payload_received(&block.message().parent_root())
&& Some(bid.message.parent_block_hash) != parent_block.execution_payload_block_hash
{
return Err(BlockError::ParentEnvelopeUnknown {
parent_root: block.message().parent_root(),