Skip to content

feat: defer payload processing to next block#9257

Merged
nflaig merged 58 commits intounstablefrom
nc/defer-payload-processing
Apr 23, 2026
Merged

feat: defer payload processing to next block#9257
nflaig merged 58 commits intounstablefrom
nc/defer-payload-processing

Conversation

@ensi321
Copy link
Copy Markdown
Contributor

@ensi321 ensi321 commented Apr 22, 2026

Will target unstable after #9254 is merged

implement ethereum/consensus-specs#5094

ensi321 and others added 24 commits April 21, 2026 15:19
Move slot from ExecutionPayloadEnvelope to ExecutionPayload as
slotNumber (uint64) and add slotNumber to PayloadAttributes per
consensus-specs#4840. Updates all verification, gossip validation,
signing, serialization, and SSZ byte extraction accordingly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eturn

New function implements deferred parent execution payload processing
(consensus-specs#5094). Moves execution requests, builder payment, and
availability updates from envelope processing to block processing.

Removes the isParentBlockFull early return in processWithdrawals since
processParentExecutionPayload now runs before withdrawals.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lock

New ordering for Gloas blocks:
1. processParentExecutionPayload (NEW - before header)
2. processBlockHeader
3. processWithdrawals (no longer has empty-parent early return)
4. processExecutionPayloadBid
5. ... rest unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Envelope verification no longer mutates state. All state effects (execution
requests, builder payment, availability, latestBlockHash) have moved to
processParentExecutionPayload in the next block.

Changes:
- Remove state cloning, execution request processing, builder payment,
  availability/latestBlockHash updates, and state root verification
- Add executionRequestsRoot check against bid commitment
- Return void instead of post-state
- Remove verifyStateRoot and dontTransferCache options
- Rename stateView method to verifyExecutionPayloadEnvelope

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…onPayload

With deferred payload processing, the envelope no longer produces a
separate post-state. The FULL variant node shares the same stateRoot
as the PENDING node.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- importExecutionPayload now does pure verification only — no state
  cloning, no post-payload state computation, no state root check,
  no regen.processState(), no checkpoint caching
- Remove stateRoot from executionPayload and executionPayloadGossip events
- Remove stateRoot from envelope construction in validator API
- Remove stateRoot from fork choice onExecutionPayload call
- Envelope verification runs via verifyExecutionPayloadEnvelope (void)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rocessing

Block production:
- Add executionRequestsRoot to ExecutionPayloadBid construction
- Add parentExecutionRequests to BeaconBlockBody via getParentExecutionRequests()
- Add getParentExecutionRequests() to BeaconChain (returns parent's
  execution requests from cached envelope, or empty if EMPTY parent)

Gossip validation:
- Add executionRequestsRoot check in envelope validation
- Add EXECUTION_REQUESTS_ROOT_MISMATCH error code

Cleanup:
- Remove stateRoot from validator envelope logging
- Fix spec test for void-returning processExecutionPayloadEnvelope
- Update stale TODO comment in writePayloadEnvelopeInputToDb

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use electra.ExecutionRequests type instead of unknown[]
- Fix parentBlockRootHex -> parentBlock.blockRoot variable name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
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 implements deferred payload processing for the Gloas fork, aligning the codebase with consensus-specs#5094. The implementation replaces the immediate state mutation in processExecutionPayloadEnvelope with a deferred approach in processParentExecutionPayload, where state effects are applied in the following block. Significant updates were made to block production and fork choice to handle the distinction between FULL and EMPTY parent variants. Review feedback identifies a critical consensus-breaking deviation in how builder payments are settled for older slots, a missing validation check for the execution head when the parent block is empty, and a logic error in fork choice initialization that hardcodes the payload status of checkpoints.

Comment thread packages/state-transition/src/block/processParentExecutionPayload.ts Outdated
Comment thread packages/beacon-node/src/chain/forkChoice/index.ts Outdated
Base automatically changed from nc/eip-7843-slot-number to unstable April 22, 2026 11:58
@nflaig nflaig changed the title Nc/defer payload processing feat: defer payload processing to next block Apr 22, 2026
…processing

# Conflicts:
#	packages/beacon-node/src/chain/blocks/importExecutionPayload.ts
#	packages/beacon-node/test/spec/presets/fork_choice.test.ts
#	packages/beacon-node/test/spec/utils/specTestIterator.ts
#	packages/state-transition/src/block/processExecutionPayloadEnvelope.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: fcd76b6 Previous: 6b7eebb Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 887.98 us/op 870.78 us/op 1.02
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 38.267 us/op 37.874 us/op 1.01
BLS verify - blst 638.62 us/op 627.08 us/op 1.02
BLS verifyMultipleSignatures 3 - blst 1.3231 ms/op 1.3033 ms/op 1.02
BLS verifyMultipleSignatures 8 - blst 2.1024 ms/op 2.0778 ms/op 1.01
BLS verifyMultipleSignatures 32 - blst 6.8345 ms/op 6.4923 ms/op 1.05
BLS verifyMultipleSignatures 64 - blst 13.123 ms/op 12.515 ms/op 1.05
BLS verifyMultipleSignatures 128 - blst 24.415 ms/op 24.696 ms/op 0.99
BLS deserializing 10000 signatures 620.18 ms/op 623.64 ms/op 0.99
BLS deserializing 100000 signatures 6.2230 s/op 6.2657 s/op 0.99
BLS verifyMultipleSignatures - same message - 3 - blst 747.03 us/op 747.94 us/op 1.00
BLS verifyMultipleSignatures - same message - 8 - blst 866.91 us/op 827.86 us/op 1.05
BLS verifyMultipleSignatures - same message - 32 - blst 1.4110 ms/op 1.4962 ms/op 0.94
BLS verifyMultipleSignatures - same message - 64 - blst 2.3117 ms/op 2.2771 ms/op 1.02
BLS verifyMultipleSignatures - same message - 128 - blst 3.8496 ms/op 3.9291 ms/op 0.98
BLS aggregatePubkeys 32 - blst 17.002 us/op 17.120 us/op 0.99
BLS aggregatePubkeys 128 - blst 60.444 us/op 60.633 us/op 1.00
getSlashingsAndExits - default max 47.122 us/op 44.348 us/op 1.06
getSlashingsAndExits - 2k 366.18 us/op 334.52 us/op 1.09
proposeBlockBody type=full, size=empty 706.62 us/op 596.00 us/op 1.19
isKnown best case - 1 super set check 166.00 ns/op 158.00 ns/op 1.05
isKnown normal case - 2 super set checks 157.00 ns/op 162.00 ns/op 0.97
isKnown worse case - 16 super set checks 161.00 ns/op 157.00 ns/op 1.03
validate api signedAggregateAndProof - struct 1.4571 ms/op 1.4600 ms/op 1.00
validate gossip signedAggregateAndProof - struct 1.4504 ms/op 1.4564 ms/op 1.00
batch validate gossip attestation - vc 640000 - chunk 32 105.94 us/op 104.79 us/op 1.01
batch validate gossip attestation - vc 640000 - chunk 64 91.310 us/op 93.487 us/op 0.98
batch validate gossip attestation - vc 640000 - chunk 128 83.555 us/op 85.831 us/op 0.97
batch validate gossip attestation - vc 640000 - chunk 256 81.174 us/op 84.769 us/op 0.96
bytes32 toHexString 275.00 ns/op 276.00 ns/op 1.00
bytes32 Buffer.toString(hex) 173.00 ns/op 164.00 ns/op 1.05
bytes32 Buffer.toString(hex) from Uint8Array 238.00 ns/op 237.00 ns/op 1.00
bytes32 Buffer.toString(hex) + 0x 174.00 ns/op 171.00 ns/op 1.02
Return object 10000 times 0.20430 ns/op 0.20980 ns/op 0.97
Throw Error 10000 times 3.1988 us/op 3.3717 us/op 0.95
toHex 95.179 ns/op 89.336 ns/op 1.07
Buffer.from 80.738 ns/op 82.516 ns/op 0.98
shared Buffer 53.292 ns/op 55.716 ns/op 0.96
fastMsgIdFn sha256 / 200 bytes 1.4130 us/op 1.4720 us/op 0.96
fastMsgIdFn h32 xxhash / 200 bytes 147.00 ns/op 146.00 ns/op 1.01
fastMsgIdFn h64 xxhash / 200 bytes 208.00 ns/op 203.00 ns/op 1.02
fastMsgIdFn sha256 / 1000 bytes 4.5350 us/op 4.6720 us/op 0.97
fastMsgIdFn h32 xxhash / 1000 bytes 235.00 ns/op 237.00 ns/op 0.99
fastMsgIdFn h64 xxhash / 1000 bytes 255.00 ns/op 246.00 ns/op 1.04
fastMsgIdFn sha256 / 10000 bytes 39.850 us/op 41.376 us/op 0.96
fastMsgIdFn h32 xxhash / 10000 bytes 1.2070 us/op 1.2810 us/op 0.94
fastMsgIdFn h64 xxhash / 10000 bytes 778.00 ns/op 826.00 ns/op 0.94
send data - 1000 256B messages 4.3525 ms/op 4.4917 ms/op 0.97
send data - 1000 512B messages 4.3978 ms/op 5.6530 ms/op 0.78
send data - 1000 1024B messages 4.5012 ms/op 4.6047 ms/op 0.98
send data - 1000 1200B messages 4.7992 ms/op 4.9926 ms/op 0.96
send data - 1000 2048B messages 4.8304 ms/op 5.2117 ms/op 0.93
send data - 1000 4096B messages 5.5894 ms/op 5.8291 ms/op 0.96
send data - 1000 16384B messages 14.434 ms/op 39.635 ms/op 0.36
send data - 1000 65536B messages 129.34 ms/op 189.10 ms/op 0.68
enrSubnets - fastDeserialize 64 bits 732.00 ns/op 710.00 ns/op 1.03
enrSubnets - ssz BitVector 64 bits 265.00 ns/op 254.00 ns/op 1.04
enrSubnets - fastDeserialize 4 bits 97.000 ns/op 97.000 ns/op 1.00
enrSubnets - ssz BitVector 4 bits 274.00 ns/op 258.00 ns/op 1.06
prioritizePeers score -10:0 att 32-0.1 sync 2-0 196.71 us/op 201.84 us/op 0.97
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 224.36 us/op 228.49 us/op 0.98
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 330.85 us/op 337.83 us/op 0.98
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 580.73 us/op 604.19 us/op 0.96
prioritizePeers score 0:0 att 64-1 sync 4-1 686.76 us/op 737.21 us/op 0.93
array of 16000 items push then shift 1.2302 us/op 1.2322 us/op 1.00
LinkedList of 16000 items push then shift 7.7700 ns/op 7.4730 ns/op 1.04
array of 16000 items push then pop 63.797 ns/op 65.424 ns/op 0.98
LinkedList of 16000 items push then pop 5.7630 ns/op 5.9360 ns/op 0.97
array of 24000 items push then shift 1.8069 us/op 1.8021 us/op 1.00
LinkedList of 24000 items push then shift 7.3300 ns/op 7.1160 ns/op 1.03
array of 24000 items push then pop 89.441 ns/op 93.902 ns/op 0.95
LinkedList of 24000 items push then pop 5.7820 ns/op 5.8910 ns/op 0.98
intersect bitArray bitLen 8 4.7110 ns/op 4.6510 ns/op 1.01
intersect array and set length 8 28.030 ns/op 28.618 ns/op 0.98
intersect bitArray bitLen 128 23.207 ns/op 23.398 ns/op 0.99
intersect array and set length 128 478.07 ns/op 490.30 ns/op 0.98
bitArray.getTrueBitIndexes() bitLen 128 951.00 ns/op 1.0450 us/op 0.91
bitArray.getTrueBitIndexes() bitLen 248 1.7150 us/op 1.7530 us/op 0.98
bitArray.getTrueBitIndexes() bitLen 512 3.5620 us/op 3.6210 us/op 0.98
Full columns - reconstruct all 6 blobs 174.75 us/op 136.00 us/op 1.28
Full columns - reconstruct half of the blobs out of 6 111.63 us/op 89.306 us/op 1.25
Full columns - reconstruct single blob out of 6 32.822 us/op 32.045 us/op 1.02
Half columns - reconstruct all 6 blobs 375.61 ms/op 386.73 ms/op 0.97
Half columns - reconstruct half of the blobs out of 6 188.84 ms/op 194.14 ms/op 0.97
Half columns - reconstruct single blob out of 6 68.544 ms/op 69.615 ms/op 0.98
Full columns - reconstruct all 10 blobs 267.11 us/op 271.89 us/op 0.98
Full columns - reconstruct half of the blobs out of 10 120.75 us/op 153.83 us/op 0.78
Full columns - reconstruct single blob out of 10 30.887 us/op 30.986 us/op 1.00
Half columns - reconstruct all 10 blobs 634.31 ms/op 655.55 ms/op 0.97
Half columns - reconstruct half of the blobs out of 10 322.91 ms/op 329.28 ms/op 0.98
Half columns - reconstruct single blob out of 10 69.730 ms/op 70.438 ms/op 0.99
Full columns - reconstruct all 20 blobs 1.8909 ms/op 1.3480 ms/op 1.40
Full columns - reconstruct half of the blobs out of 20 248.10 us/op 277.96 us/op 0.89
Full columns - reconstruct single blob out of 20 29.445 us/op 33.943 us/op 0.87
Half columns - reconstruct all 20 blobs 1.2850 s/op 1.2708 s/op 1.01
Half columns - reconstruct half of the blobs out of 20 635.71 ms/op 627.13 ms/op 1.01
Half columns - reconstruct single blob out of 20 68.753 ms/op 67.768 ms/op 1.01
Set add up to 64 items then delete first 2.4439 us/op 2.0347 us/op 1.20
OrderedSet add up to 64 items then delete first 3.3237 us/op 3.2140 us/op 1.03
Set add up to 64 items then delete last 2.3354 us/op 2.0291 us/op 1.15
OrderedSet add up to 64 items then delete last 3.3327 us/op 3.1472 us/op 1.06
Set add up to 64 items then delete middle 2.1047 us/op 2.0152 us/op 1.04
OrderedSet add up to 64 items then delete middle 4.8167 us/op 4.5255 us/op 1.06
Set add up to 128 items then delete first 4.0479 us/op 4.0136 us/op 1.01
OrderedSet add up to 128 items then delete first 6.6279 us/op 6.0619 us/op 1.09
Set add up to 128 items then delete last 3.9257 us/op 3.6959 us/op 1.06
OrderedSet add up to 128 items then delete last 6.0658 us/op 5.5870 us/op 1.09
Set add up to 128 items then delete middle 3.8250 us/op 3.6702 us/op 1.04
OrderedSet add up to 128 items then delete middle 11.882 us/op 11.633 us/op 1.02
Set add up to 256 items then delete first 7.5692 us/op 7.5310 us/op 1.01
OrderedSet add up to 256 items then delete first 11.618 us/op 11.805 us/op 0.98
Set add up to 256 items then delete last 7.7965 us/op 7.4696 us/op 1.04
OrderedSet add up to 256 items then delete last 11.986 us/op 11.030 us/op 1.09
Set add up to 256 items then delete middle 7.8504 us/op 7.2194 us/op 1.09
OrderedSet add up to 256 items then delete middle 36.272 us/op 37.761 us/op 0.96
pass gossip attestations to forkchoice per slot 2.5738 ms/op 2.5332 ms/op 1.02
forkChoice updateHead vc 100000 bc 64 eq 0 407.89 us/op 385.21 us/op 1.06
forkChoice updateHead vc 600000 bc 64 eq 0 2.3263 ms/op 2.3159 ms/op 1.00
forkChoice updateHead vc 1000000 bc 64 eq 0 3.8836 ms/op 3.7524 ms/op 1.03
forkChoice updateHead vc 600000 bc 320 eq 0 2.3410 ms/op 2.2372 ms/op 1.05
forkChoice updateHead vc 600000 bc 1200 eq 0 2.3666 ms/op 2.3238 ms/op 1.02
forkChoice updateHead vc 600000 bc 7200 eq 0 3.4022 ms/op 2.7125 ms/op 1.25
forkChoice updateHead vc 600000 bc 64 eq 1000 2.8642 ms/op 2.8188 ms/op 1.02
forkChoice updateHead vc 600000 bc 64 eq 10000 2.9882 ms/op 2.8995 ms/op 1.03
forkChoice updateHead vc 600000 bc 64 eq 300000 6.8270 ms/op 6.5849 ms/op 1.04
computeDeltas 1400000 validators 0% inactive 12.514 ms/op 12.109 ms/op 1.03
computeDeltas 1400000 validators 10% inactive 11.676 ms/op 11.306 ms/op 1.03
computeDeltas 1400000 validators 20% inactive 10.631 ms/op 10.350 ms/op 1.03
computeDeltas 1400000 validators 50% inactive 8.2625 ms/op 8.0744 ms/op 1.02
computeDeltas 2100000 validators 0% inactive 18.666 ms/op 18.386 ms/op 1.02
computeDeltas 2100000 validators 10% inactive 17.481 ms/op 17.152 ms/op 1.02
computeDeltas 2100000 validators 20% inactive 15.838 ms/op 15.605 ms/op 1.01
computeDeltas 2100000 validators 50% inactive 9.3299 ms/op 9.0967 ms/op 1.03
altair processAttestation - 250000 vs - 7PWei normalcase 2.3848 ms/op 2.5067 ms/op 0.95
altair processAttestation - 250000 vs - 7PWei worstcase 3.4630 ms/op 2.8256 ms/op 1.23
altair processAttestation - setStatus - 1/6 committees join 102.29 us/op 104.47 us/op 0.98
altair processAttestation - setStatus - 1/3 committees join 205.98 us/op 193.63 us/op 1.06
altair processAttestation - setStatus - 1/2 committees join 290.71 us/op 283.96 us/op 1.02
altair processAttestation - setStatus - 2/3 committees join 382.13 us/op 362.28 us/op 1.05
altair processAttestation - setStatus - 4/5 committees join 509.93 us/op 498.23 us/op 1.02
altair processAttestation - setStatus - 100% committees join 590.05 us/op 590.45 us/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase 4.7160 ms/op 4.6906 ms/op 1.01
altair processBlock - 250000 vs - 7PWei normalcase hashState 14.762 ms/op 16.848 ms/op 0.88
altair processBlock - 250000 vs - 7PWei worstcase 22.851 ms/op 23.340 ms/op 0.98
altair processBlock - 250000 vs - 7PWei worstcase hashState 43.223 ms/op 43.500 ms/op 0.99
phase0 processBlock - 250000 vs - 7PWei normalcase 1.2607 ms/op 1.5068 ms/op 0.84
phase0 processBlock - 250000 vs - 7PWei worstcase 18.791 ms/op 18.770 ms/op 1.00
altair processEth1Data - 250000 vs - 7PWei normalcase 298.36 us/op 306.26 us/op 0.97
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.5030 us/op 3.8660 us/op 0.91
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 22.853 us/op 21.584 us/op 1.06
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 7.1360 us/op 9.8460 us/op 0.72
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.5560 us/op 5.1160 us/op 0.70
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 91.842 us/op 89.410 us/op 1.03
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3491 ms/op 1.3106 ms/op 1.03
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.7520 ms/op 1.7280 ms/op 1.01
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7296 ms/op 1.8743 ms/op 0.92
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.1155 ms/op 4.9544 ms/op 0.83
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0034 ms/op 1.9746 ms/op 1.01
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.0669 ms/op 3.9997 ms/op 1.02
Tree 40 250000 create 303.51 ms/op 327.15 ms/op 0.93
Tree 40 250000 get(125000) 91.247 ns/op 88.719 ns/op 1.03
Tree 40 250000 set(125000) 986.64 ns/op 959.60 ns/op 1.03
Tree 40 250000 toArray() 15.126 ms/op 14.019 ms/op 1.08
Tree 40 250000 iterate all - toArray() + loop 15.308 ms/op 14.491 ms/op 1.06
Tree 40 250000 iterate all - get(i) 38.265 ms/op 38.219 ms/op 1.00
Array 250000 create 2.1517 ms/op 2.1464 ms/op 1.00
Array 250000 clone - spread 655.16 us/op 673.10 us/op 0.97
Array 250000 get(125000) 0.28800 ns/op 0.29500 ns/op 0.98
Array 250000 set(125000) 0.29400 ns/op 0.29600 ns/op 0.99
Array 250000 iterate all - loop 57.092 us/op 56.634 us/op 1.01
phase0 afterProcessEpoch - 250000 vs - 7PWei 39.465 ms/op 39.661 ms/op 1.00
Array.fill - length 1000000 2.0800 ms/op 2.2887 ms/op 0.91
Array push - length 1000000 8.8385 ms/op 8.3977 ms/op 1.05
Array.get 0.20485 ns/op 0.20274 ns/op 1.01
Uint8Array.get 0.23614 ns/op 0.23168 ns/op 1.02
phase0 beforeProcessEpoch - 250000 vs - 7PWei 20.298 ms/op 16.473 ms/op 1.23
altair processEpoch - mainnet_e81889 274.88 ms/op 291.88 ms/op 0.94
mainnet_e81889 - altair beforeProcessEpoch 39.134 ms/op 18.186 ms/op 2.15
mainnet_e81889 - altair processJustificationAndFinalization 6.3910 us/op 6.1870 us/op 1.03
mainnet_e81889 - altair processInactivityUpdates 7.5465 ms/op 5.7596 ms/op 1.31
mainnet_e81889 - altair processRewardsAndPenalties 22.080 ms/op 20.323 ms/op 1.09
mainnet_e81889 - altair processRegistryUpdates 548.00 ns/op 524.00 ns/op 1.05
mainnet_e81889 - altair processSlashings 151.00 ns/op 131.00 ns/op 1.15
mainnet_e81889 - altair processEth1DataReset 130.00 ns/op 126.00 ns/op 1.03
mainnet_e81889 - altair processEffectiveBalanceUpdates 8.5835 ms/op 1.6103 ms/op 5.33
mainnet_e81889 - altair processSlashingsReset 737.00 ns/op 687.00 ns/op 1.07
mainnet_e81889 - altair processRandaoMixesReset 1.3300 us/op 1.3050 us/op 1.02
mainnet_e81889 - altair processHistoricalRootsUpdate 125.00 ns/op 135.00 ns/op 0.93
mainnet_e81889 - altair processParticipationFlagUpdates 432.00 ns/op 424.00 ns/op 1.02
mainnet_e81889 - altair processSyncCommitteeUpdates 102.00 ns/op 111.00 ns/op 0.92
mainnet_e81889 - altair afterProcessEpoch 41.936 ms/op 43.710 ms/op 0.96
capella processEpoch - mainnet_e217614 888.11 ms/op 871.87 ms/op 1.02
mainnet_e217614 - capella beforeProcessEpoch 61.324 ms/op 67.084 ms/op 0.91
mainnet_e217614 - capella processJustificationAndFinalization 6.4990 us/op 6.8030 us/op 0.96
mainnet_e217614 - capella processInactivityUpdates 18.131 ms/op 21.224 ms/op 0.85
mainnet_e217614 - capella processRewardsAndPenalties 97.558 ms/op 99.682 ms/op 0.98
mainnet_e217614 - capella processRegistryUpdates 4.4690 us/op 4.6180 us/op 0.97
mainnet_e217614 - capella processSlashings 138.00 ns/op 133.00 ns/op 1.04
mainnet_e217614 - capella processEth1DataReset 138.00 ns/op 136.00 ns/op 1.01
mainnet_e217614 - capella processEffectiveBalanceUpdates 17.279 ms/op 21.668 ms/op 0.80
mainnet_e217614 - capella processSlashingsReset 703.00 ns/op 717.00 ns/op 0.98
mainnet_e217614 - capella processRandaoMixesReset 1.4270 us/op 1.5490 us/op 0.92
mainnet_e217614 - capella processHistoricalRootsUpdate 138.00 ns/op 127.00 ns/op 1.09
mainnet_e217614 - capella processParticipationFlagUpdates 441.00 ns/op 448.00 ns/op 0.98
mainnet_e217614 - capella afterProcessEpoch 109.00 ms/op 107.98 ms/op 1.01
phase0 processEpoch - mainnet_e58758 383.64 ms/op 319.65 ms/op 1.20
mainnet_e58758 - phase0 beforeProcessEpoch 89.470 ms/op 68.744 ms/op 1.30
mainnet_e58758 - phase0 processJustificationAndFinalization 12.943 us/op 6.2220 us/op 2.08
mainnet_e58758 - phase0 processRewardsAndPenalties 19.268 ms/op 16.490 ms/op 1.17
mainnet_e58758 - phase0 processRegistryUpdates 2.3630 us/op 2.1800 us/op 1.08
mainnet_e58758 - phase0 processSlashings 146.00 ns/op 131.00 ns/op 1.11
mainnet_e58758 - phase0 processEth1DataReset 143.00 ns/op 130.00 ns/op 1.10
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.1405 ms/op 788.27 us/op 1.45
mainnet_e58758 - phase0 processSlashingsReset 1.0440 us/op 885.00 ns/op 1.18
mainnet_e58758 - phase0 processRandaoMixesReset 1.5410 us/op 1.2720 us/op 1.21
mainnet_e58758 - phase0 processHistoricalRootsUpdate 168.00 ns/op 233.00 ns/op 0.72
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.2930 us/op 1.1790 us/op 1.10
mainnet_e58758 - phase0 afterProcessEpoch 34.060 ms/op 33.198 ms/op 1.03
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.0904 ms/op 994.73 us/op 1.10
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.6055 ms/op 1.7404 ms/op 0.92
altair processInactivityUpdates - 250000 normalcase 14.870 ms/op 12.391 ms/op 1.20
altair processInactivityUpdates - 250000 worstcase 13.976 ms/op 14.678 ms/op 0.95
phase0 processRegistryUpdates - 250000 normalcase 3.5410 us/op 5.0800 us/op 0.70
phase0 processRegistryUpdates - 250000 badcase_full_deposits 181.27 us/op 146.43 us/op 1.24
phase0 processRegistryUpdates - 250000 worstcase 0.5 87.976 ms/op 56.509 ms/op 1.56
altair processRewardsAndPenalties - 250000 normalcase 20.131 ms/op 16.278 ms/op 1.24
altair processRewardsAndPenalties - 250000 worstcase 20.235 ms/op 16.471 ms/op 1.23
phase0 getAttestationDeltas - 250000 normalcase 5.6623 ms/op 5.2140 ms/op 1.09
phase0 getAttestationDeltas - 250000 worstcase 5.6232 ms/op 5.1556 ms/op 1.09
phase0 processSlashings - 250000 worstcase 65.167 us/op 58.006 us/op 1.12
altair processSyncCommitteeUpdates - 250000 12.447 ms/op 9.7593 ms/op 1.28
BeaconState.hashTreeRoot - No change 204.00 ns/op 190.00 ns/op 1.07
BeaconState.hashTreeRoot - 1 full validator 90.719 us/op 89.457 us/op 1.01
BeaconState.hashTreeRoot - 32 full validator 933.95 us/op 971.95 us/op 0.96
BeaconState.hashTreeRoot - 512 full validator 10.511 ms/op 9.4082 ms/op 1.12
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 117.68 us/op 114.21 us/op 1.03
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.5146 ms/op 1.5833 ms/op 0.96
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 25.146 ms/op 23.241 ms/op 1.08
BeaconState.hashTreeRoot - 1 balances 84.046 us/op 92.316 us/op 0.91
BeaconState.hashTreeRoot - 32 balances 736.13 us/op 822.21 us/op 0.90
BeaconState.hashTreeRoot - 512 balances 8.2551 ms/op 7.5677 ms/op 1.09
BeaconState.hashTreeRoot - 250000 balances 160.12 ms/op 157.31 ms/op 1.02
aggregationBits - 2048 els - zipIndexesInBitList 20.855 us/op 19.443 us/op 1.07
regular array get 100000 times 22.941 us/op 22.268 us/op 1.03
wrappedArray get 100000 times 23.081 us/op 22.481 us/op 1.03
arrayWithProxy get 100000 times 18.099 ms/op 9.2616 ms/op 1.95
ssz.Root.equals 73.803 ns/op 20.748 ns/op 3.56
byteArrayEquals 21.283 ns/op 20.490 ns/op 1.04
Buffer.compare 8.8180 ns/op 8.4890 ns/op 1.04
processSlot - 1 slots 11.386 us/op 9.9280 us/op 1.15
processSlot - 32 slots 2.3658 ms/op 2.1361 ms/op 1.11
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 6.4518 ms/op 3.6518 ms/op 1.77
getCommitteeAssignments - req 1 vs - 250000 vc 1.6803 ms/op 1.5917 ms/op 1.06
getCommitteeAssignments - req 100 vs - 250000 vc 3.4154 ms/op 3.2733 ms/op 1.04
getCommitteeAssignments - req 1000 vs - 250000 vc 3.6996 ms/op 3.5149 ms/op 1.05
findModifiedValidators - 10000 modified validators 747.33 ms/op 648.17 ms/op 1.15
findModifiedValidators - 1000 modified validators 533.87 ms/op 417.84 ms/op 1.28
findModifiedValidators - 100 modified validators 309.95 ms/op 295.93 ms/op 1.05
findModifiedValidators - 10 modified validators 266.58 ms/op 255.11 ms/op 1.04
findModifiedValidators - 1 modified validators 161.90 ms/op 172.57 ms/op 0.94
findModifiedValidators - no difference 162.11 ms/op 164.51 ms/op 0.99
migrate state 1500000 validators, 3400 modified, 2000 new 3.5974 s/op 3.1366 s/op 1.15
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.6900 ns/op 3.6800 ns/op 1.00
state getBlockRootAtSlot - 250000 vs - 7PWei 405.65 ns/op 367.54 ns/op 1.10
computeProposerIndex 100000 validators 1.3721 ms/op 1.2536 ms/op 1.09
getNextSyncCommitteeIndices 1000 validators 2.8411 ms/op 2.7351 ms/op 1.04
getNextSyncCommitteeIndices 10000 validators 25.138 ms/op 24.182 ms/op 1.04
getNextSyncCommitteeIndices 100000 validators 89.483 ms/op 85.508 ms/op 1.05
computeProposers - vc 250000 554.53 us/op 531.02 us/op 1.04
computeEpochShuffling - vc 250000 39.146 ms/op 38.213 ms/op 1.02
getNextSyncCommittee - vc 250000 10.513 ms/op 10.070 ms/op 1.04
nodejs block root to RootHex using toHex 91.938 ns/op 89.238 ns/op 1.03
nodejs block root to RootHex using toRootHex 56.148 ns/op 54.473 ns/op 1.03
nodejs fromHex(blob) 907.45 us/op 786.00 us/op 1.15
nodejs fromHexInto(blob) 622.71 us/op 736.68 us/op 0.85
nodejs block root to RootHex using the deprecated toHexString 350.86 ns/op 350.91 ns/op 1.00
nodejs byteArrayEquals 32 bytes (block root) 25.519 ns/op 25.184 ns/op 1.01
nodejs byteArrayEquals 48 bytes (pubkey) 36.946 ns/op 36.070 ns/op 1.02
nodejs byteArrayEquals 96 bytes (signature) 33.585 ns/op 32.732 ns/op 1.03
nodejs byteArrayEquals 1024 bytes 40.439 ns/op 38.375 ns/op 1.05
nodejs byteArrayEquals 131072 bytes (blob) 1.7568 us/op 1.6965 us/op 1.04
browser block root to RootHex using toHex 142.92 ns/op 137.94 ns/op 1.04
browser block root to RootHex using toRootHex 129.38 ns/op 125.08 ns/op 1.03
browser fromHex(blob) 1.7195 ms/op 1.4889 ms/op 1.15
browser fromHexInto(blob) 617.93 us/op 618.43 us/op 1.00
browser block root to RootHex using the deprecated toHexString 462.06 ns/op 464.05 ns/op 1.00
browser byteArrayEquals 32 bytes (block root) 27.837 ns/op 28.053 ns/op 0.99
browser byteArrayEquals 48 bytes (pubkey) 39.693 ns/op 39.237 ns/op 1.01
browser byteArrayEquals 96 bytes (signature) 74.604 ns/op 73.020 ns/op 1.02
browser byteArrayEquals 1024 bytes 757.50 ns/op 735.26 ns/op 1.03
browser byteArrayEquals 131072 bytes (blob) 94.109 us/op 94.026 us/op 1.00

by benchmarkbot/action

@nflaig
Copy link
Copy Markdown
Member

nflaig commented Apr 23, 2026

@codex review

Copy link
Copy Markdown

@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: 56f686ce52

ℹ️ 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".

Comment thread packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts
Comment thread packages/beacon-node/src/chain/blocks/types.ts Outdated
Comment thread packages/state-transition/src/block/index.ts Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't know what happened here but it seems needed for spec tests, revisit later

Comment thread packages/state-transition/src/block/processWithdrawals.ts Outdated
Comment thread packages/beacon-node/test/spec/presets/fork_choice.test.ts Outdated

// 4. Apply backpressure from the write queue, before doing verification work.
// The actual DB write is deferred until after verification succeeds.
await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't understand why we did this, this doesn't make sense to me, I moved that check down after verification

// 6. Persist payload envelope to hot DB (performed asynchronously to avoid blocking)
// 6. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
// on the import pipeline during sync, then perform the write asynchronously to avoid blocking.
await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
Copy link
Copy Markdown
Member

@nflaig nflaig Apr 23, 2026

Choose a reason for hiding this comment

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

do we even wanna update fork choice before applying backpressure? I keep this for now but worth to reconsider

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.

I think we should update fork choice before persisting it as fork choice is quite time sensitive. Writing to DB is not.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we do that already, the db write is async, this is more about when to apply backpressure which in normal case shouldn't even happen, mostly during sync this is relevant

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

it would be good to have more eyes on importExecutionPayload later but it's good enough to merge this cc @wemeetagain @ensi321 @twoeths

Copy link
Copy Markdown
Member

@nflaig nflaig left a comment

Choose a reason for hiding this comment

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

LGTM

@nflaig nflaig merged commit 6b7eebb into unstable Apr 23, 2026
18 of 20 checks passed
@nflaig nflaig deleted the nc/defer-payload-processing branch April 23, 2026 16:17
nflaig added a commit that referenced this pull request Apr 23, 2026
**Motivation**

- We should not prune `PayloadEnvelopeInput` from
`seenPayloadEnvelopeInputCache` right after we persist to DB, because
block production needs it (next-slot `getParentExecutionRequests` and
`prepareExecutionPayload` read the cached envelope synchronously).

**Description**

- Keep the last 2 `PayloadEnvelope`s in memory (head + head.parent)
- In the worst case, we fall back to loading from DB.
- This PR gets the most part of #9249 targeting #9257 to make it ready
for unstable
  - block production modification is removed due to #9257

**AI Assistance Disclosure**

Used Claude Code to assist with implementation and review.

---------

Co-authored-by: Nico Flaig <nflaig@protonmail.com>
Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spec-gloas Issues targeting the Glamsterdam spec version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants