fix(focil): FOCIL interop fixes for Besu/Lodestar devnet#35
Merged
Conversation
added 5 commits
May 6, 2026 13:16
- Force engine_newPayloadV6 for Heze blocks (Besu supports V6 but capability detection was falling through to broken V5 path) - Pass parentHash to engine_getInclusionListV1 (was sending empty params, Besu/Lodestar expect the parent block hash)
Besu does not implement this method. Lodestar handles IL satisfaction checking via the il_transactions param in newPayloadV6 instead of a separate engine call. Skip the call and assume satisfied for now.
In ePBS/Gloas, the execution payload is delivered via envelope, not embedded in the beacon block. produce_inclusion_list was trying to extract parent_hash from the beacon block's execution payload (which doesn't exist), causing every IL fetch to fail. Use cached_head.head_hash() which correctly tracks the execution block hash through fork choice, including envelope imports.
Add a payload envelope monitor that subscribes to the ExecutionPayloadAvailable SSE event (following the existing beacon_head_monitor pattern). The inclusion list service now races the IL deadline (66.67% into slot) against the payload envelope event, matching Lodestar's Promise.race approach. This ensures IL production fires as soon as the envelope is imported (when the EL has fresh state) rather than at a fixed offset that may be too early or too late.
56702a5 to
2388acc
Compare
When engine_newPayloadV6 fails with a transient error (e.g. Besu's ConcurrentModificationException), queue the envelope for retry instead of permanently rejecting it. Matches Lodestar's behavior of retrying on the next BlockImported event. - Add RetryEnvelope variant to ReprocessQueueMessage - On BlockImported, immediately dispatch any pending retry envelopes - Fallback timeout of 1 slot in case no block arrives - Max 3 retries per envelope to prevent infinite loops - Only retry non-penalizing EL errors (transient failures)
During fork transitions, the head state may not yet reflect the new fork version. Use spec.fork_at_epoch() instead of state.fork().
Remove non-spec attestation deadline check that was incorrectly rejecting ILs arriving in the first 1/3 of the slot. Per the heze p2p-interface spec, ILs are valid when message.slot == current_slot (with MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance). Also accept current_slot + 1 for clock disparity tolerance.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes multiple interop issues discovered while running a FOCIL devnet with Lighthouse + Besu + Lodestar.
Engine API fixes
BN inclusion list production fix
VC timing fix
Results
Before: Lighthouse couldn't produce any blocks post-Heze (100% miss rate)
After: Devnet stable, finalizing, ILs being produced, ~18% miss rate comparable to Lodestar on same hardware
Note
First commit includes pre-existing uncommitted WIP (early envelope reprocessing, is_heze_fork plumbing) that was on the focil branch working tree.