Skip to content

Comments

feat: implement epbs block production#8838

Merged
nflaig merged 43 commits intounstablefrom
nflaig/epbs-block-production
Feb 20, 2026
Merged

feat: implement epbs block production#8838
nflaig merged 43 commits intounstablefrom
nflaig/epbs-block-production

Conversation

@nflaig
Copy link
Member

@nflaig nflaig commented Feb 2, 2026

Notable changes

  • implement epbs stateful block production (self-build only)
    • GET /eth/v4/validator/blocks/{slot} added
    • GET /eth/v1/validator/execution_payload_envelope/{slot}/{beacon_block_root} added
    • POST /eth/v1/beacon/execution_payload_envelope added
    • POST /eth/v2/beacon/blocks updated
  • implement envelope state root computation
  • update block production cache for gloas (includes state root)
  • add validator block production flow for gloas
  • add envelope signing to validator store / remote signer
  • data column sidecar changes required to wire up new gloas type
  • update beacon-api spec to v5.0.0-alpha.0

see ethereum/beacon-APIs#580 for reference

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @nflaig, 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 changes required to support block production for the upcoming 'Gloas' fork. The core change involves a shift from directly embedding execution payloads in beacon blocks to a system where beacon blocks contain bids, and the full execution payload is published in a separate envelope. This architectural change is crucial for enabling a more flexible and potentially more decentralized block building process, allowing for external builders to participate more effectively.

Highlights

  • Gloas Fork Block Production: Introduced a new block production mechanism specifically for the 'Gloas' fork, which changes how execution payloads are handled. Instead of including the full execution payload directly in the beacon block, proposers now submit an 'execution payload bid' within the beacon block.
  • New API Endpoints: Added three new API endpoints: 'publishExecutionPayloadEnvelope' (POST) to broadcast signed execution payload envelopes, 'produceBlockV4' (GET) for validators to request a block with an execution payload bid, and 'getExecutionPayloadEnvelope' (GET) to retrieve the full execution payload envelope.
  • Separated Execution Payload Envelope: The full execution payload, along with associated data columns (for PeerDAS), is now encapsulated in an 'execution payload envelope' which is published separately from the beacon block. This supports a builder-bid architecture.
  • Validator Signing for Envelopes: Implemented a new 'signExecutionPayloadEnvelope' method in the validator store, allowing validators to sign the execution payload envelope using the 'DOMAIN_BEACON_BUILDER' domain.
  • Data Column Handling for Gloas: Updated the logic for generating data column sidecars to specifically handle the 'Gloas' fork, where blobKzgCommitments are part of the ExecutionPayloadEnvelope rather than the BeaconBlockBody.

🧠 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.

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 initial implementation for enshrined proposer-builder separation (EPBS) through the new 'gloas' fork. It adds new API endpoints (produceBlockV4, getExecutionPayloadEnvelope, publishExecutionPayloadEnvelope) and modifies existing ones to support the new block production flow. The changes span across API definitions, beacon node implementation, and validator logic. The overall structure is sound, with a clear separation of concerns for the new gloas flow. However, as a work-in-progress, several critical components are marked with TODOs, such as signature verification for envelopes, state transition logic, and correct inclusion proof generation. I've provided specific feedback on a couple of areas: an incorrect type cast in the API route definitions and a logic improvement for retrieving cached block production data.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2026

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: dd73b87 Previous: 97dbe36 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.2442 ms/op 1.2721 ms/op 0.98
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 38.924 us/op 39.149 us/op 0.99
BLS verify - blst 871.59 us/op 885.19 us/op 0.98
BLS verifyMultipleSignatures 3 - blst 1.4434 ms/op 1.3013 ms/op 1.11
BLS verifyMultipleSignatures 8 - blst 2.0424 ms/op 1.9355 ms/op 1.06
BLS verifyMultipleSignatures 32 - blst 5.5281 ms/op 5.8327 ms/op 0.95
BLS verifyMultipleSignatures 64 - blst 9.1941 ms/op 11.011 ms/op 0.84
BLS verifyMultipleSignatures 128 - blst 17.900 ms/op 17.719 ms/op 1.01
BLS deserializing 10000 signatures 697.52 ms/op 710.43 ms/op 0.98
BLS deserializing 100000 signatures 6.9675 s/op 7.1173 s/op 0.98
BLS verifyMultipleSignatures - same message - 3 - blst 910.22 us/op 1.0778 ms/op 0.84
BLS verifyMultipleSignatures - same message - 8 - blst 1.0446 ms/op 1.2563 ms/op 0.83
BLS verifyMultipleSignatures - same message - 32 - blst 1.7475 ms/op 1.8390 ms/op 0.95
BLS verifyMultipleSignatures - same message - 64 - blst 2.6382 ms/op 2.7234 ms/op 0.97
BLS verifyMultipleSignatures - same message - 128 - blst 4.4614 ms/op 4.5252 ms/op 0.99
BLS aggregatePubkeys 32 - blst 19.626 us/op 19.730 us/op 0.99
BLS aggregatePubkeys 128 - blst 70.174 us/op 70.765 us/op 0.99
getSlashingsAndExits - default max 67.848 us/op 71.778 us/op 0.95
getSlashingsAndExits - 2k 319.54 us/op 301.88 us/op 1.06
isKnown best case - 1 super set check 199.00 ns/op 212.00 ns/op 0.94
isKnown normal case - 2 super set checks 195.00 ns/op 206.00 ns/op 0.95
isKnown worse case - 16 super set checks 195.00 ns/op 206.00 ns/op 0.95
validate api signedAggregateAndProof - struct 1.4308 ms/op 1.4540 ms/op 0.98
validate gossip signedAggregateAndProof - struct 1.4133 ms/op 1.4503 ms/op 0.97
batch validate gossip attestation - vc 640000 - chunk 32 117.60 us/op 129.78 us/op 0.91
batch validate gossip attestation - vc 640000 - chunk 64 103.80 us/op 111.88 us/op 0.93
batch validate gossip attestation - vc 640000 - chunk 128 100.13 us/op 97.125 us/op 1.03
batch validate gossip attestation - vc 640000 - chunk 256 93.441 us/op 93.835 us/op 1.00
bytes32 toHexString 357.00 ns/op 392.00 ns/op 0.91
bytes32 Buffer.toString(hex) 236.00 ns/op 280.00 ns/op 0.84
bytes32 Buffer.toString(hex) from Uint8Array 322.00 ns/op 348.00 ns/op 0.93
bytes32 Buffer.toString(hex) + 0x 240.00 ns/op 269.00 ns/op 0.89
Return object 10000 times 0.23340 ns/op 0.23530 ns/op 0.99
Throw Error 10000 times 4.1249 us/op 4.0727 us/op 1.01
toHex 132.74 ns/op 141.85 ns/op 0.94
Buffer.from 127.66 ns/op 124.26 ns/op 1.03
shared Buffer 77.894 ns/op 78.207 ns/op 1.00
fastMsgIdFn sha256 / 200 bytes 1.8950 us/op 2.0710 us/op 0.92
fastMsgIdFn h32 xxhash / 200 bytes 199.00 ns/op 197.00 ns/op 1.01
fastMsgIdFn h64 xxhash / 200 bytes 259.00 ns/op 309.00 ns/op 0.84
fastMsgIdFn sha256 / 1000 bytes 6.1240 us/op 6.1090 us/op 1.00
fastMsgIdFn h32 xxhash / 1000 bytes 294.00 ns/op 296.00 ns/op 0.99
fastMsgIdFn h64 xxhash / 1000 bytes 316.00 ns/op 358.00 ns/op 0.88
fastMsgIdFn sha256 / 10000 bytes 52.853 us/op 53.722 us/op 0.98
fastMsgIdFn h32 xxhash / 10000 bytes 1.3920 us/op 1.4500 us/op 0.96
fastMsgIdFn h64 xxhash / 10000 bytes 919.00 ns/op 959.00 ns/op 0.96
send data - 1000 256B messages 14.824 ms/op 13.554 ms/op 1.09
send data - 1000 512B messages 16.632 ms/op 17.276 ms/op 0.96
send data - 1000 1024B messages 21.849 ms/op 23.253 ms/op 0.94
send data - 1000 1200B messages 23.015 ms/op 24.828 ms/op 0.93
send data - 1000 2048B messages 24.783 ms/op 26.676 ms/op 0.93
send data - 1000 4096B messages 25.573 ms/op 28.090 ms/op 0.91
send data - 1000 16384B messages 161.34 ms/op 147.00 ms/op 1.10
send data - 1000 65536B messages 266.18 ms/op 266.37 ms/op 1.00
enrSubnets - fastDeserialize 64 bits 898.00 ns/op 917.00 ns/op 0.98
enrSubnets - ssz BitVector 64 bits 352.00 ns/op 367.00 ns/op 0.96
enrSubnets - fastDeserialize 4 bits 133.00 ns/op 145.00 ns/op 0.92
enrSubnets - ssz BitVector 4 bits 355.00 ns/op 398.00 ns/op 0.89
prioritizePeers score -10:0 att 32-0.1 sync 2-0 236.54 us/op 289.20 us/op 0.82
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 262.84 us/op 262.82 us/op 1.00
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 379.92 us/op 417.05 us/op 0.91
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 690.57 us/op 816.84 us/op 0.85
prioritizePeers score 0:0 att 64-1 sync 4-1 832.27 us/op 1.0140 ms/op 0.82
array of 16000 items push then shift 1.6216 us/op 1.6708 us/op 0.97
LinkedList of 16000 items push then shift 7.6680 ns/op 7.8000 ns/op 0.98
array of 16000 items push then pop 77.215 ns/op 79.575 ns/op 0.97
LinkedList of 16000 items push then pop 7.3780 ns/op 7.7950 ns/op 0.95
array of 24000 items push then shift 2.4197 us/op 2.4393 us/op 0.99
LinkedList of 24000 items push then shift 7.9430 ns/op 7.7950 ns/op 1.02
array of 24000 items push then pop 108.76 ns/op 111.81 ns/op 0.97
LinkedList of 24000 items push then pop 7.4120 ns/op 7.8460 ns/op 0.94
intersect bitArray bitLen 8 5.7480 ns/op 6.3710 ns/op 0.90
intersect array and set length 8 33.817 ns/op 34.955 ns/op 0.97
intersect bitArray bitLen 128 28.897 ns/op 29.873 ns/op 0.97
intersect array and set length 128 554.86 ns/op 570.33 ns/op 0.97
bitArray.getTrueBitIndexes() bitLen 128 998.00 ns/op 1.0720 us/op 0.93
bitArray.getTrueBitIndexes() bitLen 248 1.7930 us/op 1.8640 us/op 0.96
bitArray.getTrueBitIndexes() bitLen 512 3.6720 us/op 4.0690 us/op 0.90
Full columns - reconstruct all 6 blobs 236.64 us/op 371.38 us/op 0.64
Full columns - reconstruct half of the blobs out of 6 114.95 us/op 85.600 us/op 1.34
Full columns - reconstruct single blob out of 6 33.583 us/op 55.893 us/op 0.60
Half columns - reconstruct all 6 blobs 276.65 ms/op 388.91 ms/op 0.71
Half columns - reconstruct half of the blobs out of 6 146.62 ms/op 140.50 ms/op 1.04
Half columns - reconstruct single blob out of 6 56.943 ms/op 52.156 ms/op 1.09
Full columns - reconstruct all 10 blobs 298.68 us/op 340.38 us/op 0.88
Full columns - reconstruct half of the blobs out of 10 154.91 us/op 190.46 us/op 0.81
Full columns - reconstruct single blob out of 10 31.908 us/op 41.171 us/op 0.78
Half columns - reconstruct all 10 blobs 571.65 ms/op 463.92 ms/op 1.23
Half columns - reconstruct half of the blobs out of 10 295.74 ms/op 238.04 ms/op 1.24
Half columns - reconstruct single blob out of 10 51.957 ms/op 52.457 ms/op 0.99
Full columns - reconstruct all 20 blobs 682.34 us/op 1.2285 ms/op 0.56
Full columns - reconstruct half of the blobs out of 20 286.57 us/op 491.61 us/op 0.58
Full columns - reconstruct single blob out of 20 31.867 us/op 31.771 us/op 1.00
Half columns - reconstruct all 20 blobs 902.76 ms/op 927.27 ms/op 0.97
Half columns - reconstruct half of the blobs out of 20 449.25 ms/op 473.34 ms/op 0.95
Half columns - reconstruct single blob out of 20 50.714 ms/op 52.793 ms/op 0.96
Set add up to 64 items then delete first 2.0527 us/op 2.5255 us/op 0.81
OrderedSet add up to 64 items then delete first 3.0591 us/op 3.5446 us/op 0.86
Set add up to 64 items then delete last 2.3287 us/op 2.5847 us/op 0.90
OrderedSet add up to 64 items then delete last 3.3211 us/op 4.0532 us/op 0.82
Set add up to 64 items then delete middle 2.3336 us/op 2.6547 us/op 0.88
OrderedSet add up to 64 items then delete middle 4.9070 us/op 5.6889 us/op 0.86
Set add up to 128 items then delete first 4.9707 us/op 5.4774 us/op 0.91
OrderedSet add up to 128 items then delete first 7.4883 us/op 7.6701 us/op 0.98
Set add up to 128 items then delete last 4.7794 us/op 5.0315 us/op 0.95
OrderedSet add up to 128 items then delete last 6.8634 us/op 7.7714 us/op 0.88
Set add up to 128 items then delete middle 4.6628 us/op 4.8985 us/op 0.95
OrderedSet add up to 128 items then delete middle 18.406 us/op 14.641 us/op 1.26
Set add up to 256 items then delete first 9.8354 us/op 10.801 us/op 0.91
OrderedSet add up to 256 items then delete first 15.596 us/op 15.418 us/op 1.01
Set add up to 256 items then delete last 9.5269 us/op 10.217 us/op 0.93
OrderedSet add up to 256 items then delete last 14.927 us/op 15.507 us/op 0.96
Set add up to 256 items then delete middle 9.4306 us/op 10.164 us/op 0.93
OrderedSet add up to 256 items then delete middle 40.795 us/op 43.868 us/op 0.93
pass gossip attestations to forkchoice per slot 2.6119 ms/op 2.6951 ms/op 0.97
forkChoice updateHead vc 100000 bc 64 eq 0 502.72 us/op 517.46 us/op 0.97
forkChoice updateHead vc 600000 bc 64 eq 0 3.0320 ms/op 3.2381 ms/op 0.94
forkChoice updateHead vc 1000000 bc 64 eq 0 5.0844 ms/op 5.1677 ms/op 0.98
forkChoice updateHead vc 600000 bc 320 eq 0 3.0376 ms/op 3.1116 ms/op 0.98
forkChoice updateHead vc 600000 bc 1200 eq 0 3.1129 ms/op 3.1662 ms/op 0.98
forkChoice updateHead vc 600000 bc 7200 eq 0 3.5316 ms/op 3.9197 ms/op 0.90
forkChoice updateHead vc 600000 bc 64 eq 1000 3.6334 ms/op 3.6437 ms/op 1.00
forkChoice updateHead vc 600000 bc 64 eq 10000 3.7477 ms/op 3.6892 ms/op 1.02
forkChoice updateHead vc 600000 bc 64 eq 300000 9.5422 ms/op 9.7670 ms/op 0.98
computeDeltas 1400000 validators 0% inactive 15.408 ms/op 14.925 ms/op 1.03
computeDeltas 1400000 validators 10% inactive 13.554 ms/op 14.098 ms/op 0.96
computeDeltas 1400000 validators 20% inactive 12.623 ms/op 13.162 ms/op 0.96
computeDeltas 1400000 validators 50% inactive 9.8362 ms/op 10.254 ms/op 0.96
computeDeltas 2100000 validators 0% inactive 21.613 ms/op 22.415 ms/op 0.96
computeDeltas 2100000 validators 10% inactive 20.360 ms/op 21.057 ms/op 0.97
computeDeltas 2100000 validators 20% inactive 18.943 ms/op 19.837 ms/op 0.95
computeDeltas 2100000 validators 50% inactive 14.707 ms/op 15.529 ms/op 0.95
altair processAttestation - 250000 vs - 7PWei normalcase 2.6919 ms/op 2.6174 ms/op 1.03
altair processAttestation - 250000 vs - 7PWei worstcase 3.8646 ms/op 3.0087 ms/op 1.28
altair processAttestation - setStatus - 1/6 committees join 128.13 us/op 129.01 us/op 0.99
altair processAttestation - setStatus - 1/3 committees join 241.33 us/op 254.95 us/op 0.95
altair processAttestation - setStatus - 1/2 committees join 340.84 us/op 351.90 us/op 0.97
altair processAttestation - setStatus - 2/3 committees join 426.93 us/op 460.01 us/op 0.93
altair processAttestation - setStatus - 4/5 committees join 586.74 us/op 620.12 us/op 0.95
altair processAttestation - setStatus - 100% committees join 699.15 us/op 725.61 us/op 0.96
altair processBlock - 250000 vs - 7PWei normalcase 4.0005 ms/op 4.3289 ms/op 0.92
altair processBlock - 250000 vs - 7PWei normalcase hashState 17.120 ms/op 18.870 ms/op 0.91
altair processBlock - 250000 vs - 7PWei worstcase 23.775 ms/op 26.196 ms/op 0.91
altair processBlock - 250000 vs - 7PWei worstcase hashState 56.924 ms/op 61.062 ms/op 0.93
phase0 processBlock - 250000 vs - 7PWei normalcase 1.5297 ms/op 1.5565 ms/op 0.98
phase0 processBlock - 250000 vs - 7PWei worstcase 20.365 ms/op 20.724 ms/op 0.98
altair processEth1Data - 250000 vs - 7PWei normalcase 367.16 us/op 396.30 us/op 0.93
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 6.1430 us/op 7.5950 us/op 0.81
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 40.877 us/op 49.600 us/op 0.82
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 12.963 us/op 15.006 us/op 0.86
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 6.9870 us/op 9.1130 us/op 0.77
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 174.27 us/op 228.41 us/op 0.76
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.9251 ms/op 2.2310 ms/op 0.86
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 2.4155 ms/op 2.9212 ms/op 0.83
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 2.3665 ms/op 2.4580 ms/op 0.96
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.5973 ms/op 4.9264 ms/op 0.93
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.7633 ms/op 2.9329 ms/op 0.94
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.9375 ms/op 5.4049 ms/op 0.91
Tree 40 250000 create 357.76 ms/op 395.02 ms/op 0.91
Tree 40 250000 get(125000) 130.65 ns/op 140.85 ns/op 0.93
Tree 40 250000 set(125000) 1.2213 us/op 1.2572 us/op 0.97
Tree 40 250000 toArray() 14.072 ms/op 17.688 ms/op 0.80
Tree 40 250000 iterate all - toArray() + loop 15.006 ms/op 17.883 ms/op 0.84
Tree 40 250000 iterate all - get(i) 47.829 ms/op 49.928 ms/op 0.96
Array 250000 create 2.5149 ms/op 2.6255 ms/op 0.96
Array 250000 clone - spread 814.18 us/op 857.78 us/op 0.95
Array 250000 get(125000) 0.34000 ns/op 0.39600 ns/op 0.86
Array 250000 set(125000) 0.34700 ns/op 0.36000 ns/op 0.96
Array 250000 iterate all - loop 61.363 us/op 65.296 us/op 0.94
phase0 afterProcessEpoch - 250000 vs - 7PWei 41.519 ms/op 44.123 ms/op 0.94
Array.fill - length 1000000 2.8662 ms/op 3.0500 ms/op 0.94
Array push - length 1000000 11.131 ms/op 12.959 ms/op 0.86
Array.get 0.21605 ns/op 0.22881 ns/op 0.94
Uint8Array.get 0.21954 ns/op 0.22818 ns/op 0.96
phase0 beforeProcessEpoch - 250000 vs - 7PWei 13.927 ms/op 17.595 ms/op 0.79
altair processEpoch - mainnet_e81889 231.35 ms/op 261.53 ms/op 0.88
mainnet_e81889 - altair beforeProcessEpoch 15.701 ms/op 18.206 ms/op 0.86
mainnet_e81889 - altair processJustificationAndFinalization 5.6020 us/op 5.7400 us/op 0.98
mainnet_e81889 - altair processInactivityUpdates 3.7477 ms/op 3.9960 ms/op 0.94
mainnet_e81889 - altair processRewardsAndPenalties 17.768 ms/op 18.660 ms/op 0.95
mainnet_e81889 - altair processRegistryUpdates 637.00 ns/op 665.00 ns/op 0.96
mainnet_e81889 - altair processSlashings 165.00 ns/op 185.00 ns/op 0.89
mainnet_e81889 - altair processEth1DataReset 157.00 ns/op 181.00 ns/op 0.87
mainnet_e81889 - altair processEffectiveBalanceUpdates 2.0493 ms/op 4.9276 ms/op 0.42
mainnet_e81889 - altair processSlashingsReset 802.00 ns/op 895.00 ns/op 0.90
mainnet_e81889 - altair processRandaoMixesReset 1.0420 us/op 1.2290 us/op 0.85
mainnet_e81889 - altair processHistoricalRootsUpdate 163.00 ns/op 177.00 ns/op 0.92
mainnet_e81889 - altair processParticipationFlagUpdates 504.00 ns/op 513.00 ns/op 0.98
mainnet_e81889 - altair processSyncCommitteeUpdates 126.00 ns/op 140.00 ns/op 0.90
mainnet_e81889 - altair afterProcessEpoch 43.443 ms/op 46.282 ms/op 0.94
capella processEpoch - mainnet_e217614 728.52 ms/op 835.98 ms/op 0.87
mainnet_e217614 - capella beforeProcessEpoch 70.170 ms/op 76.080 ms/op 0.92
mainnet_e217614 - capella processJustificationAndFinalization 5.3500 us/op 6.1190 us/op 0.87
mainnet_e217614 - capella processInactivityUpdates 16.023 ms/op 13.853 ms/op 1.16
mainnet_e217614 - capella processRewardsAndPenalties 100.82 ms/op 103.08 ms/op 0.98
mainnet_e217614 - capella processRegistryUpdates 5.7390 us/op 5.9280 us/op 0.97
mainnet_e217614 - capella processSlashings 163.00 ns/op 161.00 ns/op 1.01
mainnet_e217614 - capella processEth1DataReset 158.00 ns/op 186.00 ns/op 0.85
mainnet_e217614 - capella processEffectiveBalanceUpdates 12.074 ms/op 18.911 ms/op 0.64
mainnet_e217614 - capella processSlashingsReset 785.00 ns/op 906.00 ns/op 0.87
mainnet_e217614 - capella processRandaoMixesReset 1.0610 us/op 1.1810 us/op 0.90
mainnet_e217614 - capella processHistoricalRootsUpdate 161.00 ns/op 202.00 ns/op 0.80
mainnet_e217614 - capella processParticipationFlagUpdates 510.00 ns/op 573.00 ns/op 0.89
mainnet_e217614 - capella afterProcessEpoch 134.60 ms/op 120.43 ms/op 1.12
phase0 processEpoch - mainnet_e58758 240.19 ms/op 290.43 ms/op 0.83
mainnet_e58758 - phase0 beforeProcessEpoch 45.857 ms/op 85.752 ms/op 0.53
mainnet_e58758 - phase0 processJustificationAndFinalization 5.5750 us/op 6.7830 us/op 0.82
mainnet_e58758 - phase0 processRewardsAndPenalties 18.177 ms/op 19.243 ms/op 0.94
mainnet_e58758 - phase0 processRegistryUpdates 2.7980 us/op 2.9370 us/op 0.95
mainnet_e58758 - phase0 processSlashings 165.00 ns/op 227.00 ns/op 0.73
mainnet_e58758 - phase0 processEth1DataReset 155.00 ns/op 196.00 ns/op 0.79
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.1060 ms/op 1.0168 ms/op 1.09
mainnet_e58758 - phase0 processSlashingsReset 882.00 ns/op 1.0010 us/op 0.88
mainnet_e58758 - phase0 processRandaoMixesReset 1.0780 us/op 1.2760 us/op 0.84
mainnet_e58758 - phase0 processHistoricalRootsUpdate 168.00 ns/op 193.00 ns/op 0.87
mainnet_e58758 - phase0 processParticipationRecordUpdates 856.00 ns/op 900.00 ns/op 0.95
mainnet_e58758 - phase0 afterProcessEpoch 35.511 ms/op 38.190 ms/op 0.93
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.8486 ms/op 1.6155 ms/op 1.14
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 2.0226 ms/op 2.9556 ms/op 0.68
altair processInactivityUpdates - 250000 normalcase 12.384 ms/op 15.876 ms/op 0.78
altair processInactivityUpdates - 250000 worstcase 12.558 ms/op 16.191 ms/op 0.78
phase0 processRegistryUpdates - 250000 normalcase 4.7780 us/op 5.5150 us/op 0.87
phase0 processRegistryUpdates - 250000 badcase_full_deposits 231.13 us/op 323.98 us/op 0.71
phase0 processRegistryUpdates - 250000 worstcase 0.5 65.095 ms/op 77.369 ms/op 0.84
altair processRewardsAndPenalties - 250000 normalcase 18.773 ms/op 18.829 ms/op 1.00
altair processRewardsAndPenalties - 250000 worstcase 17.488 ms/op 18.400 ms/op 0.95
phase0 getAttestationDeltas - 250000 normalcase 6.8239 ms/op 7.2913 ms/op 0.94
phase0 getAttestationDeltas - 250000 worstcase 6.8666 ms/op 7.2439 ms/op 0.95
phase0 processSlashings - 250000 worstcase 91.989 us/op 139.97 us/op 0.66
altair processSyncCommitteeUpdates - 250000 11.142 ms/op 12.959 ms/op 0.86
BeaconState.hashTreeRoot - No change 199.00 ns/op 197.00 ns/op 1.01
BeaconState.hashTreeRoot - 1 full validator 88.925 us/op 95.966 us/op 0.93
BeaconState.hashTreeRoot - 32 full validator 1.0358 ms/op 1.0941 ms/op 0.95
BeaconState.hashTreeRoot - 512 full validator 7.9195 ms/op 9.5320 ms/op 0.83
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 103.75 us/op 123.26 us/op 0.84
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4734 ms/op 1.8272 ms/op 0.81
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 16.118 ms/op 20.223 ms/op 0.80
BeaconState.hashTreeRoot - 1 balances 85.189 us/op 92.996 us/op 0.92
BeaconState.hashTreeRoot - 32 balances 767.33 us/op 945.79 us/op 0.81
BeaconState.hashTreeRoot - 512 balances 5.9140 ms/op 7.3433 ms/op 0.81
BeaconState.hashTreeRoot - 250000 balances 135.20 ms/op 161.51 ms/op 0.84
aggregationBits - 2048 els - zipIndexesInBitList 20.655 us/op 23.248 us/op 0.89
regular array get 100000 times 24.345 us/op 25.634 us/op 0.95
wrappedArray get 100000 times 24.343 us/op 25.654 us/op 0.95
arrayWithProxy get 100000 times 13.057 ms/op 15.177 ms/op 0.86
ssz.Root.equals 23.284 ns/op 25.002 ns/op 0.93
byteArrayEquals 22.849 ns/op 24.525 ns/op 0.93
Buffer.compare 9.7130 ns/op 10.536 ns/op 0.92
processSlot - 1 slots 11.022 us/op 12.073 us/op 0.91
processSlot - 32 slots 1.9170 ms/op 2.3718 ms/op 0.81
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 4.2341 ms/op 4.2185 ms/op 1.00
getCommitteeAssignments - req 1 vs - 250000 vc 1.8916 ms/op 1.9563 ms/op 0.97
getCommitteeAssignments - req 100 vs - 250000 vc 3.7032 ms/op 3.7985 ms/op 0.97
getCommitteeAssignments - req 1000 vs - 250000 vc 3.9507 ms/op 4.0565 ms/op 0.97
findModifiedValidators - 10000 modified validators 572.70 ms/op 676.53 ms/op 0.85
findModifiedValidators - 1000 modified validators 400.59 ms/op 451.65 ms/op 0.89
findModifiedValidators - 100 modified validators 323.51 ms/op 351.18 ms/op 0.92
findModifiedValidators - 10 modified validators 193.44 ms/op 240.61 ms/op 0.80
findModifiedValidators - 1 modified validators 189.28 ms/op 176.87 ms/op 1.07
findModifiedValidators - no difference 166.17 ms/op 182.24 ms/op 0.91
migrate state 1500000 validators, 3400 modified, 2000 new 953.10 ms/op 1.0991 s/op 0.87
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 4.2400 ns/op 4.4400 ns/op 0.95
state getBlockRootAtSlot - 250000 vs - 7PWei 516.41 ns/op 583.47 ns/op 0.89
computeProposerIndex 100000 validators 1.5748 ms/op 1.7529 ms/op 0.90
getNextSyncCommitteeIndices 1000 validators 116.85 ms/op 132.31 ms/op 0.88
getNextSyncCommitteeIndices 10000 validators 117.12 ms/op 128.71 ms/op 0.91
getNextSyncCommitteeIndices 100000 validators 119.54 ms/op 130.50 ms/op 0.92
computeProposers - vc 250000 643.22 us/op 710.49 us/op 0.91
computeEpochShuffling - vc 250000 41.816 ms/op 44.440 ms/op 0.94
getNextSyncCommittee - vc 250000 10.493 ms/op 12.512 ms/op 0.84
nodejs block root to RootHex using toHex 141.86 ns/op 152.51 ns/op 0.93
nodejs block root to RootHex using toRootHex 83.817 ns/op 93.592 ns/op 0.90
nodejs fromHex(blob) 225.81 us/op 539.12 us/op 0.42
nodejs fromHexInto(blob) 730.08 us/op 746.58 us/op 0.98
nodejs block root to RootHex using the deprecated toHexString 213.86 ns/op 594.20 ns/op 0.36
nodejs byteArrayEquals 32 bytes (block root) 28.516 ns/op 30.086 ns/op 0.95
nodejs byteArrayEquals 48 bytes (pubkey) 40.846 ns/op 43.266 ns/op 0.94
nodejs byteArrayEquals 96 bytes (signature) 40.382 ns/op 49.153 ns/op 0.82
nodejs byteArrayEquals 1024 bytes 47.387 ns/op 53.112 ns/op 0.89
nodejs byteArrayEquals 131072 bytes (blob) 1.8711 us/op 1.9482 us/op 0.96
browser block root to RootHex using toHex 166.85 ns/op 296.68 ns/op 0.56
browser block root to RootHex using toRootHex 156.65 ns/op 162.12 ns/op 0.97
browser fromHex(blob) 1.1769 ms/op 1.1438 ms/op 1.03
browser fromHexInto(blob) 707.71 us/op 757.01 us/op 0.93
browser block root to RootHex using the deprecated toHexString 561.17 ns/op 595.94 ns/op 0.94
browser byteArrayEquals 32 bytes (block root) 31.532 ns/op 33.054 ns/op 0.95
browser byteArrayEquals 48 bytes (pubkey) 44.133 ns/op 45.984 ns/op 0.96
browser byteArrayEquals 96 bytes (signature) 86.127 ns/op 90.171 ns/op 0.96
browser byteArrayEquals 1024 bytes 810.58 ns/op 855.00 ns/op 0.95
browser byteArrayEquals 131072 bytes (blob) 104.73 us/op 108.32 us/op 0.97

by benchmarkbot/action

@nflaig
Copy link
Member Author

nflaig commented Feb 8, 2026

@codex review

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

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@nflaig
Copy link
Member Author

nflaig commented Feb 14, 2026

/gemini review

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 support for the Gloas fork and Enshrined Proposer-Builder Separation (EPBS). It adds new API endpoints for the new block production flow, updates existing logic to be fork-aware, and implements the core changes in the beacon node and validator for producing and handling blocks under EPBS. The changes are extensive and well-structured. I've found one critical issue in the gossip handler for data_column_sidecar that will cause a runtime error on the Gloas fork. My review includes a suggestion to address this.

}

const delaySec = seenTimestampSec - computeTimeAtSlot(config, slot, chain.genesisTime);
metrics?.gossipExecutionPayloadEnvelope.elapsedTimeTillReceived.observe({source: OpSource.api}, delaySec);
Copy link
Member

Choose a reason for hiding this comment

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

Review if we can combine OpSource with other similar types

Copy link
Member Author

Choose a reason for hiding this comment

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

haven't found an obvious type with which we could combine it, seems fine to me as is

* This is the state root after running `processExecutionPayloadEnvelope` on the
* post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
*/
envelopeStateRoot: Root;
Copy link
Member

@wemeetagain wemeetagain Feb 19, 2026

Choose a reason for hiding this comment

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

discussion idea to figure out: store a reference to the post-block, pre-payload state instead of the post-payload state root

return ssz.deneb.BlobSidecar;
case GossipType.data_column_sidecar:
return ssz.fulu.DataColumnSidecar;
return isForkPostFulu(fork) ? sszTypesFor(fork).DataColumnSidecar : ssz.fulu.DataColumnSidecar;
Copy link
Member

Choose a reason for hiding this comment

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

can be simplified to just use sszTypesFor?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it's not possible because DataColumnSidecar doesn't exist pre-fulu, we used the same pattern for light client types in altair, we could think about updating sszTypesFor to have a default value to avoid having to handle this explicitly but this is rarely needed

wemeetagain
wemeetagain previously approved these changes Feb 19, 2026
Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

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

generally lgtm

we reviewed on a video meeting, all comments are minor nits and discussion points.

matthewkeil
matthewkeil previously approved these changes Feb 19, 2026
Copy link
Member

@matthewkeil matthewkeil left a comment

Choose a reason for hiding this comment

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

LGTM!!! 🚀

Did team review via Google Meet. Comments left by @wemeetagain. Approving assuming all the comments he documented from the call get resolved

@nflaig nflaig dismissed stale reviews from wemeetagain and matthewkeil via a118ebc February 20, 2026 14:15
@nflaig nflaig merged commit a35cbde into unstable Feb 20, 2026
24 of 26 checks passed
@nflaig nflaig deleted the nflaig/epbs-block-production branch February 20, 2026 14:36
@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.34%. Comparing base (97dbe36) to head (a118ebc).
⚠️ Report is 1 commits behind head on unstable.

Additional details and impacted files
@@            Coverage Diff            @@
##           unstable    #8838   +/-   ##
=========================================
  Coverage     52.33%   52.34%           
=========================================
  Files           848      848           
  Lines         63429    63380   -49     
  Branches       4702     4697    -5     
=========================================
- Hits          33195    33175   -20     
+ Misses        30165    30136   -29     
  Partials         69       69           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

4 participants