Skip to content

feat: add getStateBuilders endpoint - #9593

Merged
wemeetagain merged 4 commits into
unstablefrom
nflaig/state-builders-api
Jul 7, 2026
Merged

feat: add getStateBuilders endpoint#9593
wemeetagain merged 4 commits into
unstablefrom
nflaig/state-builders-api

Conversation

@nflaig

@nflaig nflaig commented Jul 5, 2026

Copy link
Copy Markdown
Member

Motivation

Implement POST /eth/v1/beacon/states/{state_id}/builders added to the beacon-api spec in ethereum/beacon-APIs#614.

Description

  • add getStateBuilders route, filterable by builder ids (hex encoded public key or builder index) and statuses (pending, active, exited)
  • add getBuildersLength() to the beacon state view to enumerate the builder registry
  • returns 400 if the requested state is prior to gloas, ids that do not match a known builder are skipped without error as per spec
  • builder pubkey lookups are a linear scan over the registry, can consider a builder pubkey cache if this becomes a performance issue

@nflaig
nflaig requested a review from a team as a code owner July 5, 2026 09:33

@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: e923627cb8

ℹ️ 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/api/impl/beacon/state/utils.ts Outdated
Comment thread packages/beacon-node/src/api/impl/beacon/state/index.ts

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the getStateBuilders endpoint (POST /eth/v1/beacon/states/{state_id}/builders) to retrieve and filter builders from a Gloas state by ID and status. It includes updates to state views, types, helper functions, and unit tests. The review feedback points out a potential out-of-bounds issue where negative builder indices are not rejected as invalid, and suggests moving the uniqueness validation for statuses to the beginning of the handler to prevent it from being bypassed when builderIds are provided.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/beacon-node/src/api/impl/beacon/state/utils.ts Outdated
Comment thread packages/beacon-node/src/api/impl/beacon/state/index.ts
Comment thread packages/beacon-node/src/api/impl/beacon/state/index.ts
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Performance Report

🚀🚀 Significant benchmark improvement detected

Benchmark suite Current: 4103339 Previous: d173b63 Ratio
Array.fill - length 1000000 2.2372 ms/op 18.841 ms/op 0.12
Full benchmark results
Benchmark suite Current: 4103339 Previous: d173b63 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.4041 ms/op 842.78 us/op 1.67
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 40.285 us/op 42.234 us/op 0.95
BLS verify - blst 716.18 us/op 704.37 us/op 1.02
BLS verifyMultipleSignatures 3 - blst 1.3901 ms/op 1.3534 ms/op 1.03
BLS verifyMultipleSignatures 8 - blst 2.2004 ms/op 2.1534 ms/op 1.02
BLS verifyMultipleSignatures 32 - blst 6.9745 ms/op 6.8126 ms/op 1.02
BLS verifyMultipleSignatures 64 - blst 13.975 ms/op 13.033 ms/op 1.07
BLS verifyMultipleSignatures 128 - blst 26.565 ms/op 25.934 ms/op 1.02
BLS deserializing 10000 signatures 636.41 ms/op 616.57 ms/op 1.03
BLS deserializing 100000 signatures 6.3609 s/op 6.2730 s/op 1.01
BLS verifyMultipleSignatures - same message - 3 - blst 806.91 us/op 760.07 us/op 1.06
BLS verifyMultipleSignatures - same message - 8 - blst 940.66 us/op 941.07 us/op 1.00
BLS verifyMultipleSignatures - same message - 32 - blst 1.5221 ms/op 1.5751 ms/op 0.97
BLS verifyMultipleSignatures - same message - 64 - blst 2.3371 ms/op 2.4513 ms/op 0.95
BLS verifyMultipleSignatures - same message - 128 - blst 3.9406 ms/op 3.9966 ms/op 0.99
BLS aggregatePubkeys 32 - blst 17.317 us/op 17.145 us/op 1.01
BLS aggregatePubkeys 128 - blst 60.489 us/op 61.028 us/op 0.99
getSlashingsAndExits - default max 96.169 us/op 46.760 us/op 2.06
getSlashingsAndExits - 2k 483.79 us/op 338.31 us/op 1.43
proposeBlockBody type=full, size=empty 707.95 us/op 698.29 us/op 1.01
isKnown best case - 1 super set check 161.00 ns/op 163.00 ns/op 0.99
isKnown normal case - 2 super set checks 167.00 ns/op 166.00 ns/op 1.01
isKnown worse case - 16 super set checks 166.00 ns/op 164.00 ns/op 1.01
validate api signedAggregateAndProof - struct 1.5486 ms/op 1.5272 ms/op 1.01
validate gossip signedAggregateAndProof - struct 1.5230 ms/op 1.5180 ms/op 1.00
batch validate gossip attestation - vc 640000 - chunk 32 110.71 us/op 105.87 us/op 1.05
batch validate gossip attestation - vc 640000 - chunk 64 100.85 us/op 91.874 us/op 1.10
batch validate gossip attestation - vc 640000 - chunk 128 92.185 us/op 86.173 us/op 1.07
batch validate gossip attestation - vc 640000 - chunk 256 94.598 us/op 83.585 us/op 1.13
bytes32 toHexString 292.00 ns/op 274.00 ns/op 1.07
bytes32 Buffer.toString(hex) 169.00 ns/op 164.00 ns/op 1.03
bytes32 Buffer.toString(hex) from Uint8Array 246.00 ns/op 233.00 ns/op 1.06
bytes32 Buffer.toString(hex) + 0x 170.00 ns/op 158.00 ns/op 1.08
Return object 10000 times 0.20640 ns/op 0.20690 ns/op 1.00
Throw Error 10000 times 3.2772 us/op 3.3655 us/op 0.97
toHex 94.405 ns/op 104.83 ns/op 0.90
Buffer.from 90.098 ns/op 87.162 ns/op 1.03
shared Buffer 59.086 ns/op 57.549 ns/op 1.03
fastMsgIdFn sha256 / 200 bytes 1.4630 us/op 1.4400 us/op 1.02
fastMsgIdFn h32 xxhash / 200 bytes 151.00 ns/op 159.00 ns/op 0.95
fastMsgIdFn h64 xxhash / 200 bytes 220.00 ns/op 210.00 ns/op 1.05
fastMsgIdFn sha256 / 1000 bytes 4.6290 us/op 4.7970 us/op 0.96
fastMsgIdFn h32 xxhash / 1000 bytes 237.00 ns/op 248.00 ns/op 0.96
fastMsgIdFn h64 xxhash / 1000 bytes 247.00 ns/op 261.00 ns/op 0.95
fastMsgIdFn sha256 / 10000 bytes 40.321 us/op 42.650 us/op 0.95
fastMsgIdFn h32 xxhash / 10000 bytes 1.2310 us/op 1.2790 us/op 0.96
fastMsgIdFn h64 xxhash / 10000 bytes 800.00 ns/op 820.00 ns/op 0.98
send data - 1000 256B messages 4.5228 ms/op 4.9867 ms/op 0.91
send data - 1000 512B messages 5.4045 ms/op 5.8916 ms/op 0.92
send data - 1000 1024B messages 6.1206 ms/op 5.9202 ms/op 1.03
send data - 1000 1200B messages 6.6743 ms/op 6.0667 ms/op 1.10
send data - 1000 2048B messages 10.783 ms/op 9.6987 ms/op 1.11
send data - 1000 4096B messages 57.232 ms/op 43.997 ms/op 1.30
send data - 1000 16384B messages 307.81 ms/op 333.02 ms/op 0.92
send data - 1000 65536B messages 1.8579 s/op 1.7583 s/op 1.06
enrSubnets - fastDeserialize 64 bits 820.00 ns/op 763.00 ns/op 1.07
enrSubnets - ssz BitVector 64 bits 282.00 ns/op 250.00 ns/op 1.13
enrSubnets - fastDeserialize 4 bits 106.00 ns/op 101.00 ns/op 1.05
enrSubnets - ssz BitVector 4 bits 278.00 ns/op 262.00 ns/op 1.06
prioritizePeers score -10:0 att 32-0.1 sync 2-0 216.38 us/op 207.62 us/op 1.04
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 259.84 us/op 239.00 us/op 1.09
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 379.13 us/op 352.48 us/op 1.08
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 638.50 us/op 607.30 us/op 1.05
prioritizePeers score 0:0 att 64-1 sync 4-1 734.14 us/op 709.60 us/op 1.03
array of 16000 items push then shift 1.3493 us/op 1.3167 us/op 1.02
LinkedList of 16000 items push then shift 7.8780 ns/op 7.5560 ns/op 1.04
array of 16000 items push then pop 74.016 ns/op 71.638 ns/op 1.03
LinkedList of 16000 items push then pop 6.2410 ns/op 6.0360 ns/op 1.03
array of 24000 items push then shift 1.9776 us/op 1.9258 us/op 1.03
LinkedList of 24000 items push then shift 7.5540 ns/op 6.6810 ns/op 1.13
array of 24000 items push then pop 105.42 ns/op 96.774 ns/op 1.09
LinkedList of 24000 items push then pop 6.3780 ns/op 5.9510 ns/op 1.07
intersect bitArray bitLen 8 4.9340 ns/op 4.7330 ns/op 1.04
intersect array and set length 8 30.898 ns/op 31.022 ns/op 1.00
intersect bitArray bitLen 128 24.926 ns/op 23.918 ns/op 1.04
intersect array and set length 128 519.37 ns/op 497.13 ns/op 1.04
bitArray.getTrueBitIndexes() bitLen 128 1.1250 us/op 963.00 ns/op 1.17
bitArray.getTrueBitIndexes() bitLen 248 1.8680 us/op 1.6770 us/op 1.11
bitArray.getTrueBitIndexes() bitLen 512 3.7750 us/op 3.4100 us/op 1.11
Full columns - reconstruct all 6 blobs 129.55 us/op 115.55 us/op 1.12
Full columns - reconstruct half of the blobs out of 6 77.611 us/op 66.606 us/op 1.17
Full columns - reconstruct single blob out of 6 36.965 us/op 31.129 us/op 1.19
Half columns - reconstruct all 6 blobs 406.23 ms/op 386.41 ms/op 1.05
Half columns - reconstruct half of the blobs out of 6 204.07 ms/op 194.12 ms/op 1.05
Half columns - reconstruct single blob out of 6 73.355 ms/op 69.564 ms/op 1.05
Set add up to 64 items then delete first 2.1992 us/op 2.1245 us/op 1.04
OrderedSet add up to 64 items then delete first 3.4922 us/op 3.3970 us/op 1.03
Set add up to 64 items then delete last 2.4265 us/op 2.3787 us/op 1.02
OrderedSet add up to 64 items then delete last 3.4229 us/op 3.3005 us/op 1.04
Set add up to 64 items then delete middle 2.1316 us/op 2.1663 us/op 0.98
OrderedSet add up to 64 items then delete middle 4.9903 us/op 4.7891 us/op 1.04
Set add up to 128 items then delete first 4.5900 us/op 4.2788 us/op 1.07
OrderedSet add up to 128 items then delete first 7.3010 us/op 6.5606 us/op 1.11
Set add up to 128 items then delete last 4.1918 us/op 3.8885 us/op 1.08
OrderedSet add up to 128 items then delete last 6.4422 us/op 5.8085 us/op 1.11
Set add up to 128 items then delete middle 4.0401 us/op 3.9033 us/op 1.04
OrderedSet add up to 128 items then delete middle 12.417 us/op 11.659 us/op 1.07
Set add up to 256 items then delete first 8.1998 us/op 7.9714 us/op 1.03
OrderedSet add up to 256 items then delete first 12.643 us/op 12.160 us/op 1.04
Set add up to 256 items then delete last 7.9634 us/op 7.7149 us/op 1.03
OrderedSet add up to 256 items then delete last 11.992 us/op 11.528 us/op 1.04
Set add up to 256 items then delete middle 7.8820 us/op 7.7102 us/op 1.02
OrderedSet add up to 256 items then delete middle 37.477 us/op 34.763 us/op 1.08
runFastConfirmationRules vc:100000 bc:96 eq:0 4.1160 us/op 3.5790 us/op 1.15
runFastConfirmationRules vc:600000 bc:96 eq:0 3.9790 us/op 3.8180 us/op 1.04
runFastConfirmationRules vc:1000000 bc:96 eq:0 3.9960 us/op 3.9570 us/op 1.01
runFastConfirmationRules vc:600000 bc:320 eq:0 9.4270 us/op 8.1990 us/op 1.15
runFastConfirmationRules vc:600000 bc:1200 eq:0 35.357 us/op 39.538 us/op 0.89
runFastConfirmationRules vc:600000 bc:96 eq:1000 4.5970 us/op 3.4590 us/op 1.33
runFastConfirmationRules vc:600000 bc:96 eq:10000 4.2140 us/op 3.3060 us/op 1.27
runFastConfirmationRules vc:600000 bc:96 eq:300000 3.8630 us/op 3.3280 us/op 1.16
pass gossip attestations to forkchoice per slot 2.6610 ms/op 2.5548 ms/op 1.04
forkChoice updateHead vc 100000 bc 64 eq 0 411.08 us/op 502.71 us/op 0.82
forkChoice updateHead vc 600000 bc 64 eq 0 2.4381 ms/op 2.7130 ms/op 0.90
forkChoice updateHead vc 1000000 bc 64 eq 0 4.0669 ms/op 4.6153 ms/op 0.88
forkChoice updateHead vc 600000 bc 320 eq 0 2.4531 ms/op 2.7333 ms/op 0.90
forkChoice updateHead vc 600000 bc 1200 eq 0 2.4568 ms/op 2.7573 ms/op 0.89
forkChoice updateHead vc 600000 bc 7200 eq 0 2.9267 ms/op 3.3279 ms/op 0.88
forkChoice updateHead vc 600000 bc 64 eq 1000 2.5520 ms/op 2.8202 ms/op 0.90
forkChoice updateHead vc 600000 bc 64 eq 10000 2.6508 ms/op 2.9268 ms/op 0.91
forkChoice updateHead vc 600000 bc 64 eq 300000 7.3057 ms/op 7.1786 ms/op 1.02
computeDeltas 1400000 validators 0% inactive 13.072 ms/op 13.565 ms/op 0.96
computeDeltas 1400000 validators 10% inactive 12.163 ms/op 13.028 ms/op 0.93
computeDeltas 1400000 validators 20% inactive 10.999 ms/op 11.775 ms/op 0.93
computeDeltas 1400000 validators 50% inactive 8.5798 ms/op 8.8012 ms/op 0.97
computeDeltas 2100000 validators 0% inactive 19.476 ms/op 20.498 ms/op 0.95
computeDeltas 2100000 validators 10% inactive 18.236 ms/op 19.709 ms/op 0.93
computeDeltas 2100000 validators 20% inactive 16.472 ms/op 18.063 ms/op 0.91
computeDeltas 2100000 validators 50% inactive 12.787 ms/op 13.229 ms/op 0.97
altair processAttestation - 250000 vs - 7PWei normalcase 1.9408 ms/op 1.6865 ms/op 1.15
altair processAttestation - 250000 vs - 7PWei worstcase 3.6145 ms/op 2.4316 ms/op 1.49
altair processAttestation - setStatus - 1/6 committees join 114.84 us/op 107.20 us/op 1.07
altair processAttestation - setStatus - 1/3 committees join 197.35 us/op 191.41 us/op 1.03
altair processAttestation - setStatus - 1/2 committees join 289.21 us/op 271.16 us/op 1.07
altair processAttestation - setStatus - 2/3 committees join 379.13 us/op 357.72 us/op 1.06
altair processAttestation - setStatus - 4/5 committees join 529.10 us/op 487.84 us/op 1.08
altair processAttestation - setStatus - 100% committees join 629.88 us/op 579.59 us/op 1.09
altair processBlock - 250000 vs - 7PWei normalcase 3.8823 ms/op 3.9822 ms/op 0.97
altair processBlock - 250000 vs - 7PWei normalcase hashState 14.117 ms/op 13.077 ms/op 1.08
altair processBlock - 250000 vs - 7PWei worstcase 20.487 ms/op 21.669 ms/op 0.95
altair processBlock - 250000 vs - 7PWei worstcase hashState 44.043 ms/op 39.049 ms/op 1.13
phase0 processBlock - 250000 vs - 7PWei normalcase 1.3776 ms/op 1.4756 ms/op 0.93
phase0 processBlock - 250000 vs - 7PWei worstcase 17.966 ms/op 16.972 ms/op 1.06
altair processEth1Data - 250000 vs - 7PWei normalcase 308.56 us/op 272.32 us/op 1.13
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.2440 us/op 3.3480 us/op 0.97
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 21.101 us/op 20.927 us/op 1.01
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 11.036 us/op 5.9320 us/op 1.86
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.7260 us/op 3.6360 us/op 1.02
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 93.741 us/op 88.055 us/op 1.06
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.4369 ms/op 1.3220 ms/op 1.09
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.9586 ms/op 1.8244 ms/op 1.07
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.9246 ms/op 1.7280 ms/op 1.11
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.9412 ms/op 3.4374 ms/op 1.15
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.1467 ms/op 1.9466 ms/op 1.10
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.1228 ms/op 3.9038 ms/op 1.06
Tree 40 250000 create 367.89 ms/op 345.63 ms/op 1.06
Tree 40 250000 get(125000) 92.663 ns/op 99.347 ns/op 0.93
Tree 40 250000 set(125000) 1.0369 us/op 1.0390 us/op 1.00
Tree 40 250000 toArray() 18.149 ms/op 9.8113 ms/op 1.85
Tree 40 250000 iterate all - toArray() + loop 17.797 ms/op 10.380 ms/op 1.71
Tree 40 250000 iterate all - get(i) 41.237 ms/op 41.559 ms/op 0.99
Array 250000 create 2.3001 ms/op 2.1784 ms/op 1.06
Array 250000 clone - spread 725.87 us/op 687.12 us/op 1.06
Array 250000 get(125000) 0.29300 ns/op 0.29300 ns/op 1.00
Array 250000 set(125000) 0.29400 ns/op 0.29500 ns/op 1.00
Array 250000 iterate all - loop 57.514 us/op 56.945 us/op 1.01
phase0 afterProcessEpoch - 250000 vs - 7PWei 67.342 ms/op 39.332 ms/op 1.71
Array.fill - length 1000000 2.2372 ms/op 18.841 ms/op 0.12
Array push - length 1000000 9.6502 ms/op 7.3394 ms/op 1.31
Array.get 0.21627 ns/op 0.20446 ns/op 1.06
Uint8Array.get 0.23781 ns/op 0.22928 ns/op 1.04
phase0 beforeProcessEpoch - 250000 vs - 7PWei 13.941 ms/op 17.784 ms/op 0.78
altair processEpoch - mainnet_e81889 382.30 ms/op 332.21 ms/op 1.15
mainnet_e81889 - altair beforeProcessEpoch 38.859 ms/op 20.315 ms/op 1.91
mainnet_e81889 - altair processJustificationAndFinalization 7.0100 us/op 6.3370 us/op 1.11
mainnet_e81889 - altair processInactivityUpdates 3.7036 ms/op 3.3129 ms/op 1.12
mainnet_e81889 - altair processRewardsAndPenalties 18.648 ms/op 20.157 ms/op 0.93
mainnet_e81889 - altair processRegistryUpdates 554.00 ns/op 542.00 ns/op 1.02
mainnet_e81889 - altair processSlashings 132.00 ns/op 141.00 ns/op 0.94
mainnet_e81889 - altair processEth1DataReset 129.00 ns/op 135.00 ns/op 0.96
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.6639 ms/op 4.6304 ms/op 0.36
mainnet_e81889 - altair processSlashingsReset 724.00 ns/op 690.00 ns/op 1.05
mainnet_e81889 - altair processRandaoMixesReset 1.6220 us/op 1.3610 us/op 1.19
mainnet_e81889 - altair processHistoricalRootsUpdate 131.00 ns/op 133.00 ns/op 0.98
mainnet_e81889 - altair processParticipationFlagUpdates 471.00 ns/op 412.00 ns/op 1.14
mainnet_e81889 - altair processSyncCommitteeUpdates 102.00 ns/op 111.00 ns/op 0.92
mainnet_e81889 - altair afterProcessEpoch 41.547 ms/op 41.473 ms/op 1.00
capella processEpoch - mainnet_e217614 1.0276 s/op 955.78 ms/op 1.08
mainnet_e217614 - capella beforeProcessEpoch 66.147 ms/op 55.986 ms/op 1.18
mainnet_e217614 - capella processJustificationAndFinalization 7.7090 us/op 7.1820 us/op 1.07
mainnet_e217614 - capella processInactivityUpdates 11.768 ms/op 12.456 ms/op 0.94
mainnet_e217614 - capella processRewardsAndPenalties 95.783 ms/op 92.416 ms/op 1.04
mainnet_e217614 - capella processRegistryUpdates 4.4340 us/op 4.3930 us/op 1.01
mainnet_e217614 - capella processSlashings 133.00 ns/op 129.00 ns/op 1.03
mainnet_e217614 - capella processEth1DataReset 125.00 ns/op 127.00 ns/op 0.98
mainnet_e217614 - capella processEffectiveBalanceUpdates 6.3470 ms/op 16.029 ms/op 0.40
mainnet_e217614 - capella processSlashingsReset 674.00 ns/op 675.00 ns/op 1.00
mainnet_e217614 - capella processRandaoMixesReset 1.4350 us/op 1.3350 us/op 1.07
mainnet_e217614 - capella processHistoricalRootsUpdate 127.00 ns/op 125.00 ns/op 1.02
mainnet_e217614 - capella processParticipationFlagUpdates 436.00 ns/op 403.00 ns/op 1.08
mainnet_e217614 - capella afterProcessEpoch 109.33 ms/op 106.97 ms/op 1.02
phase0 processEpoch - mainnet_e58758 378.91 ms/op 378.97 ms/op 1.00
mainnet_e58758 - phase0 beforeProcessEpoch 74.431 ms/op 64.396 ms/op 1.16
mainnet_e58758 - phase0 processJustificationAndFinalization 7.0460 us/op 6.3620 us/op 1.11
mainnet_e58758 - phase0 processRewardsAndPenalties 16.177 ms/op 15.521 ms/op 1.04
mainnet_e58758 - phase0 processRegistryUpdates 2.2760 us/op 2.2570 us/op 1.01
mainnet_e58758 - phase0 processSlashings 125.00 ns/op 223.00 ns/op 0.56
mainnet_e58758 - phase0 processEth1DataReset 125.00 ns/op 131.00 ns/op 0.95
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 2.0059 ms/op 804.17 us/op 2.49
mainnet_e58758 - phase0 processSlashingsReset 896.00 ns/op 948.00 ns/op 0.95
mainnet_e58758 - phase0 processRandaoMixesReset 1.4780 us/op 1.4350 us/op 1.03
mainnet_e58758 - phase0 processHistoricalRootsUpdate 133.00 ns/op 130.00 ns/op 1.02
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.2910 us/op 1.2370 us/op 1.04
mainnet_e58758 - phase0 afterProcessEpoch 32.610 ms/op 33.693 ms/op 0.97
phase0 processEffectiveBalanceUpdates - 250000 normalcase 967.57 us/op 1.0067 ms/op 0.96
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 2.8784 ms/op 1.6447 ms/op 1.75
altair processInactivityUpdates - 250000 normalcase 11.705 ms/op 10.665 ms/op 1.10
altair processInactivityUpdates - 250000 worstcase 12.185 ms/op 10.564 ms/op 1.15
phase0 processRegistryUpdates - 250000 normalcase 2.0300 us/op 2.3400 us/op 0.87
phase0 processRegistryUpdates - 250000 badcase_full_deposits 141.56 us/op 151.70 us/op 0.93
phase0 processRegistryUpdates - 250000 worstcase 0.5 57.421 ms/op 64.510 ms/op 0.89
altair processRewardsAndPenalties - 250000 normalcase 13.931 ms/op 16.630 ms/op 0.84
altair processRewardsAndPenalties - 250000 worstcase 14.021 ms/op 15.563 ms/op 0.90
phase0 getAttestationDeltas - 250000 normalcase 5.5195 ms/op 5.2269 ms/op 1.06
phase0 getAttestationDeltas - 250000 worstcase 5.6018 ms/op 5.2662 ms/op 1.06
phase0 processSlashings - 250000 worstcase 60.295 us/op 59.155 us/op 1.02
altair processSyncCommitteeUpdates - 250000 10.189 ms/op 10.236 ms/op 1.00
BeaconState.hashTreeRoot - No change 168.00 ns/op 178.00 ns/op 0.94
BeaconState.hashTreeRoot - 1 full validator 73.419 us/op 78.180 us/op 0.94
BeaconState.hashTreeRoot - 32 full validator 950.84 us/op 994.38 us/op 0.96
BeaconState.hashTreeRoot - 512 full validator 7.8768 ms/op 7.9567 ms/op 0.99
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 111.14 us/op 95.414 us/op 1.16
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.9066 ms/op 1.7720 ms/op 1.08
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 18.145 ms/op 18.460 ms/op 0.98
BeaconState.hashTreeRoot - 1 balances 91.593 us/op 89.513 us/op 1.02
BeaconState.hashTreeRoot - 32 balances 857.10 us/op 975.44 us/op 0.88
BeaconState.hashTreeRoot - 512 balances 5.5398 ms/op 5.8378 ms/op 0.95
BeaconState.hashTreeRoot - 250000 balances 196.58 ms/op 193.89 ms/op 1.01
aggregationBits - 2048 els - zipIndexesInBitList 19.296 us/op 19.339 us/op 1.00
regular array get 100000 times 22.100 us/op 22.552 us/op 0.98
wrappedArray get 100000 times 22.148 us/op 22.377 us/op 0.99
arrayWithProxy get 100000 times 9.5897 ms/op 9.7239 ms/op 0.99
ssz.Root.equals 20.722 ns/op 20.830 ns/op 0.99
byteArrayEquals 20.606 ns/op 20.756 ns/op 0.99
Buffer.compare 8.6170 ns/op 8.7430 ns/op 0.99
processSlot - 1 slots 9.0210 us/op 9.9390 us/op 0.91
processSlot - 32 slots 2.2346 ms/op 2.4195 ms/op 0.92
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 5.0567 ms/op 4.7980 ms/op 1.05
getCommitteeAssignments - req 1 vs - 250000 vc 1.7213 ms/op 1.6533 ms/op 1.04
getCommitteeAssignments - req 100 vs - 250000 vc 3.5487 ms/op 3.4161 ms/op 1.04
getCommitteeAssignments - req 1000 vs - 250000 vc 3.8173 ms/op 3.6643 ms/op 1.04
findModifiedValidators - 10000 modified validators 969.17 ms/op 709.76 ms/op 1.37
findModifiedValidators - 1000 modified validators 551.43 ms/op 476.32 ms/op 1.16
findModifiedValidators - 100 modified validators 307.14 ms/op 360.95 ms/op 0.85
findModifiedValidators - 10 modified validators 175.83 ms/op 215.66 ms/op 0.82
findModifiedValidators - 1 modified validators 179.00 ms/op 325.02 ms/op 0.55
findModifiedValidators - no difference 188.10 ms/op 198.96 ms/op 0.95
migrate state 1500000 validators, 3400 modified, 2000 new 3.9724 s/op 4.2370 s/op 0.94
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.6500 ns/op 3.6500 ns/op 1.00
state getBlockRootAtSlot - 250000 vs - 7PWei 472.26 ns/op 488.42 ns/op 0.97
computeProposerIndex 100000 validators 1.3578 ms/op 1.3810 ms/op 0.98
getNextSyncCommitteeIndices 1000 validators 2.8584 ms/op 2.8584 ms/op 1.00
getNextSyncCommitteeIndices 10000 validators 25.020 ms/op 25.332 ms/op 0.99
getNextSyncCommitteeIndices 100000 validators 87.853 ms/op 90.810 ms/op 0.97
computeProposers - vc 250000 539.27 us/op 550.79 us/op 0.98
computeEpochShuffling - vc 250000 38.987 ms/op 40.108 ms/op 0.97
getNextSyncCommittee - vc 250000 10.678 ms/op 10.822 ms/op 0.99
nodejs block root to RootHex using toHex 94.492 ns/op 99.514 ns/op 0.95
nodejs block root to RootHex using toRootHex 61.894 ns/op 65.069 ns/op 0.95
nodejs fromHex(blob) 969.94 us/op 996.41 us/op 0.97
nodejs fromHexInto(blob) 643.21 us/op 624.97 us/op 1.03
nodejs block root to RootHex using the deprecated toHexString 561.01 ns/op 349.54 ns/op 1.60
nodejs byteArrayEquals 32 bytes (block root) 26.649 ns/op 25.551 ns/op 1.04
nodejs byteArrayEquals 48 bytes (pubkey) 38.459 ns/op 36.926 ns/op 1.04
nodejs byteArrayEquals 96 bytes (signature) 35.569 ns/op 33.223 ns/op 1.07
nodejs byteArrayEquals 1024 bytes 42.704 ns/op 40.785 ns/op 1.05
nodejs byteArrayEquals 131072 bytes (blob) 1.7637 us/op 1.7528 us/op 1.01
browser block root to RootHex using toHex 146.72 ns/op 142.53 ns/op 1.03
browser block root to RootHex using toRootHex 133.56 ns/op 128.84 ns/op 1.04
browser fromHex(blob) 1.6814 ms/op 1.8059 ms/op 0.93
browser fromHexInto(blob) 641.53 us/op 625.91 us/op 1.02
browser block root to RootHex using the deprecated toHexString 368.55 ns/op 467.23 ns/op 0.79
browser byteArrayEquals 32 bytes (block root) 28.733 ns/op 28.059 ns/op 1.02
browser byteArrayEquals 48 bytes (pubkey) 40.426 ns/op 39.356 ns/op 1.03
browser byteArrayEquals 96 bytes (signature) 75.459 ns/op 73.923 ns/op 1.02
browser byteArrayEquals 1024 bytes 769.80 ns/op 759.36 ns/op 1.01
browser byteArrayEquals 131072 bytes (blob) 96.376 us/op 95.050 us/op 1.01

by benchmarkbot/action

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@lodekeeper please review/approve if it looks good

@lodekeeper lodekeeper 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.

LGTM — reviewed the full diff. Clean new endpoint that mirrors getStateValidators end-to-end:

  • getStateBuilders follows the validators pattern exactly: pre-Gloas → 400, ids-path + full-scan path, assertUniqueItems on both ids and statuses, status filtering.
  • getStateBuilderIndex mirrors getStateValidatorIndex and guards the edges correctly — < 0 / non-safe-integer → 400, >= getBuildersLength() → 404 (future state), pre-Gloas throws. Linear pubkey scan is reasonable given there's no builder pubkey cache and the registry is small.
  • Good catch fixing the same negative-index gap in getStateValidatorIndex (d7c793a5d7) and adding the regression tests.
  • getBuilderStatus (exited → active → pending) reads clean and matches beacon-APIs #614.
  • getBuildersLength added to both state views with pre-Gloas guards, memoized on the native view.

Bot threads all resolved. 👍

lodekeeper

This comment was marked as duplicate.

Comment thread packages/api/src/beacon/routes/beacon/state.ts
Comment thread packages/api/src/beacon/routes/beacon/state.ts Outdated
Addresses review feedback on #9593 by exporting a dedicated BuilderId
route type and using it for builder state lookups instead of
ValidatorId.\n\nVerification:\n- pnpm lint\n- pnpm build\n- pnpm
check-types

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
Addresses review feedback on #9593 by adding explicit builder ID serdes
aliases while preserving existing validator helper names for validator
call sites.

Changes:
- Add `toBuilderIdsStr` / `fromBuilderIdsStr` aliases in API serdes
- Use the builder aliases for `getStateBuilders` request
serialization/parsing

Verification:
- `pnpm lint`
- `pnpm build`
- `pnpm check-types`

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
| {valid: true; builderIndex: BuilderIndex}
| {valid: false; code: number; reason: string};

export function getStateBuilderIndex(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this could also be made reusable between validators/builders but I don't like to be overly DRY for the sake of it, and it would definitely become less readable, we also don't wanna couple the code too much as there might be a drift in the future between builders and validators

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.

Agreed. I would keep the builder and validator paths separate here for readability and to avoid coupling them before we know whether the APIs drift. No code change from me on this thread.

return (this.cachedState as CachedBeaconStateGloas).builders.getReadonly(index);
}

getBuildersLength(): number {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we might need a new binding for that cc @spiral-ladder

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.

Good point. This PR already adds the TypeScript state-view surface and the native wrapper call for getBuildersLength, and the current native portability check is passing on this head. If the underlying native binding implementation needs an explicit addition, I would leave that to the native binding follow-up/owner rather than adding more JS-side churn here.

@nflaig nflaig left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

LGTM, did a final self-review

@wemeetagain wemeetagain 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.

LGTM

@wemeetagain
wemeetagain merged commit bdb9aa1 into unstable Jul 7, 2026
23 of 25 checks passed
@wemeetagain
wemeetagain deleted the nflaig/state-builders-api branch July 7, 2026 13:47
wemeetagain pushed a commit to ChainSafe/lodestar-z that referenced this pull request Jul 7, 2026
## Description

Introduces `state.getBuildersLength()` binding.
Function placement reflects the one present in
`nativeBeaconStateView.ts` (ChainSafe/lodestar#9593).

Closes #470 

Used Claude to audit changes.
@wemeetagain

Copy link
Copy Markdown
Member

🎉 This PR is included in v1.45.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.

4 participants