Skip to content

feat: add gloas execution payload envelope import pipeline#8962

Open
ensi321 wants to merge 14 commits intounstablefrom
nc/epbs-payload-import
Open

feat: add gloas execution payload envelope import pipeline#8962
ensi321 wants to merge 14 commits intounstablefrom
nc/epbs-payload-import

Conversation

@ensi321
Copy link
Contributor

@ensi321 ensi321 commented Feb 26, 2026

Summary

  • Implement the execution payload import pipeline for Gloas (ePBS)
  • Add PayloadEnvelopeInput class to track payload envelope + data columns
  • Add importExecutionPayload function for EL verification and execution payload state transition
  • Add SeenPayloadEnvelopeInput cache for managing payload inputs
  • Remove SeenExecutionPayloadEnvelopes in favour of SeenPayloadEnvelopeInput
  • Integrate with gossip handlers and API for payload publishing

Background

In Gloas (ePBS), beacon blocks and execution payloads have separate validity requirements:

  • Beacon blocks are valid immediately (builder may not reveal payload)
  • Execution payloads require data availability (payload envelope + sampled columns)

Key Changes

New Files

  • payloadEnvelopeInput/payloadEnvelopeInput.ts - Tracks bid + envelope + columns with 4-state machine
  • importExecutionPayload.ts - EL verification, signature check, execution payload state transition
  • writePayloadEnvelopeInputToDb.ts - Persists envelope + columns to DB
  • seenPayloadEnvelopeInput.ts - Cache with finalization pruning

Modified Files

  • importBlock.ts - Creates PayloadEnvelopeInput during Gloas block import
  • gossipHandlers.ts - Handles execution_payload topic, triggers import on completion
  • extractSlotRootFns.ts - SSZ helpers for payload envelope queueing
  • executionPayloadEnvelope.ts - Validation using block post-state (not head state)
  • fork-choice - Removed builderIndex/blockHashHex from ProtoBlock (now in PayloadEnvelopeInput)

TODO

  • Gloas data_column_sidecar gossip handler integration (commented, needs Gloas-specific validation)

🤖 Generated with Claude Code

@ensi321 ensi321 changed the title feat: add gloas execution payload envelope import pipeline feat: add gloas execution payload envelope import pipeline p[wip] Feb 26, 2026
@ensi321 ensi321 changed the title feat: add gloas execution payload envelope import pipeline p[wip] feat: add gloas execution payload envelope import pipeline [wip] Feb 26, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ensi321, 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 introduces the foundational infrastructure for handling Gloas execution payload envelopes within the beacon node. It establishes a new data flow that tracks the availability of execution payloads and their associated data columns, ensuring that blocks are only processed once all necessary components are received. This enhancement is crucial for supporting future Gloas-specific functionalities and maintaining data integrity throughout the block processing pipeline.

Highlights

  • New Execution Payload Envelope Import Pipeline: Introduced a comprehensive pipeline for importing Gloas execution payload envelopes, managing their lifecycle from initial block import to final persistence and event emission.
  • PayloadEnvelopeInput Class: Implemented a new PayloadEnvelopeInput class to track and manage the state of execution payload envelopes and their associated data columns for Gloas blocks, including methods for adding data and checking completion.
  • API and Gossip Integration: Integrated the new payload envelope processing into the beacon node's API for block submission and the gossip network handler for execution_payload messages, ensuring proper validation and event emission.
  • Database Persistence and Caching: Added functionality to persist complete PayloadEnvelopeInput data (envelope and data column sidecars) to the database and introduced a SeenPayloadEnvelopeInput cache to manage these instances, with pruning on finalization.
  • New Event and Metrics: Added a new EventType.executionPayloadAvailable to the API and introduced new Prometheus metrics to monitor the import activity and cache usage of execution payload envelopes.

🧠 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/api/src/beacon/routes/events.ts
    • Extended EventType enum and EventData type to include executionPayloadAvailable and defined its SSZ serialization.
  • packages/api/test/unit/beacon/testData/events.ts
    • Added test data for the new executionPayloadAvailable event.
  • packages/beacon-node/src/api/impl/beacon/blocks/index.ts
    • Updated block API to process signedExecutionPayloadEnvelope using PayloadEnvelopeInput and emit executionPayloadAvailable event.
  • packages/beacon-node/src/chain/blocks/importBlock.ts
    • Modified block import to create a PayloadEnvelopeInput for Gloas blocks.
  • packages/beacon-node/src/chain/blocks/importExecutionPayload.ts
    • Added importExecutionPayload function to handle the full import pipeline for execution payload envelopes, including EL verification and state transition.
  • packages/beacon-node/src/chain/blocks/payloadEnvelopeInput/index.ts
    • Created an index file to export payloadEnvelopeInput and types modules.
  • packages/beacon-node/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts
    • Implemented PayloadEnvelopeInput class to track and manage the state of execution payload envelopes and data columns for Gloas blocks.
  • packages/beacon-node/src/chain/blocks/payloadEnvelopeInput/types.ts
    • Defined various types and enums for PayloadEnvelopeInput and its related data sources.
  • packages/beacon-node/src/chain/blocks/writePayloadEnvelopeInputToDb.ts
    • Added functions to persist PayloadEnvelopeInput data, including the envelope and data column sidecars, to the database and prune from cache.
  • packages/beacon-node/src/chain/chain.ts
    • Refactored BeaconChain to utilize the new SeenPayloadEnvelopeInput cache and integrate the importExecutionPayload and persistPayloadEnvelopeInput functions.
  • packages/beacon-node/src/chain/interface.ts
    • Updated IBeaconChain interface to include PayloadEnvelopeInput related types and methods.
  • packages/beacon-node/src/chain/seenCache/index.ts
    • Updated the seen cache index to export the new PayloadEnvelopeInput and SeenPayloadEnvelopeInput modules.
  • packages/beacon-node/src/chain/seenCache/seenExecutionPayloadEnvelope.ts
    • Removed the SeenExecutionPayloadEnvelopes module.
  • packages/beacon-node/src/chain/seenCache/seenPayloadEnvelopeInput.ts
    • Added SeenPayloadEnvelopeInput class to cache and manage PayloadEnvelopeInput instances, with pruning on finalization.
  • packages/beacon-node/src/chain/validation/executionPayloadEnvelope.ts
    • Refactored execution payload envelope validation to leverage the new SeenPayloadEnvelopeInput cache and its methods.
  • packages/beacon-node/src/chain/validatorMonitor.ts
    • Updated ValidatorMonitor to register and monitor executionPayloadEnvelope events.
  • packages/beacon-node/src/metrics/metrics/lodestar.ts
    • Introduced new Prometheus metrics for tracking execution payload envelope import activity and PayloadEnvelopeInput cache size.
  • packages/beacon-node/src/network/processor/extractSlotRootFns.ts
    • Updated SSZ byte extraction utilities to correctly parse slot and root from Gloas data column sidecars and execution payload envelopes.
  • packages/beacon-node/src/network/processor/gossipHandlers.ts
    • Implemented the gossip handler for execution_payload to process incoming envelopes, update PayloadEnvelopeInput, and trigger import.
  • packages/fork-choice/src/forkChoice/forkChoice.ts
    • Removed Gloas-specific builderIndex and blockHashHex fields from ProtoBlock creation in ForkChoice.
  • packages/fork-choice/src/protoArray/interface.ts
    • Removed builderIndex and blockHashHex properties from the ProtoBlock interface.
Activity
  • The author ensi321 has implemented a new feature to handle Gloas execution payload envelope import. No specific review comments or further progress are available in the provided context.
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.

Copy link
Contributor

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

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 the import pipeline for Gloas execution payload envelopes, a significant feature for the upcoming Gloas fork. The changes are extensive, touching the API, core chain logic, validation, caching, and fork-choice mechanisms. The introduction of PayloadEnvelopeInput and SeenPayloadEnvelopeInput provides a robust mechanism for handling the asynchronous arrival of different components of a Gloas block. The refactoring to remove Gloas-specific details from ProtoBlock is a good architectural improvement, enhancing separation of concerns. The code is well-structured, and the changes are consistent across the codebase. I've identified one minor latent issue in some commented-out code and provided a suggestion to fix it.

// 3. Run verification steps in parallel (like verifyBlocksInEpoch)
// Note: No data availability check needed here - importExecutionPayload is only
// called when payloadInput.isComplete() is true, so all data is already available.
const [execResult, _postPayloadState] = await Promise.all([
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The destructuring of the result from Promise.all appears to be incorrect. The async IIFE on lines 103-118 returns an object { postPayloadState: mutableState }. The current destructuring on line 91 assigns this entire object to _postPayloadState, not just the state value. Consequently, the commented-out usage on line 153 (this.regen.processPayloadState(_postPayloadState)) would be incorrect as it would pass the object instead of the state itself.

To prevent this latent bug, you should destructure the postPayloadState property from the returned object.

Suggested change
const [execResult, _postPayloadState] = await Promise.all([
const [execResult, {postPayloadState: _postPayloadState}] = await Promise.all([

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: 024cb29 Previous: bb27317 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.0194 ms/op 1.0494 ms/op 0.97
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 36.990 us/op 37.590 us/op 0.98
BLS verify - blst 1.4283 ms/op 886.29 us/op 1.61
BLS verifyMultipleSignatures 3 - blst 1.1625 ms/op 2.2391 ms/op 0.52
BLS verifyMultipleSignatures 8 - blst 2.1541 ms/op 2.2726 ms/op 0.95
BLS verifyMultipleSignatures 32 - blst 7.3877 ms/op 6.8281 ms/op 1.08
BLS verifyMultipleSignatures 64 - blst 11.386 ms/op 11.272 ms/op 1.01
BLS verifyMultipleSignatures 128 - blst 16.795 ms/op 17.019 ms/op 0.99
BLS deserializing 10000 signatures 673.69 ms/op 655.87 ms/op 1.03
BLS deserializing 100000 signatures 6.6816 s/op 6.5495 s/op 1.02
BLS verifyMultipleSignatures - same message - 3 - blst 1.2087 ms/op 1.3390 ms/op 0.90
BLS verifyMultipleSignatures - same message - 8 - blst 961.90 us/op 1.6215 ms/op 0.59
BLS verifyMultipleSignatures - same message - 32 - blst 1.6177 ms/op 1.8546 ms/op 0.87
BLS verifyMultipleSignatures - same message - 64 - blst 2.8144 ms/op 2.7301 ms/op 1.03
BLS verifyMultipleSignatures - same message - 128 - blst 4.5476 ms/op 4.4847 ms/op 1.01
BLS aggregatePubkeys 32 - blst 18.750 us/op 19.172 us/op 0.98
BLS aggregatePubkeys 128 - blst 67.256 us/op 68.534 us/op 0.98
getSlashingsAndExits - default max 82.835 us/op 69.291 us/op 1.20
getSlashingsAndExits - 2k 310.51 us/op 323.30 us/op 0.96
isKnown best case - 1 super set check 201.00 ns/op 204.00 ns/op 0.99
isKnown normal case - 2 super set checks 197.00 ns/op 199.00 ns/op 0.99
isKnown worse case - 16 super set checks 197.00 ns/op 202.00 ns/op 0.98
validate api signedAggregateAndProof - struct 1.3253 ms/op 1.5490 ms/op 0.86
validate gossip signedAggregateAndProof - struct 1.9538 ms/op 2.5825 ms/op 0.76
batch validate gossip attestation - vc 640000 - chunk 32 115.11 us/op 154.06 us/op 0.75
batch validate gossip attestation - vc 640000 - chunk 64 102.11 us/op 102.51 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 128 95.322 us/op 94.695 us/op 1.01
batch validate gossip attestation - vc 640000 - chunk 256 91.201 us/op 88.914 us/op 1.03
bytes32 toHexString 357.00 ns/op 364.00 ns/op 0.98
bytes32 Buffer.toString(hex) 224.00 ns/op 248.00 ns/op 0.90
bytes32 Buffer.toString(hex) from Uint8Array 437.00 ns/op 326.00 ns/op 1.34
bytes32 Buffer.toString(hex) + 0x 264.00 ns/op 245.00 ns/op 1.08
Return object 10000 times 0.22240 ns/op 0.22870 ns/op 0.97
Throw Error 10000 times 4.0982 us/op 4.2105 us/op 0.97
toHex 139.25 ns/op 132.93 ns/op 1.05
Buffer.from 122.59 ns/op 135.42 ns/op 0.91
shared Buffer 72.795 ns/op 84.700 ns/op 0.86
fastMsgIdFn sha256 / 200 bytes 1.7620 us/op 1.8310 us/op 0.96
fastMsgIdFn h32 xxhash / 200 bytes 183.00 ns/op 246.00 ns/op 0.74
fastMsgIdFn h64 xxhash / 200 bytes 447.00 ns/op 254.00 ns/op 1.76
fastMsgIdFn sha256 / 1000 bytes 5.7800 us/op 5.8490 us/op 0.99
fastMsgIdFn h32 xxhash / 1000 bytes 420.00 ns/op 352.00 ns/op 1.19
fastMsgIdFn h64 xxhash / 1000 bytes 368.00 ns/op 290.00 ns/op 1.27
fastMsgIdFn sha256 / 10000 bytes 51.157 us/op 49.235 us/op 1.04
fastMsgIdFn h32 xxhash / 10000 bytes 1.3450 us/op 1.3250 us/op 1.02
fastMsgIdFn h64 xxhash / 10000 bytes 876.00 ns/op 1.3870 us/op 0.63
send data - 1000 256B messages 5.9982 ms/op 4.5429 ms/op 1.32
send data - 1000 512B messages 4.6758 ms/op 4.2621 ms/op 1.10
send data - 1000 1024B messages 5.4923 ms/op 4.5418 ms/op 1.21
send data - 1000 1200B messages 5.2456 ms/op 5.9245 ms/op 0.89
send data - 1000 2048B messages 6.6386 ms/op 5.8836 ms/op 1.13
send data - 1000 4096B messages 8.0520 ms/op 7.5792 ms/op 1.06
send data - 1000 16384B messages 34.010 ms/op 30.810 ms/op 1.10
send data - 1000 65536B messages 101.01 ms/op 88.008 ms/op 1.15
enrSubnets - fastDeserialize 64 bits 897.00 ns/op 900.00 ns/op 1.00
enrSubnets - ssz BitVector 64 bits 350.00 ns/op 328.00 ns/op 1.07
enrSubnets - fastDeserialize 4 bits 175.00 ns/op 130.00 ns/op 1.35
enrSubnets - ssz BitVector 4 bits 427.00 ns/op 322.00 ns/op 1.33
prioritizePeers score -10:0 att 32-0.1 sync 2-0 229.82 us/op 313.47 us/op 0.73
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 336.11 us/op 262.41 us/op 1.28
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 432.18 us/op 574.43 us/op 0.75
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 705.34 us/op 864.68 us/op 0.82
prioritizePeers score 0:0 att 64-1 sync 4-1 844.64 us/op 860.76 us/op 0.98
array of 16000 items push then shift 1.5637 us/op 1.5857 us/op 0.99
LinkedList of 16000 items push then shift 7.1290 ns/op 7.1950 ns/op 0.99
array of 16000 items push then pop 73.028 ns/op 74.283 ns/op 0.98
LinkedList of 16000 items push then pop 6.9570 ns/op 7.0080 ns/op 0.99
array of 24000 items push then shift 2.3318 us/op 2.3714 us/op 0.98
LinkedList of 24000 items push then shift 7.2250 ns/op 7.3110 ns/op 0.99
array of 24000 items push then pop 102.44 ns/op 105.13 ns/op 0.97
LinkedList of 24000 items push then pop 6.9570 ns/op 7.0390 ns/op 0.99
intersect bitArray bitLen 8 5.5330 ns/op 5.5980 ns/op 0.99
intersect array and set length 8 33.063 ns/op 32.787 ns/op 1.01
intersect bitArray bitLen 128 27.696 ns/op 28.047 ns/op 0.99
intersect array and set length 128 531.61 ns/op 538.47 ns/op 0.99
bitArray.getTrueBitIndexes() bitLen 128 1.2420 us/op 1.2910 us/op 0.96
bitArray.getTrueBitIndexes() bitLen 248 1.7720 us/op 1.8630 us/op 0.95
bitArray.getTrueBitIndexes() bitLen 512 3.7260 us/op 3.5960 us/op 1.04
Full columns - reconstruct all 6 blobs 274.48 us/op 225.70 us/op 1.22
Full columns - reconstruct half of the blobs out of 6 93.891 us/op 93.201 us/op 1.01
Full columns - reconstruct single blob out of 6 30.805 us/op 30.721 us/op 1.00
Half columns - reconstruct all 6 blobs 260.95 ms/op 258.21 ms/op 1.01
Half columns - reconstruct half of the blobs out of 6 131.57 ms/op 130.34 ms/op 1.01
Half columns - reconstruct single blob out of 6 47.764 ms/op 47.935 ms/op 1.00
Full columns - reconstruct all 10 blobs 280.73 us/op 291.15 us/op 0.96
Full columns - reconstruct half of the blobs out of 10 152.12 us/op 153.49 us/op 0.99
Full columns - reconstruct single blob out of 10 42.464 us/op 30.648 us/op 1.39
Half columns - reconstruct all 10 blobs 429.81 ms/op 429.18 ms/op 1.00
Half columns - reconstruct half of the blobs out of 10 215.82 ms/op 217.91 ms/op 0.99
Half columns - reconstruct single blob out of 10 47.010 ms/op 48.375 ms/op 0.97
Full columns - reconstruct all 20 blobs 797.36 us/op 469.93 us/op 1.70
Full columns - reconstruct half of the blobs out of 20 276.25 us/op 262.37 us/op 1.05
Full columns - reconstruct single blob out of 20 29.914 us/op 31.091 us/op 0.96
Half columns - reconstruct all 20 blobs 853.35 ms/op 856.12 ms/op 1.00
Half columns - reconstruct half of the blobs out of 20 430.11 ms/op 431.11 ms/op 1.00
Half columns - reconstruct single blob out of 20 47.991 ms/op 48.879 ms/op 0.98
Set add up to 64 items then delete first 1.9951 us/op 1.9732 us/op 1.01
OrderedSet add up to 64 items then delete first 2.9702 us/op 2.9162 us/op 1.02
Set add up to 64 items then delete last 2.2339 us/op 2.2797 us/op 0.98
OrderedSet add up to 64 items then delete last 3.2044 us/op 3.4608 us/op 0.93
Set add up to 64 items then delete middle 2.2555 us/op 2.3071 us/op 0.98
OrderedSet add up to 64 items then delete middle 4.7350 us/op 5.0338 us/op 0.94
Set add up to 128 items then delete first 4.6554 us/op 4.6639 us/op 1.00
OrderedSet add up to 128 items then delete first 7.1139 us/op 6.8959 us/op 1.03
Set add up to 128 items then delete last 4.4910 us/op 4.7076 us/op 0.95
OrderedSet add up to 128 items then delete last 6.5143 us/op 7.0704 us/op 0.92
Set add up to 128 items then delete middle 4.4334 us/op 4.5615 us/op 0.97
OrderedSet add up to 128 items then delete middle 12.725 us/op 13.391 us/op 0.95
Set add up to 256 items then delete first 9.5520 us/op 9.9849 us/op 0.96
OrderedSet add up to 256 items then delete first 14.901 us/op 14.846 us/op 1.00
Set add up to 256 items then delete last 9.2625 us/op 9.3386 us/op 0.99
OrderedSet add up to 256 items then delete last 13.627 us/op 14.304 us/op 0.95
Set add up to 256 items then delete middle 9.0887 us/op 9.1153 us/op 1.00
OrderedSet add up to 256 items then delete middle 39.291 us/op 41.142 us/op 0.96
pass gossip attestations to forkchoice per slot 607.29 us/op 480.48 us/op 1.26
computeDeltas 1400000 validators 0% inactive 13.869 ms/op 14.068 ms/op 0.99
computeDeltas 1400000 validators 10% inactive 12.959 ms/op 13.148 ms/op 0.99
computeDeltas 1400000 validators 20% inactive 12.061 ms/op 12.232 ms/op 0.99
computeDeltas 1400000 validators 50% inactive 9.3919 ms/op 9.4831 ms/op 0.99
computeDeltas 2100000 validators 0% inactive 20.817 ms/op 21.069 ms/op 0.99
computeDeltas 2100000 validators 10% inactive 19.846 ms/op 19.733 ms/op 1.01
computeDeltas 2100000 validators 20% inactive 18.060 ms/op 18.345 ms/op 0.98
computeDeltas 2100000 validators 50% inactive 14.018 ms/op 14.224 ms/op 0.99
altair processAttestation - 250000 vs - 7PWei normalcase 1.8157 ms/op 1.9004 ms/op 0.96
altair processAttestation - 250000 vs - 7PWei worstcase 2.6673 ms/op 2.6799 ms/op 1.00
altair processAttestation - setStatus - 1/6 committees join 114.01 us/op 114.56 us/op 1.00
altair processAttestation - setStatus - 1/3 committees join 224.58 us/op 223.75 us/op 1.00
altair processAttestation - setStatus - 1/2 committees join 311.15 us/op 312.45 us/op 1.00
altair processAttestation - setStatus - 2/3 committees join 403.52 us/op 403.15 us/op 1.00
altair processAttestation - setStatus - 4/5 committees join 558.57 us/op 557.26 us/op 1.00
altair processAttestation - setStatus - 100% committees join 658.14 us/op 658.38 us/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase 3.3556 ms/op 3.3717 ms/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase hashState 15.120 ms/op 16.964 ms/op 0.89
altair processBlock - 250000 vs - 7PWei worstcase 24.295 ms/op 24.031 ms/op 1.01
altair processBlock - 250000 vs - 7PWei worstcase hashState 59.093 ms/op 65.117 ms/op 0.91
phase0 processBlock - 250000 vs - 7PWei normalcase 1.6505 ms/op 1.7994 ms/op 0.92
phase0 processBlock - 250000 vs - 7PWei worstcase 27.069 ms/op 21.344 ms/op 1.27
altair processEth1Data - 250000 vs - 7PWei normalcase 377.54 us/op 367.94 us/op 1.03
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 14.739 us/op 5.7320 us/op 2.57
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 54.929 us/op 54.294 us/op 1.01
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 10.649 us/op 16.065 us/op 0.66
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 10.703 us/op 11.197 us/op 0.96
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 234.03 us/op 238.55 us/op 0.98
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.4726 ms/op 2.5312 ms/op 0.58
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 2.0231 ms/op 2.1198 ms/op 0.95
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 2.0040 ms/op 2.1207 ms/op 0.94
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.0947 ms/op 4.4411 ms/op 0.92
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.4612 ms/op 2.4907 ms/op 0.99
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.4508 ms/op 4.7161 ms/op 0.94
Tree 40 250000 create 385.70 ms/op 385.04 ms/op 1.00
Tree 40 250000 get(125000) 126.41 ns/op 127.44 ns/op 0.99
Tree 40 250000 set(125000) 1.1816 us/op 1.2068 us/op 0.98
Tree 40 250000 toArray() 12.814 ms/op 12.138 ms/op 1.06
Tree 40 250000 iterate all - toArray() + loop 13.627 ms/op 12.230 ms/op 1.11
Tree 40 250000 iterate all - get(i) 43.532 ms/op 41.835 ms/op 1.04
Array 250000 create 2.3738 ms/op 2.4017 ms/op 0.99
Array 250000 clone - spread 789.21 us/op 786.84 us/op 1.00
Array 250000 get(125000) 0.34300 ns/op 0.33300 ns/op 1.03
Array 250000 set(125000) 0.34800 ns/op 0.47100 ns/op 0.74
Array 250000 iterate all - loop 60.149 us/op 57.852 us/op 1.04
phase0 afterProcessEpoch - 250000 vs - 7PWei 40.724 ms/op 39.000 ms/op 1.04
Array.fill - length 1000000 3.0021 ms/op 3.1375 ms/op 0.96
Array push - length 1000000 10.344 ms/op 9.5786 ms/op 1.08
Array.get 0.21394 ns/op 0.21772 ns/op 0.98
Uint8Array.get 0.21773 ns/op 0.27366 ns/op 0.80
phase0 beforeProcessEpoch - 250000 vs - 7PWei 13.545 ms/op 14.429 ms/op 0.94
altair processEpoch - mainnet_e81889 276.40 ms/op 268.57 ms/op 1.03
mainnet_e81889 - altair beforeProcessEpoch 16.804 ms/op 19.756 ms/op 0.85
mainnet_e81889 - altair processJustificationAndFinalization 6.7820 us/op 6.9500 us/op 0.98
mainnet_e81889 - altair processInactivityUpdates 3.7292 ms/op 3.7240 ms/op 1.00
mainnet_e81889 - altair processRewardsAndPenalties 17.895 ms/op 17.884 ms/op 1.00
mainnet_e81889 - altair processRegistryUpdates 616.00 ns/op 751.00 ns/op 0.82
mainnet_e81889 - altair processSlashings 288.00 ns/op 258.00 ns/op 1.12
mainnet_e81889 - altair processEth1DataReset 204.00 ns/op 159.00 ns/op 1.28
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.9006 ms/op 2.1738 ms/op 0.87
mainnet_e81889 - altair processSlashingsReset 776.00 ns/op 798.00 ns/op 0.97
mainnet_e81889 - altair processRandaoMixesReset 1.5770 us/op 1.2790 us/op 1.23
mainnet_e81889 - altair processHistoricalRootsUpdate 193.00 ns/op 162.00 ns/op 1.19
mainnet_e81889 - altair processParticipationFlagUpdates 498.00 ns/op 509.00 ns/op 0.98
mainnet_e81889 - altair processSyncCommitteeUpdates 130.00 ns/op 126.00 ns/op 1.03
mainnet_e81889 - altair afterProcessEpoch 41.381 ms/op 40.959 ms/op 1.01
capella processEpoch - mainnet_e217614 853.04 ms/op 839.13 ms/op 1.02
mainnet_e217614 - capella beforeProcessEpoch 59.476 ms/op 58.774 ms/op 1.01
mainnet_e217614 - capella processJustificationAndFinalization 6.0250 us/op 5.5230 us/op 1.09
mainnet_e217614 - capella processInactivityUpdates 15.129 ms/op 18.177 ms/op 0.83
mainnet_e217614 - capella processRewardsAndPenalties 126.89 ms/op 108.77 ms/op 1.17
mainnet_e217614 - capella processRegistryUpdates 5.5820 us/op 5.7900 us/op 0.96
mainnet_e217614 - capella processSlashings 248.00 ns/op 154.00 ns/op 1.61
mainnet_e217614 - capella processEth1DataReset 162.00 ns/op 178.00 ns/op 0.91
mainnet_e217614 - capella processEffectiveBalanceUpdates 11.417 ms/op 11.399 ms/op 1.00
mainnet_e217614 - capella processSlashingsReset 810.00 ns/op 983.00 ns/op 0.82
mainnet_e217614 - capella processRandaoMixesReset 1.0840 us/op 1.2940 us/op 0.84
mainnet_e217614 - capella processHistoricalRootsUpdate 245.00 ns/op 167.00 ns/op 1.47
mainnet_e217614 - capella processParticipationFlagUpdates 809.00 ns/op 509.00 ns/op 1.59
mainnet_e217614 - capella afterProcessEpoch 112.77 ms/op 113.81 ms/op 0.99
phase0 processEpoch - mainnet_e58758 258.56 ms/op 278.12 ms/op 0.93
mainnet_e58758 - phase0 beforeProcessEpoch 48.330 ms/op 59.170 ms/op 0.82
mainnet_e58758 - phase0 processJustificationAndFinalization 5.3370 us/op 5.5190 us/op 0.97
mainnet_e58758 - phase0 processRewardsAndPenalties 17.907 ms/op 25.187 ms/op 0.71
mainnet_e58758 - phase0 processRegistryUpdates 4.2140 us/op 3.4760 us/op 1.21
mainnet_e58758 - phase0 processSlashings 163.00 ns/op 164.00 ns/op 0.99
mainnet_e58758 - phase0 processEth1DataReset 195.00 ns/op 183.00 ns/op 1.07
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 937.11 us/op 930.19 us/op 1.01
mainnet_e58758 - phase0 processSlashingsReset 871.00 ns/op 887.00 ns/op 0.98
mainnet_e58758 - phase0 processRandaoMixesReset 1.1070 us/op 1.3310 us/op 0.83
mainnet_e58758 - phase0 processHistoricalRootsUpdate 249.00 ns/op 203.00 ns/op 1.23
mainnet_e58758 - phase0 processParticipationRecordUpdates 829.00 ns/op 1.2860 us/op 0.64
mainnet_e58758 - phase0 afterProcessEpoch 34.140 ms/op 34.571 ms/op 0.99
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.5923 ms/op 1.8071 ms/op 0.88
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.8502 ms/op 1.6442 ms/op 1.13
altair processInactivityUpdates - 250000 normalcase 11.684 ms/op 12.696 ms/op 0.92
altair processInactivityUpdates - 250000 worstcase 11.503 ms/op 12.201 ms/op 0.94
phase0 processRegistryUpdates - 250000 normalcase 4.2270 us/op 4.4480 us/op 0.95
phase0 processRegistryUpdates - 250000 badcase_full_deposits 362.56 us/op 371.28 us/op 0.98
phase0 processRegistryUpdates - 250000 worstcase 0.5 76.213 ms/op 75.733 ms/op 1.01
altair processRewardsAndPenalties - 250000 normalcase 16.398 ms/op 16.023 ms/op 1.02
altair processRewardsAndPenalties - 250000 worstcase 20.500 ms/op 15.476 ms/op 1.32
phase0 getAttestationDeltas - 250000 normalcase 5.5331 ms/op 6.7041 ms/op 0.83
phase0 getAttestationDeltas - 250000 worstcase 5.6089 ms/op 6.7065 ms/op 0.84
phase0 processSlashings - 250000 worstcase 119.64 us/op 119.92 us/op 1.00
altair processSyncCommitteeUpdates - 250000 10.538 ms/op 10.334 ms/op 1.02
BeaconState.hashTreeRoot - No change 254.00 ns/op 228.00 ns/op 1.11
BeaconState.hashTreeRoot - 1 full validator 86.927 us/op 86.230 us/op 1.01
BeaconState.hashTreeRoot - 32 full validator 1.2056 ms/op 1.0438 ms/op 1.15
BeaconState.hashTreeRoot - 512 full validator 10.416 ms/op 7.2997 ms/op 1.43
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 94.549 us/op 111.66 us/op 0.85
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 2.2945 ms/op 2.3996 ms/op 0.96
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 19.196 ms/op 17.652 ms/op 1.09
BeaconState.hashTreeRoot - 1 balances 87.646 us/op 106.64 us/op 0.82
BeaconState.hashTreeRoot - 32 balances 942.44 us/op 1.3363 ms/op 0.71
BeaconState.hashTreeRoot - 512 balances 5.9923 ms/op 5.6906 ms/op 1.05
BeaconState.hashTreeRoot - 250000 balances 159.51 ms/op 161.99 ms/op 0.98
aggregationBits - 2048 els - zipIndexesInBitList 20.231 us/op 20.874 us/op 0.97
regular array get 100000 times 23.792 us/op 24.605 us/op 0.97
wrappedArray get 100000 times 23.711 us/op 24.548 us/op 0.97
arrayWithProxy get 100000 times 14.347 ms/op 17.620 ms/op 0.81
ssz.Root.equals 22.992 ns/op 23.873 ns/op 0.96
byteArrayEquals 22.604 ns/op 23.421 ns/op 0.97
Buffer.compare 9.5870 ns/op 10.169 ns/op 0.94
processSlot - 1 slots 11.160 us/op 9.7410 us/op 1.15
processSlot - 32 slots 2.1744 ms/op 2.5681 ms/op 0.85
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 4.1597 ms/op 4.6417 ms/op 0.90
getCommitteeAssignments - req 1 vs - 250000 vc 1.8462 ms/op 1.8681 ms/op 0.99
getCommitteeAssignments - req 100 vs - 250000 vc 3.6566 ms/op 3.6479 ms/op 1.00
getCommitteeAssignments - req 1000 vs - 250000 vc 3.8985 ms/op 3.9317 ms/op 0.99
findModifiedValidators - 10000 modified validators 384.29 ms/op 645.23 ms/op 0.60
findModifiedValidators - 1000 modified validators 362.45 ms/op 501.08 ms/op 0.72
findModifiedValidators - 100 modified validators 325.41 ms/op 301.86 ms/op 1.08
findModifiedValidators - 10 modified validators 246.25 ms/op 153.22 ms/op 1.61
findModifiedValidators - 1 modified validators 130.28 ms/op 158.66 ms/op 0.82
findModifiedValidators - no difference 148.08 ms/op 157.07 ms/op 0.94
migrate state 1500000 validators, 3400 modified, 2000 new 1.0312 s/op 910.89 ms/op 1.13
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 4.9600 ns/op 4.2700 ns/op 1.16
state getBlockRootAtSlot - 250000 vs - 7PWei 504.62 ns/op 533.27 ns/op 0.95
computeProposerIndex 100000 validators 1.4768 ms/op 1.6570 ms/op 0.89
getNextSyncCommitteeIndices 1000 validators 108.47 ms/op 121.89 ms/op 0.89
getNextSyncCommitteeIndices 10000 validators 108.44 ms/op 123.33 ms/op 0.88
getNextSyncCommitteeIndices 100000 validators 108.30 ms/op 122.46 ms/op 0.88
computeProposers - vc 250000 611.14 us/op 632.49 us/op 0.97
computeEpochShuffling - vc 250000 41.294 ms/op 42.403 ms/op 0.97
getNextSyncCommittee - vc 250000 10.380 ms/op 10.838 ms/op 0.96
nodejs block root to RootHex using toHex 127.26 ns/op 146.73 ns/op 0.87
nodejs block root to RootHex using toRootHex 86.004 ns/op 85.770 ns/op 1.00
nodejs fromHex(blob) 182.38 us/op 447.29 us/op 0.41
nodejs fromHexInto(blob) 689.77 us/op 703.64 us/op 0.98
nodejs block root to RootHex using the deprecated toHexString 206.13 ns/op 401.67 ns/op 0.51
nodejs byteArrayEquals 32 bytes (block root) 28.061 ns/op 28.330 ns/op 0.99
nodejs byteArrayEquals 48 bytes (pubkey) 40.272 ns/op 40.563 ns/op 0.99
nodejs byteArrayEquals 96 bytes (signature) 39.497 ns/op 39.669 ns/op 1.00
nodejs byteArrayEquals 1024 bytes 45.269 ns/op 45.404 ns/op 1.00
nodejs byteArrayEquals 131072 bytes (blob) 1.8385 us/op 1.8589 us/op 0.99
browser block root to RootHex using toHex 160.97 ns/op 161.48 ns/op 1.00
browser block root to RootHex using toRootHex 151.96 ns/op 153.49 ns/op 0.99
browser fromHex(blob) 1.3872 ms/op 1.1672 ms/op 1.19
browser fromHexInto(blob) 679.82 us/op 691.14 us/op 0.98
browser block root to RootHex using the deprecated toHexString 525.67 ns/op 361.55 ns/op 1.45
browser byteArrayEquals 32 bytes (block root) 30.360 ns/op 30.677 ns/op 0.99
browser byteArrayEquals 48 bytes (pubkey) 44.384 ns/op 42.741 ns/op 1.04
browser byteArrayEquals 96 bytes (signature) 83.345 ns/op 83.749 ns/op 1.00
browser byteArrayEquals 1024 bytes 777.50 ns/op 789.89 ns/op 0.98
browser byteArrayEquals 131072 bytes (blob) 98.069 us/op 99.564 us/op 0.98

by benchmarkbot/action

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ensi321 and others added 3 commits March 2, 2026 16:24
Use getBlockSlotState instead of getHeadState for builder pubkey lookup
during execution payload envelope validation. This ensures signature
verification uses the correct builder registry state at the block's slot,
rather than potentially stale head state that could differ due to reorgs
or head changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ensi321 ensi321 changed the title feat: add gloas execution payload envelope import pipeline [wip] feat: add gloas execution payload envelope import pipeline Mar 3, 2026
ensi321 and others added 2 commits March 2, 2026 17:42
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ensi321 ensi321 marked this pull request as ready for review March 3, 2026 01:44
@ensi321 ensi321 requested a review from a team as a code owner March 3, 2026 01:44
@ensi321
Copy link
Contributor Author

ensi321 commented Mar 3, 2026

@lodekeeper can you do a review on this?

Copy link

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

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: 7c998d3b70

ℹ️ 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 processEnvelopeTimer = metrics?.blockPayload.executionPayloadEnvelopeProcessingTime.startTimer();
processExecutionPayloadEnvelope(postBlockState, signedEnvelope, false);
processExecutionPayloadEnvelope(postBlockState, signedEnvelope, {verifySignature: false, verifyStateRoot: true});

Choose a reason for hiding this comment

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

P1 Badge Disable state-root check while deriving envelope state root

computeEnvelopeStateRoot() creates a signed envelope whose stateRoot is still a placeholder, but this call now enables verifyStateRoot. processExecutionPayloadEnvelope() will compare that placeholder root against the freshly-mutated state and throw, so self-built Gloas block production can fail before the function ever returns the computed root. This path should skip state-root verification during root derivation and only verify once the envelope carries the computed value.

Useful? React with 👍 / 👎.

Comment on lines +251 to +253
if (this.isComplete() && !this.importClaimed) {
this.importClaimed = true;
return true;

Choose a reason for hiding this comment

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

P1 Badge Allow retry after failed execution payload import

shouldImport() marks importClaimed before any import work is known to succeed, and there is no reset path if importExecutionPayload() later fails (for example ELERROR/UNAVAILABLE). In that case the payload input stays complete but permanently unclaimable, so later envelope/column arrivals cannot trigger a retry and the payload can remain unimported until pruning/finalization.

Useful? React with 👍 / 👎.

Copy link
Contributor

@lodekeeper lodekeeper left a comment

Choose a reason for hiding this comment

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

Superseded by corrected review: #8962 (review)

Copy link
Contributor

@lodekeeper lodekeeper left a comment

Choose a reason for hiding this comment

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

Did a pass on the latest diff. I agree with the newly raised P1s and think they should be addressed before merge:

  1. computeEnvelopeStateRoot currently calls processExecutionPayloadEnvelope with verifyStateRoot=true while deriving the state root from an envelope that still has a placeholder stateRoot. That can self-fail block production in this path. This derivation step should skip state-root verification and only verify after the computed root is populated.

  2. PayloadEnvelopeInput.shouldImport sets importClaimed=true before import success and never resets on import failure. If EL import fails transiently (ELERROR / UNAVAILABLE), later envelope/column arrivals cannot retry import and we can stay stuck until pruning/finalization.

Also +1 on the cache-eviction TODO thread (clearByRootAndSlot) — clearing too aggressively can wipe useful pending data paths and likely needs narrower eviction semantics.

@lodekeeper
Copy link
Contributor

@ensi321 done — I left a review pass on the latest diff (including the two new P1s and cache-eviction concern): #8962 (review)


const signatureSet = createSingleSignatureSetFromComponents(
PublicKey.fromBytes(state.builders.getReadonly(envelope.builderIndex).pubkey),
PublicKey.fromBytes((blockState as CachedBeaconStateGloas).builders.getReadonly(envelope.builderIndex).pubkey),
Copy link
Contributor

Choose a reason for hiding this comment

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

Potential correctness edge case: self-build envelopes use BUILDER_INDEX_SELF_BUILD in state-transition logic, but validation here always reads state.builders.getReadonly(envelope.builderIndex). Should we mirror processExecutionPayloadEnvelope handling and verify with proposer pubkey when builderIndex === BUILDER_INDEX_SELF_BUILD?

Copy link
Contributor

@twoeths twoeths left a comment

Choose a reason for hiding this comment

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

did not fully review the PR
the PayloadEnvelopeInput should support having available data if it sees >= 64 columns similar to what we have pre-gloas
I have #8974 to make it easier to transition there and deduplicate persisting DataColumnSidecar to db

// TODO GLOAS: Handle valid envelope. Need an import flow that calls `processExecutionPayloadEnvelope` and fork choice
if (payloadInput.shouldImport()) {
await chain.importExecutionPayload(payloadInput, {validSignature: true});
chain.persistPayloadEnvelope(payloadInput);
Copy link
Contributor

Choose a reason for hiding this comment

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

we should do the same to importBlock flow, do this persist inside importExecutionPayload
in importBlock flow, we use unfinalizedBlockWrites as a job queue because it has to wait for all columns while we can import block with >= NUMBER_OF_COLUMNS / 2
so we may end up having a queue in BeaconChain and use it in importExecutionPayload

const blobsLen = payloadInput.getBlobKzgCommitments().length;
if (blobsLen > 0) {
const {custodyColumns} = this.custodyConfig;
const dataColumnSidecars = payloadInput.getCustodyColumns();
Copy link
Contributor

Choose a reason for hiding this comment

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

we should not assume we have all columns at this point, we may only have half of them for super node
see https://github.com/ChainSafe/lodestar/pull/8818/changes#diff-0ee3fd00ea4e500a6d0793b6d1184a397ac52749a082d92023532c3ba414787eR51


// TODO GLOAS: Handle valid envelope. Need an import flow that calls `processExecutionPayloadEnvelope` and fork choice
if (payloadInput.shouldImport()) {
await chain.importExecutionPayload(payloadInput, {validSignature: true});
Copy link
Contributor

Choose a reason for hiding this comment

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

we should not await the import here, let network gossip this message to other peers once it passes validation
should separate the whole function to // validation and // handler parts

(async () => {
try {
// Clone state to avoid mutating the cached state
const mutableState = blockState.clone();
Copy link
Contributor

Choose a reason for hiding this comment

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

do not clone here, let the state-transition do it
see #8728

Copy link
Contributor Author

@ensi321 ensi321 Mar 10, 2026

Choose a reason for hiding this comment

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

Opened #9015 to refactor processExecutionPayloadEnvelope

envelope.message.executionRequests
),

opts.validSignature === true
Copy link
Contributor

Choose a reason for hiding this comment

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

do we ever need this validSignature option? seems like call sites should verify it separately before reaching this function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we need it for unknown payload sync (?)

I know for unknown block sync, we don't set ImportBlockOpts.validSignatures, so state transition verifies the signature.

this.chain.processBlock(pendingBlock.blockInput, {
ignoreIfKnown: true,
// there could be finalized/head sync at the same time so we need to ignore if finalized
// see https://github.com/ChainSafe/lodestar/issues/5650
ignoreIfFinalized: true,
blsVerifyOnMainThread: true,
})

},

registerExecutionPayloadEnvelope(_src, _delaySec, _envelope) {
// TODO GLOAS: implement execution payload envelope monitoring
Copy link
Contributor

Choose a reason for hiding this comment

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

why is execution payload envelope involved validator monitor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe for the case that the validator self-build a payload? Not sure if this would be useful. Any thought @nflaig ?

Copy link
Member

Choose a reason for hiding this comment

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

we track the publish block delay in validator monitor currently, could do the same for envelopes, but validator monitor seems the wrong place to track timing info like this, we can keep the stub for now and revisit later, just realized there is still a registerBlobSidecar which is similar and doesn't really belong in the validator monitor

const payloadInput = chain.seenPayloadEnvelopeInput.get(blockRootHex);
if (!payloadInput) {
throw new ApiError(404, `PayloadEnvelopeInput not found for block root ${blockRootHex}`);
}
Copy link
Member

Choose a reason for hiding this comment

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

this can happen if block and payload are submitted in parallel as documented here #8915 we will need a queuing mechanism on the api, we can just throw for now as we currently only submit sequentially which is fine for the devnets

// For self-builds, the proposer signs with their own validator key
// For external builders, verify using the builder's registered pubkey
// Use verify_execution_payload_envelope_signature(state, signed_envelope)
await validateApiExecutionPayloadEnvelope(chain, signedExecutionPayloadEnvelope);
Copy link
Member

Choose a reason for hiding this comment

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

we should probably run this validation earlier, based on ethereum/beacon-APIs#580 (comment) we wanna implement broadcast_validation so we can mirror what we have implemented in publishBlockV2

// TODO GLOAS: Unlike publishBlock which gossips and imports in parallel, we import before gossip here.
// The publishExecutionPayloadEnvelope spec says success = "gossip validation + broadcast", so we may
// want to gossip first. Need spec clarification on whether import failure should prevent broadcast.
if (payloadInput.shouldImport()) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't really see a reason why this should work differently than pre-gloas publish block flow, we can gossip and import in parallel

broadcast_validation is separate from this and needs to be validated earlier, the checks are not exactly the same as import checks, depending on which validation rule is chosen

so I think here we can assume all validation checks have passed already

},

registerExecutionPayloadEnvelope(_src, _delaySec, _envelope) {
// TODO GLOAS: implement execution payload envelope monitoring
Copy link
Member

Choose a reason for hiding this comment

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

we track the publish block delay in validator monitor currently, could do the same for envelopes, but validator monitor seems the wrong place to track timing info like this, we can keep the stub for now and revisit later, just realized there is still a registerBlobSidecar which is similar and doesn't really belong in the validator monitor

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.

5 participants