Skip to content

feat: gloas range sync (rebased onto epbs-devnet-0) - #9000

Closed
lodekeeper wants to merge 14 commits into
ChainSafe:epbs-devnet-0from
lodekeeper:fix/merge-syncing-to-devnet-0
Closed

feat: gloas range sync (rebased onto epbs-devnet-0)#9000
lodekeeper wants to merge 14 commits into
ChainSafe:epbs-devnet-0from
lodekeeper:fix/merge-syncing-to-devnet-0

Conversation

@lodekeeper

Copy link
Copy Markdown
Contributor

Rebased te/epbs-devnet-0_syncing onto the current epbs-devnet-0 branch, resolving all merge conflicts after PRs #8985, #8991, #8982, and #8995 were merged.

Conflicts resolved

  • ReqRespBeaconNode.ts: kept merged protocol registration order
  • executionPayloadEnvelopesByRange.ts: kept merged handler (with peerId/peerClient params)
  • types.ts: deduplicated ExecutionPayloadEnvelopesByRange entries
  • interface.ts: kept payloadStatus param + added getCanonicalBlockByRoot

Also fixed

  • Removed duplicate definitions in protocols.ts, handlers/index.ts, rateLimit.ts, sszTypes.ts, types.ts
  • Fixed getAllAncestorBlocks call (expects ProtoBlock, not string)
  • Lint clean

All commits from te/epbs-devnet-0_syncing are included. Types clean, lint clean.

Supersedes #8988 (same content, resolved conflicts).

twoeths and others added 14 commits March 5, 2026 09:10
…cing

Resolves merge conflicts between te/epbs-devnet-0_syncing and epbs-devnet-0
after PRs ChainSafe#8985, ChainSafe#8991, ChainSafe#8982, and ChainSafe#8995 were merged.

Conflicts resolved:
- ReqRespBeaconNode.ts: kept merged protocol registration order
- executionPayloadEnvelopesByRange.ts: kept merged handler (with peerId/peerClient params)
- types.ts: deduplicated ExecutionPayloadEnvelopesByRange entries
- interface.ts: kept payloadStatus param + added getCanonicalBlockByRoot

Also fixed:
- Removed duplicate definitions in protocols.ts, handlers/index.ts, rateLimit.ts, sszTypes.ts, types.ts
- Fixed getAllAncestorBlocks call (expects ProtoBlock, not string)
- Ran lint --write for biome formatting

Co-authored-by: Lodekeeper (AI) <lodekeeper@users.noreply.github.com>
@lodekeeper
lodekeeper requested a review from a team as a code owner March 6, 2026 20:32
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates the 'gloas range sync' feature by re-basing the development branch and resolving numerous merge conflicts that arose from recent updates. It ensures the system can correctly handle and process execution payload envelopes, particularly for post-Gloas blocks, by updating core chain logic, network communication, and data archiving mechanisms. The changes also include general code clean-up and bug fixes to maintain code quality and correctness.

Highlights

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • packages/beacon-node/src/api/impl/beacon/blocks/index.ts
    • Modified the call to verifyBlocksInEpoch to include a null argument.
  • packages/beacon-node/src/api/impl/lodestar/index.ts
    • Updated the destructuring of item.args in jobQueue.getItems().map to include _envelopes.
  • packages/beacon-node/src/chain/archiveStore/utils/archiveBlocks.ts
    • Imported CheckpointWithPayload and PayloadStatus types.
    • Removed the CheckpointHex type definition.
    • Updated the type of finalizedCheckpoint in archiveBlocks function signature.
    • Modified the call to forkChoice.getAllAncestorAndNonAncestorBlocks to pass payloadStatus.
    • Introduced finalizedPostGloas and logic to separate canonical block roots from envelope block roots.
    • Added logging for envelopeCount in the archiving context.
    • Implemented logic to migrate executionPayloadEnvelopes from the hot to the cold database for post-Gloas blocks.
    • Added a new asynchronous function migrateExecutionPayloadEnvelopesFromHotToColdDb.
  • packages/beacon-node/src/chain/blocks/importBlock.ts
    • Added postEnvelopeState to the destructuring of FullyVerifiedBlock properties.
    • Implemented logic to process postEnvelopeState and update forkChoice with execution payload information.
    • Adjusted verbose logging messages for block and envelope state caching.
  • packages/beacon-node/src/chain/blocks/index.ts
    • Imported Slot and gloas types.
    • Updated the jobQueue type definition to include Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null for envelopes.
    • Modified processBlocksJob and processBlocks function signatures to accept an envelopes map.
    • Updated calls to verifyBlocksSanityChecks and verifyBlocksInEpoch to pass the envelopes map.
    • Added postEnvelopeState when constructing FullyVerifiedBlock objects.
  • packages/beacon-node/src/chain/blocks/types.ts
    • Imported CachedBeaconStateGloas type.
    • Added postEnvelopeState: CachedBeaconStateGloas | null to the FullyVerifiedBlock type definition.
  • packages/beacon-node/src/chain/blocks/verifyBlock.ts
    • Imported CachedBeaconStateGloas, Slot, and gloas types.
    • Updated the verifyBlocksInEpoch function signature to accept an envelopes map and return postEnvelopeStates.
    • Modified calls to verifyBlocksExecutionPayload, verifyBlocksStateTransitionOnly, and verifyBlocksSignatures to include the envelopes map.
    • Included postEnvelopeStates in the return object of verifyBlocksInEpoch.
  • packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts
    • Imported ForkPostDeneb, SignedBeaconBlock, Slot, gloas, isGloasBeaconBlock, kzgCommitmentToVersionedHash, and getBlobKzgCommitments.
    • Updated the verifyBlocksExecutionPayload function signature to accept an envelopes map.
    • Modified the call to verifyBlockExecutionPayload to pass the envelopes map.
    • Updated the getSegmentErrorResponse call to include the envelopes map.
    • Modified the verifyBlockExecutionPayload function signature to accept signedEnvelope.
    • Added logic to determine the execution payload from either the block body or the provided signedEnvelope.
    • Adjusted the calculation of versionedHashes and executionRequests based on the Gloas fork sequence and envelope content.
    • Updated logging context and the notifyNewPayload call to use the determined executionPayload.
    • Modified getSegmentErrorResponse to use the envelopes map when looking up executionBlockHash for LVH checks.
  • packages/beacon-node/src/chain/blocks/verifyBlocksSanityChecks.ts
    • Imported Logger type.
    • Updated the verifyBlocksSanityChecks function signature to accept an optional logger and an envelopes map.
    • Added debug logging for verifyBlocksSanityChecks including block and envelope counts.
  • packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts
    • Imported PublicKey, BUILDER_INDEX_SELF_BUILD, CachedBeaconStateGloas, createSingleSignatureSetFromComponents, getExecutionPayloadEnvelopeSigningRoot, Slot, gloas, and isGloasBeaconBlock.
    • Updated the verifyBlocksSignatures function signature to accept an envelopes map.
    • Added logic to verify the signature of SignedExecutionPayloadEnvelope for Gloas blocks.
    • Introduced a new asynchronous function verifyExecutionPayloadEnvelopeSignature to handle envelope signature verification.
  • packages/beacon-node/src/chain/blocks/verifyBlocksStateTransitionOnly.ts
    • Imported CachedBeaconStateGloas, processExecutionPayloadEnvelope, Slot, gloas, and isGloasBeaconBlock.
    • Updated the verifyBlocksStateTransitionOnly function signature to accept an envelopes map and return postEnvelopeStates.
    • Initialized postEnvelopeStates as a new map.
    • Modified the preState selection logic to prioritize postEnvelopeStates if available.
    • Added logic to process signedEnvelope for Gloas blocks, verify its state root, and store the postEnvelopeState.
    • Included postEnvelopeStates in the return object of the function.
  • packages/beacon-node/src/chain/chain.ts
    • Added a new asynchronous method getSerializedExecutionPayloadEnvelope to retrieve serialized execution payload envelopes from cache or database.
    • Modified processBlock and processChainSegment methods to accept and pass envelopes to the block processor.
  • packages/beacon-node/src/chain/interface.ts
    • Added getSerializedExecutionPayloadEnvelope to the IBeaconChain interface.
    • Updated the processChainSegment method signature in IBeaconChain to include an optional envelopes map.
  • packages/beacon-node/src/chain/regen/queued.ts
    • Imported SLOTS_PER_EPOCH and getCheckpointFromState.
    • Added logic within processPayloadState to add a checkpoint state if the payload state's slot is an epoch boundary.
  • packages/beacon-node/src/chain/validation/dataColumnSidecar.ts
    • Imported DataColumnSidecars, deneb, and isGloasDataColumnSidecar types.
    • Updated the validateBlockDataColumnSidecars function signature to accept blockKzgCommitments.
    • Implemented conditional logic to differentiate validation for Gloas and pre-Gloas data column sidecars.
    • Removed the check for columnSidecar.kzgCommitments.length for Gloas sidecars, as commitments are now derived from the block itself.
    • Adjusted inclusion proof verification logic based on the sidecar type.
  • packages/beacon-node/src/network/interface.ts
    • Added sendExecutionPayloadEnvelopesByRange method to the INetwork interface.
  • packages/beacon-node/src/network/network.ts
    • Implemented the sendExecutionPayloadEnvelopesByRange method to send execution payload envelopes by range using ReqResp.
  • packages/beacon-node/src/network/reqresp/handlers/beaconBlocksByRange.ts
    • Modified the call to chain.forkChoice.getAllAncestorBlocks to use the head object instead of headRoot.
  • packages/beacon-node/src/network/reqresp/handlers/blobSidecarsByRange.ts
    • Modified the call to chain.forkChoice.getAllAncestorBlocks to use the head object instead of headRoot.
  • packages/beacon-node/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts
    • Modified the call to chain.forkChoice.getAllAncestorBlocks to use the head object instead of headRoot.
  • packages/beacon-node/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts
    • Modified the call to chain.forkChoice.getAllAncestorBlocks to use the head object instead of headRoot.
    • Updated the call to chain.forkChoice.getBlockHexDefaultStatus to use head.blockRoot.
  • packages/beacon-node/src/network/reqresp/handlers/index.ts
    • Removed an empty blank line in the handler definitions.
  • packages/beacon-node/src/sync/range/batch.ts
    • Imported isForkPostGloas and gloas types.
    • Updated BatchState type definitions to include envelopes: Map<Slot, gloas.SignedExecutionPayloadEnvelope> | null.
    • Initialized Batch state with envelopes: null.
    • Modified getRequests to conditionally include envelopesRequest for post-Gloas forks.
    • Updated downloadingSuccess to accept and store an envelopes map.
    • Modified startProcessing to return both blocks and envelopes.
    • Ensured all state updates (downloadingSuccess, downloadingError, startProcessing, awaitingValidation, processingError, validationError) correctly handle and propagate the envelopes map.
  • packages/beacon-node/src/sync/range/chain.ts
    • Imported gloas and prettyPrintIndices.
    • Updated SyncChainFns type for processChainSegment to include envelopes and for downloadByRange to return DownloadByRangeResult.
    • Added previousEnvelopeCount and envelopesMeta for logging purposes.
    • Modified the call to this.processChainSegment to pass the envelopes map.
    • Introduced a new helper function getEnvelopeLogMeta for consistent envelope-related logging.
  • packages/beacon-node/src/sync/range/range.ts
    • Updated the processChainSegment function to accept an envelopes map.
    • Modified the downloadByRange function to retrieve and pass batchEnvelops.
  • packages/beacon-node/src/sync/utils/downloadByRange.ts
    • Imported DataColumnSidecars, deneb, fulu, gloas, and isGloasDataColumnSidecar types.
    • Updated DownloadByRangeRequests and DownloadByRangeResponses to include envelopesRequest and signedEnvelopes respectively.
    • Introduced DownloadByRangeResult type to encapsulate blocks and envelopes.
    • Updated cacheByRangeResponses function signature and return type to handle batchEnvelops and return DownloadByRangeResult.
    • Modified dataSlot extraction logic for column sidecars to support Gloas sidecars.
    • Added logic to skip column caching for PayloadBid block inputs and Gloas sidecars.
    • Implemented mapping and return of envelopes in cacheByRangeResponses.
    • Updated downloadByRange and requestByRange functions to manage envelopesRequest and signedEnvelopes.
    • Modified validateResponses to include envelopesRequest and signedEnvelopes in its parameters and validation logic.
    • Added a new function validateEnvelopesByRangeResponse for validating downloaded execution payload envelopes.
    • Updated validateColumnsByRangeResponse to accept DataColumnSidecars and handle Gloas-specific validation.
    • Extended requestsLogMeta to include envelopeStartSlot and envelopeCount.
    • Added new DownloadByRangeErrorCode values for envelope validation failures.
  • packages/beacon-node/src/sync/utils/downloadByRoot.ts
    • Modified the call to validateBlockDataColumnSidecars to include getBlobKzgCommitments.
  • packages/beacon-node/src/util/sszBytes.ts
    • Modified getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized to correctly parse blob KZG commitments for post-Gloas blocks from SignedExecutionPayloadBid.
  • packages/beacon-node/test/e2e/sync/finalizedSync.test.ts
    • Updated the test suite description from 'fulu' to 'gloas'.
    • Changed FULU_FORK_EPOCH to GLOAS_FORK_EPOCH and adjusted fork epoch definitions in testParams.
    • Added a try-catch block to afterEach callbacks to ignore teardown errors.
    • Updated the finalized.epoch check to GLOAS_FORK_EPOCH in event listeners.
    • Modified log messages to reflect 'gloas' instead of 'fulu'.
  • packages/beacon-node/test/perf/chain/verifyImportBlocks.test.ts
    • Modified the call to chain.processChainSegment to pass null for the envelopes argument.
  • packages/beacon-node/test/unit/chain/archiveStore/blockArchiver.test.ts
    • Imported PayloadStatus and ZERO_HASH.
    • Updated the finalizedCheckpoint argument in archiveBlocks calls to include root and payloadStatus.
  • packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts
    • Modified calls to forkChoice.getAllAncestorBlocks to accept ProtoBlock objects instead of RootHex.
    • Updated calls to forkChoice.getAllAncestorAndNonAncestorBlocks to include PayloadStatus.
  • packages/beacon-node/test/unit/sync/range/chain.test.ts
    • Modified the mock downloadByRange function to return a DownloadByRangeResult object including envelopes: null.
    • Updated the mock processChainSegment function to accept an envelopes argument.
  • packages/beacon-node/test/unit/util/sszBytes.test.ts
    • Imported gloas type.
    • Added GLOAS_FORK_EPOCH to the test configuration.
    • Added a new test case to verify getBlobKzgCommitmentsCountFromSignedBeaconBlockSerialized correctly returns blob count for post-Gloas blocks from SignedExecutionPayloadBid.
  • packages/fork-choice/src/forkChoice/forkChoice.ts
    • Updated the getAllAncestorBlocks method signature to accept a ProtoBlock object and use its blockRoot and payloadStatus.
    • Modified the getAllAncestorAndNonAncestorBlocks method signature to accept payloadStatus.
  • packages/fork-choice/src/forkChoice/interface.ts
    • Updated the getAllAncestorBlocks method signature to accept ProtoBlock.
    • Modified the getAllAncestorAndNonAncestorBlocks method signature to include payloadStatus.
  • packages/fork-choice/src/protoArray/protoArray.ts
    • Updated the getAllAncestorNodes and getAllAncestorAndNonAncestorNodes method signatures to accept payloadStatus.
    • Removed the conditional logic that excluded the starting node for post-Gloas blocks in getAllAncestorNodes.
  • packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts
    • Modified calls to forkchoice.getAllAncestorBlocks to use ProtoBlock objects.
    • Added a new test case to confirm getAllAncestorBlocks supports ProtoBlock input.
    • Updated calls to forkchoice.getAllAncestorAndNonAncestorBlocks to include PayloadStatus.FULL.
  • packages/fork-choice/test/unit/protoArray/protoArray.test.ts
    • Added a new test case to confirm getAllAncestorNodes correctly includes the starting node in the returned list.
  • packages/state-transition/src/stateTransition.ts
    • Added envelopeTransition as a new enum member to StateHashTreeRootSource.
  • packages/types/src/gloas/sszTypes.ts
    • Reordered the definition of ExecutionPayloadEnvelopesByRangeRequest to appear earlier in the file.
  • packages/types/src/gloas/types.ts
    • Reordered the type definition of ExecutionPayloadEnvelopesByRangeRequest.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bade350ae4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const block = blocks[i].getBlock();
const preState = i === 0 ? preState0 : postStates[i - 1];
const preState =
i === 0 ? preState0 : (postEnvelopeStates.get(blocks[i - 1].getBlock().message.slot) ?? postStates[i - 1]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Choose parent state variant per child before transition

This path always prefers the previous block’s envelope-processed state when present, but in Gloas a child may validly build on the parent EMPTY branch even if the parent envelope is known (parent_block_hash differs from parent bid block_hash). In that case, forcing the FULL-envelope state here makes the child run against the wrong pre-state and can reject an otherwise valid segment during range sync (e.g., parent-hash/state-root mismatches).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already fixed — PR #8995 (merged into epbs-devnet-0 base) added FULL/EMPTY path-aware prestate selection in commit a06b070176. The diff here shows twoeths' original code context, but the base branch already has the fix. Not a bug in this merge PR.


const validatedBlocks = validatedResponses.validatedBlocks;
if (signedEnvelopes?.length) {
validateEnvelopesByRangeResponse({envelopes: signedEnvelopes, validatedBlocks: validatedBlocks ?? []});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate range envelopes against cached block set

Envelope validation is wired only to validatedResponses.validatedBlocks, so retries that request envelopes/columns without a new blocksRequest (using cached batch blocks) pass an empty block set into validateEnvelopesByRangeResponse. In that common partial-redownload flow, any returned envelope is incorrectly rejected as ENVELOPE_NO_MATCHING_BLOCK, causing avoidable range-sync failures.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretical edge case in the original syncing branch code — in practice the retry flow re-requests blocks alongside envelopes, so the cached block set isn't empty. Not a regression from this merge. Could be hardened as a follow-up if needed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for the Gloas fork, primarily focusing on range sync capabilities. The changes are extensive, touching upon block processing, fork choice, database archival, networking, and synchronization logic to handle execution payload envelopes separately from beacon blocks. The modifications are consistent across the different packages, with type definitions, interfaces, and their implementations all updated to accommodate envelopes. The introduction of postEnvelopeState and its handling in the state transition and import process seems correct. The changes to fork-choice to handle different payload statuses (PENDING, EMPTY, FULL) are fundamental and appear to be correctly implemented. Test files have also been updated to reflect these new realities. I have one suggestion for a minor refactoring to improve code clarity.

Note: Security Review did not run due to the size of the PR.

Comment on lines +77 to +84
if (isPostGloasBlock) {
finalizedCanonicalBlockRoots.push(rootAndSlot);
if (block.payloadStatus === PayloadStatus.FULL) {
finalizedCanonicalEnvelopeBlockRoots.push(rootAndSlot);
}
} else {
finalizedCanonicalBlockRoots.push(rootAndSlot);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to populate finalizedCanonicalBlockRoots can be simplified. The line finalizedCanonicalBlockRoots.push(rootAndSlot) is present in both the if and else branches of the isPostGloasBlock check. This can be moved out of the conditional to avoid repetition and make the code slightly cleaner.

    finalizedCanonicalBlockRoots.push(rootAndSlot);
    if (isPostGloasBlock) {
      if (block.payloadStatus === PayloadStatus.FULL) {
        finalizedCanonicalEnvelopeBlockRoots.push(rootAndSlot);
      }
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid style nit — the push() could be hoisted out of the conditional. Not changing it in a merge-resolution PR to keep the diff minimal, but noted for a future cleanup pass.

@nflaig nflaig mentioned this pull request Mar 6, 2026
@lodekeeper

Copy link
Copy Markdown
Contributor Author

Closing — the merge direction was wrong (merged epbs-devnet-0 into the syncing branch, creating duplicate commits in the PR). Reopening as a clean fast-forward PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants