refactor: implement BeaconEngine#9550
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the BeaconEngine class to centralize consensus validation and block production logic, separating it from the facade BeaconChain. It also refactors the fork choice into read-only (IForkChoiceRead) and full (IForkChoice) interfaces. The review feedback highlights a critical issue where simplifying the executionPayloadEnabled check bypasses the Terminal Total Difficulty (TTD) transition check, which could cause failures during the Merge transition. Additionally, the reviewer suggests optimizing performance on the API hot path by passing raw request body bytes directly to handlers to avoid expensive serialization overhead.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // TODO - beacon engine: this caused failed spec tests? | ||
| // the BeaconEngine cannot provide a BeaconState | ||
| // const executionPayloadEnabled = | ||
| // isStatePostBellatrix(preState0) && | ||
| // preState0.isExecutionStateType && | ||
| // isExecutionBlockBodyType(block.message.body) && | ||
| // preState0.isExecutionEnabled(block.message) | ||
| // ? block.message.body.executionPayload | ||
| // : null; | ||
| const executionPayloadEnabled = isExecutionBlockBodyType(block.message.body) | ||
| ? block.message.body.executionPayload | ||
| : null; |
There was a problem hiding this comment.
Commenting out the isExecutionEnabled check and simplifying executionPayloadEnabled bypasses the Terminal Total Difficulty (TTD) transition check. This will cause failures during the Merge transition period (where Bellatrix is active but TTD is not yet reached) and in historical sync/spec tests (as noted in the TODO).
To resolve this without violating the BeaconEngine boundaries, you can retrieve preState0 in verifyBlocksInEpoch (which is a cheap cache hit) and pass it (or a boolean flag indicating if execution is enabled) to verifyBlocksExecutionPayload.
| return; | ||
| } | ||
| // TODO - engine: get block bytes from upstream | ||
| const blockBytes = config.getForkTypes(slot).SignedBeaconBlock.serialize(signedBlock); |
| try { | ||
| await validateGossipProposerPreferences(chain, signed); | ||
| // TODO - beacon engine: get bytes from the api | ||
| const preferencesBytes = ssz.gloas.SignedProposerPreferences.serialize(signed); |
There was a problem hiding this comment.
Performance Report✔️ no performance regression detected Full benchmark results
|
6ed95ab to
452cc42
Compare
Motivation
Description
AI Assistance Disclosure