From 7aec7a768ecdbc32fb4dc720d38107d6d770b71e Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Fri, 8 May 2026 11:37:22 +0000 Subject: [PATCH] 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. --- beacon_node/beacon_chain/src/block_verification.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index c8737e8c8c..da9e7de855 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -983,10 +983,15 @@ impl GossipVerifiedBlock { .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(),