feat: report parent_block_hash for safe/finalized post-Gloas - #9393
Conversation
Implements consensus-specs PR-5197. Post-Gloas, engine_forkchoiceUpdated must report the bid's parent_block_hash as both safeBlockHash and finalizedBlockHash rather than the block's own execution payload hash: under ePBS the safe/finalized block's own payload may not yet be confirmed canonical, but its parent EL block has been. Adds getFinalizedExecutionBlockHash to mirror getSafeExecutionBlockHash and switches all five FCU callsites to the new fork-aware helpers.
There was a problem hiding this comment.
Code Review
This pull request introduces logic to correctly handle execution block hashes for the engine_forkchoiceUpdated call in preparation for the Gloas fork. It adds a new utility function getFinalizedExecutionBlockHash and refactors getSafeExecutionBlockHash to return the parent_block_hash for Gloas blocks, ensuring compliance with the updated consensus specifications. These utilities are integrated across the beacon node's block import and production flows, and new unit tests have been added to verify the logic for both pre-Gloas and post-Gloas scenarios. I have no feedback to provide.
Performance Report✔️ no performance regression detected Full benchmark results
|
|
@wemeetagain please address review comments and resolve conflicts |
|
@nazarhussain maybe you can take this over? we need this so fcr works correctly on gloas |
…parent-hash # Conflicts: # packages/beacon-node/src/chain/prepareNextSlot.ts # packages/fork-choice/src/forkChoice/safeBlocks.ts
Genesis block body carries a default payload, so it is not an execution block per spec (is_execution_block); proto array's anchor hash comes from the state header and must not be reported as safe/finalized. Gloas genesis still reports the bid parent_block_hash (consensus-specs PR-5449 convention). - pin spec doc links to v1.7.0-alpha.13, fix broken anchors - mock getConfirmedBlock in prepareNextSlot test (FCU path threw, getFinalizedBlock never called) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Nico Flaig <nflaig@protonmail.com>
Gloas alpha.13 state transition and the gloas-modified get_safe_execution_block_hash landed on unstable (#9393), so the suite passes fully, safe_execution_block_hash assertions included. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| return confirmedBlock.executionPayloadBlockHash; | ||
| } | ||
| export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.warn>): RootHex { | ||
| const confirmedBlock = forkChoice.getConfirmedBlock(); |
There was a problem hiding this comment.
need to log when confirmed block is the finalized block
| * | ||
| * @deprecated The merged fast-confirmation spec only defines `get_safe_execution_block_hash`. | ||
| */ | ||
| export function getSafeBeaconBlockRoot(fc: IForkChoice): Root { |
There was a problem hiding this comment.
this function is not in use anymore
| export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.warn>): RootHex { | ||
| const confirmedBlock = forkChoice.getConfirmedBlock(); | ||
| if (confirmedBlock === null) { | ||
| logger?.warn("Confirmed block not found, using zero safe execution block hash", { |
There was a problem hiding this comment.
I think we should throw error instead
this should not happen on any cases, even when FCR is enabled is disabled
otherwise, we'll have other issues in downstream flows, and the CL <-> EL investigate always take time
There was a problem hiding this comment.
agree with this, had same thought when reviewing this pr, did another quick audit of code and getConfirmedBlock() returns this.fcStore.justified.checkpoint.rootHex so that should always be there, also addressed in #9794
| if (block.executionPayloadBlockHash === null) { | ||
| logger?.warn("Execution payload block hash not found, using zero hash", { | ||
| blockRoot: block.blockRoot, | ||
| slot: block.slot, |
There was a problem hiding this comment.
same to above, I think we should throw error instead
the only case executionPayloadBlockHash could be null is when pre-bellatrix
**Motivation** Update spec tests to v1.7.0-alpha.13 FCR fixes proposed from #9690 ([consensus-specs#5489](ethereum/consensus-specs#5489), [consensus-specs#5490](ethereum/consensus-specs#5490)) and complete the missing FCR assertions. **Description** - Unskip `is_one_confirmed_fails_large_validator_slashed`, fixed upstream by [consensus-specs#5490](ethereum/consensus-specs#5490) - Enable the gloas `fast_confirmation` suite — gloas alpha.13 state transition and `get_safe_execution_block_hash` landed via #9393 - Assert `safe_execution_block_hash` ([consensus-specs#5449](ethereum/consensus-specs#5449)) and the `FastConfirmationStore` variables, exposed via `IForkChoice.getFastConfirmationStore()` (debug API endpoint in a follow-up PR) - Skip vectors blocked on upstream vector artifacts, documented inline; the schedule-related ones are already fixed upstream ([consensus-specs#5498](ethereum/consensus-specs#5498), [consensus-specs#5499](ethereum/consensus-specs#5499)) and unskip on the next spec-tests release `fast_confirmation` (minimal): 1416 passed / 20 skipped / 0 failed. Full spec suites green: minimal 70,899 passed, mainnet 13,586 passed, 0 failures. Refs #9690 **AI Assistance Disclosure** - [x] I have read the [contributor guidelines](https://github.com/ChainSafe/lodestar/blob/unstable/CONTRIBUTING.md#ai-assistance-notice) and disclosed my usage of AI below. Implemented and verified with AI assistance (Claude Code); all changes reviewed and tests executed locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
🎉 This PR is included in v1.46.0 🎉 |
Motivation
Post-Gloas (ePBS) a block's own payload may not yet be confirmed canonical, so
engine_forkchoiceUpdatedmust report the bid'sparent_block_hashas the safe/finalized block hash.Description
getFinalizedExecutionBlockHashand a shared fork-aware helper; switch all five FCU callsitesparent_block_hash; pre-Gloas behavior unchangedIForkChoice.getConfirmedBlock()(justified fallback when FCR is disabled), with warnings on zero-hash fallbacksZERO_HASHpre-Gloas (genesis body carries a default payload, so it is not an execution block); bidparent_block_hashfor Gloas genesisReferences:
notify_forkchoice_updatedethereum/consensus-specs#5197safe_execution_block_hashproperty to FCR tests ethereum/consensus-specs#5449AI Assistance Disclosure