Skip to content

feat: implement EIP 7688 - #9390

Merged
ensi321 merged 17 commits into
unstablefrom
eip-7688
Jul 21, 2026
Merged

feat: implement EIP 7688#9390
ensi321 merged 17 commits into
unstablefrom
eip-7688

Conversation

@wemeetagain

Copy link
Copy Markdown
Member

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements support for the Gloas fork (EIP-7688) by transitioning core consensus structures like BeaconState and BeaconBlockBody to progressive SSZ types. Key changes include updating dependencies to @chainsafe/ssz v1.6.0, implementing Gloas-specific light client proof logic, and establishing P2P size limits for progressive gossip objects. Review feedback identifies a potential vulnerability where getGossipSSZMaxSize lacks explicit limits for attestations and points out a performance regression in the participation flag update logic due to O(N) array allocations. Further suggestions include using Gloas-native default headers in the light client server and simplifying fork-specific witness validation logic to ensure consistency and efficiency.

Comment thread packages/beacon-node/src/network/gossip/topic.ts
Comment thread packages/beacon-node/src/chain/lightClient/index.ts
Comment thread packages/beacon-node/src/chain/lightClient/index.ts
Comment thread packages/state-transition/src/epoch/processParticipationFlagUpdates.ts Outdated
@wemeetagain wemeetagain changed the title feat: EIP 7688 feat: implement EIP 7688 May 20, 2026
@github-actions

github-actions Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: e853a34 Previous: 27da921 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 901.15 us/op 1.2362 ms/op 0.73
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 38.822 us/op 39.670 us/op 0.98
BLS verify - blst 632.94 us/op 751.55 us/op 0.84
BLS verifyMultipleSignatures 3 - blst 1.2901 ms/op 1.3564 ms/op 0.95
BLS verifyMultipleSignatures 8 - blst 2.0470 ms/op 2.1595 ms/op 0.95
BLS verifyMultipleSignatures 32 - blst 6.4940 ms/op 6.8164 ms/op 0.95
BLS verifyMultipleSignatures 64 - blst 12.490 ms/op 13.555 ms/op 0.92
BLS verifyMultipleSignatures 128 - blst 24.206 ms/op 25.874 ms/op 0.94
BLS deserializing 10000 signatures 628.71 ms/op 640.88 ms/op 0.98
BLS deserializing 100000 signatures 6.2673 s/op 6.3913 s/op 0.98
BLS verifyMultipleSignatures - same message - 3 - blst 786.35 us/op 804.75 us/op 0.98
BLS verifyMultipleSignatures - same message - 8 - blst 857.59 us/op 933.10 us/op 0.92
BLS verifyMultipleSignatures - same message - 32 - blst 1.4513 ms/op 1.5457 ms/op 0.94
BLS verifyMultipleSignatures - same message - 64 - blst 2.2626 ms/op 2.3648 ms/op 0.96
BLS verifyMultipleSignatures - same message - 128 - blst 3.9058 ms/op 4.0503 ms/op 0.96
BLS aggregatePubkeys 32 - blst 17.235 us/op 17.580 us/op 0.98
BLS aggregatePubkeys 128 - blst 61.064 us/op 62.618 us/op 0.98
getSlashingsAndExits - default max 58.032 us/op 54.658 us/op 1.06
getSlashingsAndExits - 2k 436.26 us/op 367.74 us/op 1.19
proposeBlockBody type=full, size=empty 563.06 us/op 638.74 us/op 0.88
isKnown best case - 1 super set check 169.00 ns/op 166.00 ns/op 1.02
isKnown normal case - 2 super set checks 166.00 ns/op 164.00 ns/op 1.01
isKnown worse case - 16 super set checks 165.00 ns/op 166.00 ns/op 0.99
validate api signedAggregateAndProof - struct 1.4733 ms/op 1.5062 ms/op 0.98
validate gossip signedAggregateAndProof - struct 1.4683 ms/op 1.5042 ms/op 0.98
batch validate gossip attestation - vc 640000 - chunk 32 106.70 us/op 106.35 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 64 93.324 us/op 92.630 us/op 1.01
batch validate gossip attestation - vc 640000 - chunk 128 86.924 us/op 86.025 us/op 1.01
batch validate gossip attestation - vc 640000 - chunk 256 86.172 us/op 82.400 us/op 1.05
bytes32 toHexString 288.00 ns/op 296.00 ns/op 0.97
bytes32 Buffer.toString(hex) 172.00 ns/op 161.00 ns/op 1.07
bytes32 Buffer.toString(hex) from Uint8Array 235.00 ns/op 233.00 ns/op 1.01
bytes32 Buffer.toString(hex) + 0x 172.00 ns/op 164.00 ns/op 1.05
Return object 10000 times 0.20760 ns/op 0.21090 ns/op 0.98
Throw Error 10000 times 3.3443 us/op 3.4511 us/op 0.97
toHex 95.100 ns/op 97.261 ns/op 0.98
Buffer.from 85.899 ns/op 88.599 ns/op 0.97
shared Buffer 57.891 ns/op 60.967 ns/op 0.95
fastMsgIdFn sha256 / 200 bytes 1.4490 us/op 1.4680 us/op 0.99
fastMsgIdFn h32 xxhash / 200 bytes 152.00 ns/op 152.00 ns/op 1.00
fastMsgIdFn h64 xxhash / 200 bytes 202.00 ns/op 202.00 ns/op 1.00
fastMsgIdFn sha256 / 1000 bytes 4.6190 us/op 4.7630 us/op 0.97
fastMsgIdFn h32 xxhash / 1000 bytes 237.00 ns/op 243.00 ns/op 0.98
fastMsgIdFn h64 xxhash / 1000 bytes 245.00 ns/op 250.00 ns/op 0.98
fastMsgIdFn sha256 / 10000 bytes 40.759 us/op 41.697 us/op 0.98
fastMsgIdFn h32 xxhash / 10000 bytes 1.2220 us/op 1.2710 us/op 0.96
fastMsgIdFn h64 xxhash / 10000 bytes 786.00 ns/op 830.00 ns/op 0.95
send data - 1000 256B messages 4.3895 ms/op 4.1716 ms/op 1.05
send data - 1000 512B messages 5.5729 ms/op 5.1064 ms/op 1.09
send data - 1000 1024B messages 5.8894 ms/op 5.5459 ms/op 1.06
send data - 1000 1200B messages 6.7626 ms/op 6.0571 ms/op 1.12
send data - 1000 2048B messages 12.609 ms/op 15.662 ms/op 0.81
send data - 1000 4096B messages 34.901 ms/op 54.685 ms/op 0.64
send data - 1000 16384B messages 201.01 ms/op 262.20 ms/op 0.77
send data - 1000 65536B messages 640.07 ms/op 795.72 ms/op 0.80
enrSubnets - fastDeserialize 64 bits 701.00 ns/op 722.00 ns/op 0.97
enrSubnets - ssz BitVector 64 bits 261.00 ns/op 254.00 ns/op 1.03
enrSubnets - fastDeserialize 4 bits 100.00 ns/op 98.000 ns/op 1.02
enrSubnets - ssz BitVector 4 bits 267.00 ns/op 253.00 ns/op 1.06
prioritizePeers score -10:0 att 32-0.1 sync 2-0 193.57 us/op 200.23 us/op 0.97
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 218.32 us/op 228.56 us/op 0.96
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 321.57 us/op 338.72 us/op 0.95
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 567.57 us/op 593.40 us/op 0.96
prioritizePeers score 0:0 att 64-1 sync 4-1 661.45 us/op 688.85 us/op 0.96
array of 16000 items push then shift 1.2619 us/op 1.2873 us/op 0.98
LinkedList of 16000 items push then shift 7.0960 ns/op 6.8720 ns/op 1.03
array of 16000 items push then pop 70.465 ns/op 65.458 ns/op 1.08
LinkedList of 16000 items push then pop 5.6700 ns/op 5.8900 ns/op 0.96
array of 24000 items push then shift 1.7862 us/op 1.9002 us/op 0.94
LinkedList of 24000 items push then shift 6.8970 ns/op 6.5930 ns/op 1.05
array of 24000 items push then pop 100.62 ns/op 91.480 ns/op 1.10
LinkedList of 24000 items push then pop 5.7920 ns/op 5.8720 ns/op 0.99
intersect bitArray bitLen 8 4.5530 ns/op 4.7410 ns/op 0.96
intersect array and set length 8 28.087 ns/op 29.071 ns/op 0.97
intersect bitArray bitLen 128 22.957 ns/op 23.933 ns/op 0.96
intersect array and set length 128 475.81 ns/op 495.49 ns/op 0.96
bitArray.getTrueBitIndexes() bitLen 128 908.00 ns/op 1.0690 us/op 0.85
bitArray.getTrueBitIndexes() bitLen 248 1.6160 us/op 1.8740 us/op 0.86
bitArray.getTrueBitIndexes() bitLen 512 3.3810 us/op 3.7640 us/op 0.90
Full columns - reconstruct all 6 blobs 254.65 us/op 150.78 us/op 1.69
Full columns - reconstruct half of the blobs out of 6 76.565 us/op 93.882 us/op 0.82
Full columns - reconstruct single blob out of 6 34.296 us/op 51.702 us/op 0.66
Half columns - reconstruct all 6 blobs 371.94 ms/op 380.30 ms/op 0.98
Half columns - reconstruct half of the blobs out of 6 188.54 ms/op 189.97 ms/op 0.99
Half columns - reconstruct single blob out of 6 66.794 ms/op 66.915 ms/op 1.00
Set add up to 64 items then delete first 1.5533 us/op 1.6418 us/op 0.95
OrderedSet add up to 64 items then delete first 2.4104 us/op 2.5336 us/op 0.95
Set add up to 64 items then delete last 1.7825 us/op 1.8865 us/op 0.94
OrderedSet add up to 64 items then delete last 2.6658 us/op 2.7940 us/op 0.95
Set add up to 64 items then delete middle 1.7870 us/op 1.8804 us/op 0.95
OrderedSet add up to 64 items then delete middle 4.0799 us/op 4.3006 us/op 0.95
Set add up to 128 items then delete first 3.5686 us/op 3.7476 us/op 0.95
OrderedSet add up to 128 items then delete first 5.6701 us/op 5.7827 us/op 0.98
Set add up to 128 items then delete last 3.4639 us/op 3.7287 us/op 0.93
OrderedSet add up to 128 items then delete last 5.0620 us/op 5.5197 us/op 0.92
Set add up to 128 items then delete middle 3.4189 us/op 3.5942 us/op 0.95
OrderedSet add up to 128 items then delete middle 10.687 us/op 11.467 us/op 0.93
Set add up to 256 items then delete first 7.1276 us/op 7.6934 us/op 0.93
OrderedSet add up to 256 items then delete first 11.512 us/op 11.795 us/op 0.98
Set add up to 256 items then delete last 6.8105 us/op 7.1251 us/op 0.96
OrderedSet add up to 256 items then delete last 10.577 us/op 10.918 us/op 0.97
Set add up to 256 items then delete middle 6.7325 us/op 7.1051 us/op 0.95
OrderedSet add up to 256 items then delete middle 33.486 us/op 34.079 us/op 0.98
runFastConfirmationRules vc:100000 bc:96 eq:0 4.2081 ms/op 4.4876 ms/op 0.94
runFastConfirmationRules vc:600000 bc:96 eq:0 47.602 ms/op 33.985 ms/op 1.40
runFastConfirmationRules vc:1000000 bc:96 eq:0 54.668 ms/op 57.236 ms/op 0.96
runFastConfirmationRules vc:600000 bc:320 eq:0 33.825 ms/op 34.014 ms/op 0.99
runFastConfirmationRules vc:100000 bc:96 eq:1000 1.3006 s/op 1.1447 s/op 1.14
pass gossip attestations to forkchoice per slot 2.4993 ms/op 2.6024 ms/op 0.96
forkChoice updateHead vc 100000 bc 64 eq 0 388.71 us/op 414.07 us/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 0 2.3111 ms/op 2.4896 ms/op 0.93
forkChoice updateHead vc 1000000 bc 64 eq 0 3.8549 ms/op 4.1295 ms/op 0.93
forkChoice updateHead vc 600000 bc 320 eq 0 2.3068 ms/op 2.4877 ms/op 0.93
forkChoice updateHead vc 600000 bc 1200 eq 0 2.3545 ms/op 2.4913 ms/op 0.95
forkChoice updateHead vc 600000 bc 7200 eq 0 2.7434 ms/op 2.8884 ms/op 0.95
forkChoice updateHead vc 600000 bc 64 eq 1000 2.3034 ms/op 2.4493 ms/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 10000 2.4199 ms/op 2.5434 ms/op 0.95
forkChoice updateHead vc 600000 bc 64 eq 300000 6.1987 ms/op 6.5508 ms/op 0.95
computeDeltas 1400000 validators 0% inactive 11.573 ms/op 12.187 ms/op 0.95
computeDeltas 1400000 validators 10% inactive 10.953 ms/op 11.618 ms/op 0.94
computeDeltas 1400000 validators 20% inactive 10.269 ms/op 10.978 ms/op 0.94
computeDeltas 1400000 validators 50% inactive 8.4237 ms/op 8.8811 ms/op 0.95
computeDeltas 2100000 validators 0% inactive 17.319 ms/op 18.362 ms/op 0.94
computeDeltas 2100000 validators 10% inactive 16.392 ms/op 17.647 ms/op 0.93
computeDeltas 2100000 validators 20% inactive 15.344 ms/op 16.526 ms/op 0.93
computeDeltas 2100000 validators 50% inactive 10.209 ms/op 11.024 ms/op 0.93
altair processAttestation - 250000 vs - 7PWei normalcase 1.9788 ms/op 1.6719 ms/op 1.18
altair processAttestation - 250000 vs - 7PWei worstcase 2.7199 ms/op 2.4184 ms/op 1.12
altair processAttestation - setStatus - 1/6 committees join 97.462 us/op 103.86 us/op 0.94
altair processAttestation - setStatus - 1/3 committees join 200.85 us/op 195.30 us/op 1.03
altair processAttestation - setStatus - 1/2 committees join 278.84 us/op 283.62 us/op 0.98
altair processAttestation - setStatus - 2/3 committees join 364.64 us/op 364.24 us/op 1.00
altair processAttestation - setStatus - 4/5 committees join 500.24 us/op 504.04 us/op 0.99
altair processAttestation - setStatus - 100% committees join 580.56 us/op 603.02 us/op 0.96
altair processBlock - 250000 vs - 7PWei normalcase 4.4990 ms/op 2.9146 ms/op 1.54
altair processBlock - 250000 vs - 7PWei normalcase hashState 15.994 ms/op 11.875 ms/op 1.35
altair processBlock - 250000 vs - 7PWei worstcase 21.087 ms/op 19.820 ms/op 1.06
altair processBlock - 250000 vs - 7PWei worstcase hashState 39.750 ms/op 38.342 ms/op 1.04
phase0 processBlock - 250000 vs - 7PWei normalcase 1.4044 ms/op 1.2888 ms/op 1.09
phase0 processBlock - 250000 vs - 7PWei worstcase 16.351 ms/op 16.086 ms/op 1.02
altair processEth1Data - 250000 vs - 7PWei normalcase 293.92 us/op 297.18 us/op 0.99
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.0210 us/op 3.1990 us/op 0.94
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 19.349 us/op 20.926 us/op 0.92
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.7470 us/op 6.0180 us/op 0.95
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.5840 us/op 3.7990 us/op 0.94
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 88.913 us/op 93.085 us/op 0.96
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3399 ms/op 1.4107 ms/op 0.95
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.7740 ms/op 1.8769 ms/op 0.95
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7376 ms/op 1.8836 ms/op 0.92
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.5649 ms/op 3.7262 ms/op 0.96
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0150 ms/op 2.0850 ms/op 0.97
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.9406 ms/op 4.0405 ms/op 0.98
Tree 40 250000 create 312.83 ms/op 310.29 ms/op 1.01
Tree 40 250000 get(125000) 88.708 ns/op 95.067 ns/op 0.93
Tree 40 250000 set(125000) 947.08 ns/op 1.0246 us/op 0.92
Tree 40 250000 toArray() 12.866 ms/op 9.0260 ms/op 1.43
Tree 40 250000 iterate all - toArray() + loop 12.286 ms/op 9.2267 ms/op 1.33
Tree 40 250000 iterate all - get(i) 35.667 ms/op 34.305 ms/op 1.04
Array 250000 create 2.2802 ms/op 2.1658 ms/op 1.05
Array 250000 clone - spread 711.31 us/op 671.50 us/op 1.06
Array 250000 get(125000) 0.28100 ns/op 0.29500 ns/op 0.95
Array 250000 set(125000) 0.28400 ns/op 0.29600 ns/op 0.96
Array 250000 iterate all - loop 55.035 us/op 57.806 us/op 0.95
phase0 afterProcessEpoch - 250000 vs - 7PWei 38.041 ms/op 61.007 ms/op 0.62
Array.fill - length 1000000 1.9766 ms/op 2.2202 ms/op 0.89
Array push - length 1000000 10.671 ms/op 8.1796 ms/op 1.30
Array.get 0.19950 ns/op 0.20575 ns/op 0.97
Uint8Array.get 0.24718 ns/op 0.25414 ns/op 0.97
phase0 beforeProcessEpoch - 250000 vs - 7PWei 14.835 ms/op 16.292 ms/op 0.91
altair processEpoch - mainnet_e81889 252.43 ms/op 261.18 ms/op 0.97
mainnet_e81889 - altair beforeProcessEpoch 15.541 ms/op 19.969 ms/op 0.78
mainnet_e81889 - altair processJustificationAndFinalization 6.4450 us/op 5.6180 us/op 1.15
mainnet_e81889 - altair processInactivityUpdates 3.5098 ms/op 3.4682 ms/op 1.01
mainnet_e81889 - altair processRewardsAndPenalties 19.571 ms/op 18.019 ms/op 1.09
mainnet_e81889 - altair processRegistryUpdates 536.00 ns/op 565.00 ns/op 0.95
mainnet_e81889 - altair processSlashings 127.00 ns/op 156.00 ns/op 0.81
mainnet_e81889 - altair processEth1DataReset 125.00 ns/op 146.00 ns/op 0.86
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.3144 ms/op 1.1921 ms/op 1.10
mainnet_e81889 - altair processSlashingsReset 677.00 ns/op 746.00 ns/op 0.91
mainnet_e81889 - altair processRandaoMixesReset 1.2440 us/op 1.0950 us/op 1.14
mainnet_e81889 - altair processHistoricalRootsUpdate 124.00 ns/op 149.00 ns/op 0.83
mainnet_e81889 - altair processParticipationFlagUpdates 420.00 ns/op 432.00 ns/op 0.97
mainnet_e81889 - altair processSyncCommitteeUpdates 101.00 ns/op 104.00 ns/op 0.97
mainnet_e81889 - altair afterProcessEpoch 39.411 ms/op 43.315 ms/op 0.91
capella processEpoch - mainnet_e217614 843.21 ms/op 764.76 ms/op 1.10
mainnet_e217614 - capella beforeProcessEpoch 61.356 ms/op 55.580 ms/op 1.10
mainnet_e217614 - capella processJustificationAndFinalization 6.2220 us/op 5.4760 us/op 1.14
mainnet_e217614 - capella processInactivityUpdates 13.962 ms/op 12.299 ms/op 1.14
mainnet_e217614 - capella processRewardsAndPenalties 90.555 ms/op 91.491 ms/op 0.99
mainnet_e217614 - capella processRegistryUpdates 4.4470 us/op 4.4520 us/op 1.00
mainnet_e217614 - capella processSlashings 133.00 ns/op 147.00 ns/op 0.90
mainnet_e217614 - capella processEth1DataReset 130.00 ns/op 145.00 ns/op 0.90
mainnet_e217614 - capella processEffectiveBalanceUpdates 14.167 ms/op 5.7287 ms/op 2.47
mainnet_e217614 - capella processSlashingsReset 666.00 ns/op 721.00 ns/op 0.92
mainnet_e217614 - capella processRandaoMixesReset 1.4160 us/op 1.2290 us/op 1.15
mainnet_e217614 - capella processHistoricalRootsUpdate 130.00 ns/op 147.00 ns/op 0.88
mainnet_e217614 - capella processParticipationFlagUpdates 430.00 ns/op 434.00 ns/op 0.99
mainnet_e217614 - capella afterProcessEpoch 106.32 ms/op 110.10 ms/op 0.97
phase0 processEpoch - mainnet_e58758 320.52 ms/op 278.06 ms/op 1.15
mainnet_e58758 - phase0 beforeProcessEpoch 70.381 ms/op 54.040 ms/op 1.30
mainnet_e58758 - phase0 processJustificationAndFinalization 6.6790 us/op 5.6140 us/op 1.19
mainnet_e58758 - phase0 processRewardsAndPenalties 16.060 ms/op 15.257 ms/op 1.05
mainnet_e58758 - phase0 processRegistryUpdates 2.2110 us/op 4.4560 us/op 0.50
mainnet_e58758 - phase0 processSlashings 160.00 ns/op 144.00 ns/op 1.11
mainnet_e58758 - phase0 processEth1DataReset 128.00 ns/op 145.00 ns/op 0.88
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 802.95 us/op 826.43 us/op 0.97
mainnet_e58758 - phase0 processSlashingsReset 891.00 ns/op 828.00 ns/op 1.08
mainnet_e58758 - phase0 processRandaoMixesReset 1.3000 us/op 1.0910 us/op 1.19
mainnet_e58758 - phase0 processHistoricalRootsUpdate 139.00 ns/op 146.00 ns/op 0.95
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.2400 us/op 1.0110 us/op 1.23
mainnet_e58758 - phase0 afterProcessEpoch 32.456 ms/op 33.596 ms/op 0.97
phase0 processEffectiveBalanceUpdates - 250000 normalcase 980.75 us/op 1.0119 ms/op 0.97
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.7306 ms/op 1.7887 ms/op 0.97
altair processInactivityUpdates - 250000 normalcase 10.687 ms/op 10.632 ms/op 1.01
altair processInactivityUpdates - 250000 worstcase 10.860 ms/op 11.186 ms/op 0.97
phase0 processRegistryUpdates - 250000 normalcase 2.1200 us/op 2.3270 us/op 0.91
phase0 processRegistryUpdates - 250000 badcase_full_deposits 142.24 us/op 140.89 us/op 1.01
phase0 processRegistryUpdates - 250000 worstcase 0.5 59.229 ms/op 61.334 ms/op 0.97
altair processRewardsAndPenalties - 250000 normalcase 15.480 ms/op 15.776 ms/op 0.98
altair processRewardsAndPenalties - 250000 worstcase 15.368 ms/op 15.059 ms/op 1.02
phase0 getAttestationDeltas - 250000 normalcase 5.3883 ms/op 8.7563 ms/op 0.62
phase0 getAttestationDeltas - 250000 worstcase 5.5190 ms/op 8.6709 ms/op 0.64
phase0 processSlashings - 250000 worstcase 58.244 us/op 63.346 us/op 0.92
altair processSyncCommitteeUpdates - 250000 9.8360 ms/op 10.235 ms/op 0.96
BeaconState.hashTreeRoot - No change 165.00 ns/op 174.00 ns/op 0.95
BeaconState.hashTreeRoot - 1 full validator 70.861 us/op 71.694 us/op 0.99
BeaconState.hashTreeRoot - 32 full validator 817.95 us/op 859.62 us/op 0.95
BeaconState.hashTreeRoot - 512 full validator 6.8783 ms/op 6.1558 ms/op 1.12
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 90.632 us/op 83.298 us/op 1.09
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.3678 ms/op 1.2731 ms/op 1.07
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 14.573 ms/op 14.652 ms/op 0.99
BeaconState.hashTreeRoot - 1 balances 74.066 us/op 63.223 us/op 1.17
BeaconState.hashTreeRoot - 32 balances 684.75 us/op 741.93 us/op 0.92
BeaconState.hashTreeRoot - 512 balances 5.3501 ms/op 4.7887 ms/op 1.12
BeaconState.hashTreeRoot - 250000 balances 176.37 ms/op 113.88 ms/op 1.55
aggregationBits - 2048 els - zipIndexesInBitList 19.331 us/op 20.060 us/op 0.96
regular array get 100000 times 22.454 us/op 23.476 us/op 0.96
wrappedArray get 100000 times 22.491 us/op 23.452 us/op 0.96
arrayWithProxy get 100000 times 10.094 ms/op 10.484 ms/op 0.96
ssz.Root.equals 21.131 ns/op 21.800 ns/op 0.97
byteArrayEquals 20.936 ns/op 21.544 ns/op 0.97
Buffer.compare 8.6290 ns/op 8.9100 ns/op 0.97
processSlot - 1 slots 8.3800 us/op 8.3360 us/op 1.01
processSlot - 32 slots 2.0349 ms/op 1.5354 ms/op 1.33
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 4.6118 ms/op 2.8076 ms/op 1.64
getCommitteeAssignments - req 1 vs - 250000 vc 1.6553 ms/op 1.6868 ms/op 0.98
getCommitteeAssignments - req 100 vs - 250000 vc 3.3866 ms/op 3.4555 ms/op 0.98
getCommitteeAssignments - req 1000 vs - 250000 vc 3.5919 ms/op 3.7030 ms/op 0.97
findModifiedValidators - 10000 modified validators 693.82 ms/op 757.44 ms/op 0.92
findModifiedValidators - 1000 modified validators 576.07 ms/op 520.40 ms/op 1.11
findModifiedValidators - 100 modified validators 333.97 ms/op 306.47 ms/op 1.09
findModifiedValidators - 10 modified validators 281.11 ms/op 258.46 ms/op 1.09
findModifiedValidators - 1 modified validators 235.49 ms/op 192.58 ms/op 1.22
findModifiedValidators - no difference 156.88 ms/op 157.70 ms/op 0.99
migrate state 1500000 validators, 3400 modified, 2000 new 2.9451 s/op 3.2322 s/op 0.91
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.6000 ns/op 3.7600 ns/op 0.96
state getBlockRootAtSlot - 250000 vs - 7PWei 396.34 ns/op 283.09 ns/op 1.40
computeProposerIndex 100000 validators 1.3185 ms/op 1.4434 ms/op 0.91
getNextSyncCommitteeIndices 1000 validators 2.8275 ms/op 2.9166 ms/op 0.97
getNextSyncCommitteeIndices 10000 validators 24.570 ms/op 27.001 ms/op 0.91
getNextSyncCommitteeIndices 100000 validators 85.443 ms/op 89.673 ms/op 0.95
computeProposers - vc 250000 523.57 us/op 557.58 us/op 0.94
computeEpochShuffling - vc 250000 37.227 ms/op 40.495 ms/op 0.92
getNextSyncCommittee - vc 250000 9.2047 ms/op 9.5625 ms/op 0.96
nodejs block root to RootHex using toHex 93.604 ns/op 96.027 ns/op 0.97
nodejs block root to RootHex using toRootHex 59.200 ns/op 63.244 ns/op 0.94
nodejs fromHex(blob) 723.41 us/op 790.43 us/op 0.92
nodejs fromHexInto(blob) 611.47 us/op 635.07 us/op 0.96
nodejs block root to RootHex using the deprecated toHexString 520.58 ns/op 510.43 ns/op 1.02
nodejs byteArrayEquals 32 bytes (block root) 25.459 ns/op 26.455 ns/op 0.96
nodejs byteArrayEquals 48 bytes (pubkey) 36.697 ns/op 38.224 ns/op 0.96
nodejs byteArrayEquals 96 bytes (signature) 33.097 ns/op 35.431 ns/op 0.93
nodejs byteArrayEquals 1024 bytes 38.830 ns/op 45.413 ns/op 0.86
nodejs byteArrayEquals 131072 bytes (blob) 1.7114 us/op 1.7879 us/op 0.96
browser block root to RootHex using toHex 140.15 ns/op 146.84 ns/op 0.95
browser block root to RootHex using toRootHex 126.99 ns/op 132.88 ns/op 0.96
browser fromHex(blob) 1.5004 ms/op 1.6701 ms/op 0.90
browser fromHexInto(blob) 621.10 us/op 632.02 us/op 0.98
browser block root to RootHex using the deprecated toHexString 527.80 ns/op 350.01 ns/op 1.51
browser byteArrayEquals 32 bytes (block root) 27.516 ns/op 28.442 ns/op 0.97
browser byteArrayEquals 48 bytes (pubkey) 38.741 ns/op 40.033 ns/op 0.97
browser byteArrayEquals 96 bytes (signature) 73.711 ns/op 74.679 ns/op 0.99
browser byteArrayEquals 1024 bytes 744.69 ns/op 767.09 ns/op 0.97
browser byteArrayEquals 131072 bytes (blob) 93.489 us/op 96.522 us/op 0.97

by benchmarkbot/action

wemeetagain and others added 5 commits May 21, 2026 10:32
Brings the EIP-7688 (progressive SSZ) branch up to the v1.7.0-alpha.11
spec baseline. Conflict resolutions of note:

- @chainsafe/ssz bumped to ^1.6.0 (progressive types) across workspace;
  dropped unused deps (utils ssz, cli pubkey-index-map, st persistent-ts)
  to match unstable's #9462 cleanup.
- gloas sszTypes: kept branch's progressive types, re-applied unstable's
  alpha.9-11 changes it predated: EIP-8282 builder deposits/exits
  (as ProgressiveList), BuilderPendingPayment.proposerIndex, and
  ExecutionPayloadBid.gasLimit UintBn64 -> UintNum64.
- processParentExecutionPayload: kept #4630 length asserts, extended to
  builder deposits/exits, used unstable's 5-field empty-requests check.
- processOperations: kept assertGloasOperationLimits + unstable's fulu
  zero-deposit rule.
- specTestIterator: kept branch's narrower gloas light-client skips.

Build, check-types, lint, and types/state-transition unit tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
https://discord.com/channels/595666850260713488/1295427781722898505/1520371177036709949
we need couple more progressive containers in gloas.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ensi321

ensi321 commented Jul 4, 2026

Copy link
Copy Markdown
Member

Current code passes all spec tests in ethereum/consensus-specs#4630 . Waiting for alpha.12 to be released before marking the PR ready for review.

**Motivation**

- improve upgradeStateToGloas() by reusing nodes of pre-gloas
BeaconState
- bump `@chainsafe/ssz` version to v1.6.1

**Description**

with mainnet state 14707840

- before
```
[bench] upgradeStateToGloas: 3205.5ms
[bench] gloas hashTreeRoot: 32196.4ms
```

- this PR
```
[bench] upgradeStateToGloas: 1178.3ms
[bench] gloas hashTreeRoot: 4899.3ms
```



**AI Assistance Disclosure**
- created with the help of Claude

---------

Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
Co-authored-by: NC <17676176+ensi321@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ensi321 added a commit that referenced this pull request Jul 7, 2026
Squashed eip7688 implementation from the eip-7688 branch (lodestar #9390)
@ 06b588d: converts Gloas containers to ProgressiveContainer/ProgressiveList
(incl. additional containers #9586 and BlockAccessList -> ProgressiveByteList),
bumps @chainsafe/ssz, updates light-client gindices and gossip size bounds, and
reuses container nodes in upgradeStateToGloas for perf (#9601). Verified against
#4630-generated spec vectors.
ensi321 and others added 4 commits July 6, 2026 21:59
…nsensus-specs #4630)

apply_parent_execution_payload performs no length checks in the spec. With
EIP-7688 the ExecutionRequests lists are progressive (no SSZ max length), so
the Electra-cap assertion (assertExecutionRequestsWithinLimits) is invalid --
requests exceeding the Electra caps are valid. Removes the assertion and its
now-unused imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reverts 0395641. consensus-specs master still asserts the 5 execution
request length limits in apply_parent_execution_payload (beacon-chain.md
L1284-1290, tip a62bc326c) through the #4630 merge and all followups; the
"drop the cap" idea was never adopted (#5420 instead tightened
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD 256->64). Keep parity with spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The value shipped in the merged #4630 (and master, tip a62bc326c) is lower
than the pre-merge PR snapshot this branch used:
- mainnet 4082504 -> 4027336
- minimal 1993180 -> 1938012

(MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD 256->64 and PAYLOAD_DUE_BPS
7500->5000 are handled on nc/alpha.12-constants, not here.)

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

consensus-specs #4630 (gloas p2p-interface) requires beacon_block gossip to
REJECT when parent_execution_requests counts or block body operation counts
exceed their per-block limits. EIP-7688 made these lists progressive (no SSZ
type-level cap), so the bounds are enforced here at the gossip layer (they are
also asserted in the state transition). deposits must be empty (limit 0)
post-Fulu.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ensi321 added a commit that referenced this pull request Jul 7, 2026
Squashed eip7688 implementation from the eip-7688 branch (#9390): progressive
containers/lists for Gloas, @chainsafe/ssz ^1.6.1, light-client gindices,
apply_parent_execution_payload length asserts, MAX_SIGNED_BEACON_BLOCK_SIZE
synced to alpha.12 (4027336/1938012), and block-gossip count REJECTs.

@twoeths twoeths left a comment

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.

right now we have

function activeFields(count: number): boolean[] {
  return Array.from({length: count}, () => true);
}

to mark all active fields active, and we have no way to represent an inactive fields in the future. May want to refactor it to allActiveFields(number), so that in the future we can have a real activeFields(0b1001) or activeFields("0b1001") (if it's too many fields) to represent inactive fields also

Bring EIP-7688 progressive-containers branch current (36 commits behind).
Conflicts resolved:
- beacon-node/package.json: keep quic ^2.1.1 (unstable), ssz ^1.6.1 + persistent-merkle-tree ^1.3.0 (eip-7688, needed for progressive containers)
- topic.test.ts: union of both test suites (gossip SSZ size limits + getAllowedTopics)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Do the alpha.12 bump in eip-7688 branch.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ensi321
ensi321 marked this pull request as ready for review July 16, 2026 16:44
@ensi321
ensi321 requested a review from a team as a code owner July 16, 2026 16:44

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef8b555e4e

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

typeName: "BLSToExecutionChanges",
});

export const Validators = new ProgressiveListCompositeType(phase0Ssz.Validator, {typeName: "Validators"});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rebuild cached lists across the Gloas fork

With Validators now using progressive-list merkleization, a post-Gloas state cannot safely reuse a pre-Gloas list view. loadState() still overwrites the deserialized field with migratedState.validators = seedState.validators.clone(true) (and similarly transfers inactivity scores whenever both forks are Altair+), so loading Gloas state bytes from a Fulu/Electra seed state during restart/regen before finalization crosses the fork keeps old list nodes inside a Gloas state and produces incorrect roots. Please gate those cache transfers on matching fork/list types or migrate them like upgradeStateToGloas.

Useful? React with 👍 / 👎.

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.

Will be addressed in a follow-up PR

);

export const ExecutionPayloadEnvelope = new ContainerType(
export const ExecutionPayloadEnvelope = new ProgressiveContainerType(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound req/resp lengths for progressive envelopes

After this switches the envelope to progressive containers/lists, ssz.gloas.SignedExecutionPayloadEnvelope.maxSize is no longer the preset P2P bound. The gossip path compensates via getGossipSSZMaxSize, but req/resp still passes ssz.gloas.SignedExecutionPayloadEnvelope directly to the SSZ-snappy decoder, which validates the length prefix only against type.maxSize; on ExecutionPayloadEnvelopesByRoot/Range, a peer can therefore advertise an oversized SSZ length and make us read/decompress far beyond the intended limit instead of rejecting it up front. Please add bounded TypeSizes for these progressive req/resp responses too.

Useful? React with 👍 / 👎.

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.

Will be addressed in a follow-up PR

ensi321 and others added 2 commits July 16, 2026 11:42
Root package.json was left at ^1.6.1 when packages/* were bumped to
1.6.2, leaving the lockfile pointing at a dropped 1.6.1 block and
breaking frozen install in CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread packages/state-transition/src/block/processParentExecutionPayload.ts Outdated
**Description**

- more progressive ssz utils to reuse nodes, this improves:
  - gloas fork transition to migrate basic list
  - progressParticipationFlagUpdates, which happens at epoch transition
- also do not check deposit length as found in
#9390 (comment)

**AI Assistance Disclosure**

- created with the help of Claude

---------

Co-authored-by: Tuyen Nguyen <twoeths@users.noreply.github.com>
twoeths
twoeths previously approved these changes Jul 17, 2026

@ensi321 ensi321 left a comment

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.

Will have to do a follow up PR to address codex's comments

@ensi321
ensi321 merged commit 17a4805 into unstable Jul 21, 2026
19 checks passed
@ensi321
ensi321 deleted the eip-7688 branch July 21, 2026 05:08
ensi321 added a commit that referenced this pull request Jul 24, 2026
Depends on #9390

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Nico Flaig <nflaig@protonmail.com>
wemeetagain pushed a commit that referenced this pull request Aug 4, 2026
Follow up on unaddressed comments from #9390

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@wemeetagain

Copy link
Copy Markdown
Member Author

🎉 This PR is included in v1.46.0 🎉

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