Skip to content

fix: validate cached validator indices against state - #9748

Merged
nflaig merged 1 commit into
unstablefrom
nflaig/validate-cached-validator-indices
Aug 3, 2026
Merged

fix: validate cached validator indices against state#9748
nflaig merged 1 commit into
unstablefrom
nflaig/validate-cached-validator-indices

Conversation

@nflaig

@nflaig nflaig commented Aug 2, 2026

Copy link
Copy Markdown
Member

No description provided.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: b27a05e Previous: b3cb0f6 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 906.58 us/op 1.0484 ms/op 0.86
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 37.390 us/op 40.844 us/op 0.92
BLS verify - blst 716.41 us/op 662.34 us/op 1.08
BLS verifyMultipleSignatures 3 - blst 1.3515 ms/op 1.3852 ms/op 0.98
BLS verifyMultipleSignatures 8 - blst 2.1450 ms/op 2.2027 ms/op 0.97
BLS verifyMultipleSignatures 32 - blst 6.8005 ms/op 6.9396 ms/op 0.98
BLS verifyMultipleSignatures 64 - blst 13.369 ms/op 13.781 ms/op 0.97
BLS verifyMultipleSignatures 128 - blst 25.995 ms/op 26.020 ms/op 1.00
BLS deserializing 10000 signatures 614.95 ms/op 642.55 ms/op 0.96
BLS deserializing 100000 signatures 6.0977 s/op 6.4661 s/op 0.94
BLS verifyMultipleSignatures - same message - 3 - blst 688.71 us/op 798.28 us/op 0.86
BLS verifyMultipleSignatures - same message - 8 - blst 811.79 us/op 948.21 us/op 0.86
BLS verifyMultipleSignatures - same message - 32 - blst 1.4397 ms/op 1.4735 ms/op 0.98
BLS verifyMultipleSignatures - same message - 64 - blst 2.2327 ms/op 2.3872 ms/op 0.94
BLS verifyMultipleSignatures - same message - 128 - blst 3.8457 ms/op 4.1394 ms/op 0.93
BLS aggregatePubkeys 32 - blst 16.728 us/op 17.809 us/op 0.94
BLS aggregatePubkeys 128 - blst 59.635 us/op 63.908 us/op 0.93
getSlashingsAndExits - default max 41.139 us/op 49.481 us/op 0.83
getSlashingsAndExits - 2k 323.41 us/op 353.29 us/op 0.92
proposeBlockBody type=full, size=empty 613.97 us/op 640.40 us/op 0.96
isKnown best case - 1 super set check 186.00 ns/op 170.00 ns/op 1.09
isKnown normal case - 2 super set checks 161.00 ns/op 165.00 ns/op 0.98
isKnown worse case - 16 super set checks 164.00 ns/op 169.00 ns/op 0.97
validate api signedAggregateAndProof - struct 1.4962 ms/op 1.5601 ms/op 0.96
validate gossip signedAggregateAndProof - struct 1.4988 ms/op 1.5566 ms/op 0.96
batch validate gossip attestation - vc 640000 - chunk 32 102.25 us/op 111.02 us/op 0.92
batch validate gossip attestation - vc 640000 - chunk 64 89.433 us/op 95.224 us/op 0.94
batch validate gossip attestation - vc 640000 - chunk 128 83.556 us/op 89.225 us/op 0.94
batch validate gossip attestation - vc 640000 - chunk 256 80.187 us/op 84.843 us/op 0.95
bytes32 toHexString 294.00 ns/op 292.00 ns/op 1.01
bytes32 Buffer.toString(hex) 155.00 ns/op 165.00 ns/op 0.94
bytes32 Buffer.toString(hex) from Uint8Array 227.00 ns/op 235.00 ns/op 0.97
bytes32 Buffer.toString(hex) + 0x 157.00 ns/op 165.00 ns/op 0.95
Return object 10000 times 0.20420 ns/op 0.21320 ns/op 0.96
Throw Error 10000 times 3.2344 us/op 3.4972 us/op 0.92
toHex 95.390 ns/op 100.52 ns/op 0.95
Buffer.from 80.063 ns/op 93.044 ns/op 0.86
shared Buffer 56.918 ns/op 64.170 ns/op 0.89
fastMsgIdFn sha256 / 200 bytes 1.3940 us/op 1.4950 us/op 0.93
fastMsgIdFn h32 xxhash / 200 bytes 147.00 ns/op 150.00 ns/op 0.98
fastMsgIdFn h64 xxhash / 200 bytes 183.00 ns/op 209.00 ns/op 0.88
fastMsgIdFn sha256 / 1000 bytes 4.4560 us/op 4.9010 us/op 0.91
fastMsgIdFn h32 xxhash / 1000 bytes 235.00 ns/op 240.00 ns/op 0.98
fastMsgIdFn h64 xxhash / 1000 bytes 238.00 ns/op 257.00 ns/op 0.93
fastMsgIdFn sha256 / 10000 bytes 39.261 us/op 43.245 us/op 0.91
fastMsgIdFn h32 xxhash / 10000 bytes 1.2090 us/op 1.2670 us/op 0.95
fastMsgIdFn h64 xxhash / 10000 bytes 798.00 ns/op 819.00 ns/op 0.97
send data - 1000 256B messages 4.0364 ms/op 4.1424 ms/op 0.97
send data - 1000 512B messages 5.2804 ms/op 4.9397 ms/op 1.07
send data - 1000 1024B messages 5.5812 ms/op 5.6226 ms/op 0.99
send data - 1000 1200B messages 6.2307 ms/op 6.0369 ms/op 1.03
send data - 1000 2048B messages 8.4021 ms/op 20.242 ms/op 0.42
send data - 1000 4096B messages 56.256 ms/op 47.211 ms/op 1.19
send data - 1000 16384B messages 278.74 ms/op 255.66 ms/op 1.09
send data - 1000 65536B messages 1.5533 s/op 1.2293 s/op 1.26
enrSubnets - fastDeserialize 64 bits 709.00 ns/op 784.00 ns/op 0.90
enrSubnets - ssz BitVector 64 bits 263.00 ns/op 266.00 ns/op 0.99
enrSubnets - fastDeserialize 4 bits 94.000 ns/op 104.00 ns/op 0.90
enrSubnets - ssz BitVector 4 bits 267.00 ns/op 269.00 ns/op 0.99
prioritizePeers score -10:0 att 32-0.1 sync 2-0 206.62 us/op 212.78 us/op 0.97
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 215.57 us/op 243.12 us/op 0.89
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 324.29 us/op 353.36 us/op 0.92
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 581.61 us/op 621.30 us/op 0.94
prioritizePeers score 0:0 att 64-1 sync 4-1 678.09 us/op 727.66 us/op 0.93
array of 16000 items push then shift 1.2828 us/op 1.3198 us/op 0.97
LinkedList of 16000 items push then shift 7.0330 ns/op 6.9230 ns/op 1.02
array of 16000 items push then pop 62.690 ns/op 66.659 ns/op 0.94
LinkedList of 16000 items push then pop 5.6230 ns/op 6.1480 ns/op 0.91
array of 24000 items push then shift 1.7346 us/op 1.9636 us/op 0.88
LinkedList of 24000 items push then shift 6.6400 ns/op 6.4990 ns/op 1.02
array of 24000 items push then pop 87.172 ns/op 93.766 ns/op 0.93
LinkedList of 24000 items push then pop 5.6830 ns/op 6.1320 ns/op 0.93
intersect bitArray bitLen 8 3.6540 ns/op 3.9010 ns/op 0.94
intersect array and set length 8 54.042 ns/op 30.630 ns/op 1.76
intersect bitArray bitLen 128 21.862 ns/op 23.527 ns/op 0.93
intersect array and set length 128 464.14 ns/op 517.67 ns/op 0.90
bitArray.getTrueBitIndexes() bitLen 128 878.00 ns/op 931.00 ns/op 0.94
bitArray.getTrueBitIndexes() bitLen 248 1.5960 us/op 1.6660 us/op 0.96
bitArray.getTrueBitIndexes() bitLen 512 3.3440 us/op 3.4810 us/op 0.96
Full columns - reconstruct all 6 blobs 168.53 us/op 165.69 us/op 1.02
Full columns - reconstruct half of the blobs out of 6 67.228 us/op 68.287 us/op 0.98
Full columns - reconstruct single blob out of 6 34.811 us/op 33.919 us/op 1.03
Half columns - reconstruct all 6 blobs 377.31 ms/op 396.72 ms/op 0.95
Half columns - reconstruct half of the blobs out of 6 193.11 ms/op 203.65 ms/op 0.95
Half columns - reconstruct single blob out of 6 69.294 ms/op 70.710 ms/op 0.98
Set add up to 64 items then delete first 2.1525 us/op 1.6887 us/op 1.27
OrderedSet add up to 64 items then delete first 3.3241 us/op 2.5696 us/op 1.29
Set add up to 64 items then delete last 2.3389 us/op 1.9749 us/op 1.18
OrderedSet add up to 64 items then delete last 3.2480 us/op 3.0060 us/op 1.08
Set add up to 64 items then delete middle 2.1089 us/op 2.0226 us/op 1.04
OrderedSet add up to 64 items then delete middle 4.6871 us/op 4.5528 us/op 1.03
Set add up to 128 items then delete first 4.2012 us/op 3.9387 us/op 1.07
OrderedSet add up to 128 items then delete first 6.4373 us/op 5.8714 us/op 1.10
Set add up to 128 items then delete last 3.8374 us/op 3.8884 us/op 0.99
OrderedSet add up to 128 items then delete last 5.7120 us/op 5.9316 us/op 0.96
Set add up to 128 items then delete middle 3.8170 us/op 3.8388 us/op 0.99
OrderedSet add up to 128 items then delete middle 11.500 us/op 11.878 us/op 0.97
Set add up to 256 items then delete first 7.8265 us/op 7.9006 us/op 0.99
OrderedSet add up to 256 items then delete first 11.982 us/op 12.067 us/op 0.99
Set add up to 256 items then delete last 7.4597 us/op 7.7172 us/op 0.97
OrderedSet add up to 256 items then delete last 11.357 us/op 12.126 us/op 0.94
Set add up to 256 items then delete middle 7.5140 us/op 7.6175 us/op 0.99
OrderedSet add up to 256 items then delete middle 34.462 us/op 35.825 us/op 0.96
runFastConfirmationRules vc:100000 bc:96 eq:0 4.9335 ms/op 5.1926 ms/op 0.95
runFastConfirmationRules vc:600000 bc:96 eq:0 39.187 ms/op 35.686 ms/op 1.10
runFastConfirmationRules vc:1000000 bc:96 eq:0 66.237 ms/op 59.620 ms/op 1.11
runFastConfirmationRules vc:600000 bc:320 eq:0 37.152 ms/op 35.735 ms/op 1.04
runFastConfirmationRules vc:100000 bc:96 eq:1000 1.0403 s/op 1.1033 s/op 0.94
pass gossip attestations to forkchoice per slot 2.5415 ms/op 2.6199 ms/op 0.97
forkChoice updateHead vc 100000 bc 64 eq 0 450.72 us/op 478.91 us/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 0 2.3286 ms/op 2.7665 ms/op 0.84
forkChoice updateHead vc 1000000 bc 64 eq 0 3.8265 ms/op 4.6805 ms/op 0.82
forkChoice updateHead vc 600000 bc 320 eq 0 2.2756 ms/op 2.8882 ms/op 0.79
forkChoice updateHead vc 600000 bc 1200 eq 0 2.3684 ms/op 2.9500 ms/op 0.80
forkChoice updateHead vc 600000 bc 7200 eq 0 2.6601 ms/op 3.2581 ms/op 0.82
forkChoice updateHead vc 600000 bc 64 eq 1000 2.2675 ms/op 2.8826 ms/op 0.79
forkChoice updateHead vc 600000 bc 64 eq 10000 2.3796 ms/op 2.8364 ms/op 0.84
forkChoice updateHead vc 600000 bc 64 eq 300000 5.9781 ms/op 6.7289 ms/op 0.89
computeDeltas 1400000 validators 0% inactive 11.395 ms/op 13.518 ms/op 0.84
computeDeltas 1400000 validators 10% inactive 10.906 ms/op 12.777 ms/op 0.85
computeDeltas 1400000 validators 20% inactive 10.065 ms/op 12.095 ms/op 0.83
computeDeltas 1400000 validators 50% inactive 8.2915 ms/op 9.8352 ms/op 0.84
computeDeltas 2100000 validators 0% inactive 16.915 ms/op 20.162 ms/op 0.84
computeDeltas 2100000 validators 10% inactive 15.996 ms/op 19.316 ms/op 0.83
computeDeltas 2100000 validators 20% inactive 14.989 ms/op 17.943 ms/op 0.84
computeDeltas 2100000 validators 50% inactive 10.034 ms/op 14.621 ms/op 0.69
altair processAttestation - 250000 vs - 7PWei normalcase 1.6609 ms/op 1.6198 ms/op 1.03
altair processAttestation - 250000 vs - 7PWei worstcase 2.4017 ms/op 2.3987 ms/op 1.00
altair processAttestation - setStatus - 1/6 committees join 108.21 us/op 106.13 us/op 1.02
altair processAttestation - setStatus - 1/3 committees join 205.18 us/op 202.89 us/op 1.01
altair processAttestation - setStatus - 1/2 committees join 283.98 us/op 287.01 us/op 0.99
altair processAttestation - setStatus - 2/3 committees join 367.91 us/op 368.76 us/op 1.00
altair processAttestation - setStatus - 4/5 committees join 512.31 us/op 510.32 us/op 1.00
altair processAttestation - setStatus - 100% committees join 596.87 us/op 602.03 us/op 0.99
altair processBlock - 250000 vs - 7PWei normalcase 3.2106 ms/op 3.2142 ms/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase hashState 14.427 ms/op 12.444 ms/op 1.16
altair processBlock - 250000 vs - 7PWei worstcase 20.162 ms/op 19.820 ms/op 1.02
altair processBlock - 250000 vs - 7PWei worstcase hashState 42.176 ms/op 38.508 ms/op 1.10
phase0 processBlock - 250000 vs - 7PWei normalcase 1.3547 ms/op 1.3453 ms/op 1.01
phase0 processBlock - 250000 vs - 7PWei worstcase 17.212 ms/op 17.320 ms/op 0.99
altair processEth1Data - 250000 vs - 7PWei normalcase 292.85 us/op 311.55 us/op 0.94
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.2020 us/op 3.7080 us/op 0.86
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 19.201 us/op 23.362 us/op 0.82
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.4580 us/op 6.5680 us/op 0.83
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.3090 us/op 5.2240 us/op 0.63
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 90.156 us/op 100.30 us/op 0.90
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3547 ms/op 1.4170 ms/op 0.96
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.7039 ms/op 1.9115 ms/op 0.89
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7507 ms/op 1.8619 ms/op 0.94
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.5430 ms/op 3.7932 ms/op 0.93
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0726 ms/op 2.0805 ms/op 1.00
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.7327 ms/op 4.0441 ms/op 0.92
Tree 40 250000 create 331.81 ms/op 320.02 ms/op 1.04
Tree 40 250000 get(125000) 100.06 ns/op 103.87 ns/op 0.96
Tree 40 250000 set(125000) 1.0263 us/op 1.0979 us/op 0.93
Tree 40 250000 toArray() 10.749 ms/op 9.6388 ms/op 1.12
Tree 40 250000 iterate all - toArray() + loop 9.3767 ms/op 9.7342 ms/op 0.96
Tree 40 250000 iterate all - get(i) 38.236 ms/op 37.194 ms/op 1.03
Array 250000 create 2.0829 ms/op 2.0605 ms/op 1.01
Array 250000 clone - spread 645.37 us/op 648.88 us/op 0.99
Array 250000 get(125000) 0.28400 ns/op 0.29800 ns/op 0.95
Array 250000 set(125000) 0.28500 ns/op 0.30300 ns/op 0.94
Array 250000 iterate all - loop 55.523 us/op 57.337 us/op 0.97
phase0 afterProcessEpoch - 250000 vs - 7PWei 52.737 ms/op 39.436 ms/op 1.34
Array.fill - length 1000000 2.1916 ms/op 2.3815 ms/op 0.92
Array push - length 1000000 7.4826 ms/op 7.6183 ms/op 0.98
Array.get 0.20262 ns/op 0.20628 ns/op 0.98
Uint8Array.get 0.22520 ns/op 0.24774 ns/op 0.91
phase0 beforeProcessEpoch - 250000 vs - 7PWei 17.692 ms/op 12.241 ms/op 1.45
altair processEpoch - mainnet_e81889 227.94 ms/op 245.23 ms/op 0.93
mainnet_e81889 - altair beforeProcessEpoch 33.491 ms/op 19.548 ms/op 1.71
mainnet_e81889 - altair processJustificationAndFinalization 5.5660 us/op 5.1910 us/op 1.07
mainnet_e81889 - altair processInactivityUpdates 3.4632 ms/op 3.7644 ms/op 0.92
mainnet_e81889 - altair processRewardsAndPenalties 18.682 ms/op 17.382 ms/op 1.07
mainnet_e81889 - altair processRegistryUpdates 562.00 ns/op 587.00 ns/op 0.96
mainnet_e81889 - altair processSlashings 137.00 ns/op 160.00 ns/op 0.86
mainnet_e81889 - altair processEth1DataReset 132.00 ns/op 155.00 ns/op 0.85
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.5062 ms/op 1.7260 ms/op 0.87
mainnet_e81889 - altair processSlashingsReset 687.00 ns/op 714.00 ns/op 0.96
mainnet_e81889 - altair processRandaoMixesReset 971.00 ns/op 1.0960 us/op 0.89
mainnet_e81889 - altair processHistoricalRootsUpdate 135.00 ns/op 155.00 ns/op 0.87
mainnet_e81889 - altair processParticipationFlagUpdates 436.00 ns/op 462.00 ns/op 0.94
mainnet_e81889 - altair processSyncCommitteeUpdates 107.00 ns/op 130.00 ns/op 0.82
mainnet_e81889 - altair afterProcessEpoch 41.937 ms/op 40.583 ms/op 1.03
capella processEpoch - mainnet_e217614 789.77 ms/op 817.04 ms/op 0.97
mainnet_e217614 - capella beforeProcessEpoch 54.599 ms/op 59.005 ms/op 0.93
mainnet_e217614 - capella processJustificationAndFinalization 4.9420 us/op 5.6370 us/op 0.88
mainnet_e217614 - capella processInactivityUpdates 11.900 ms/op 12.247 ms/op 0.97
mainnet_e217614 - capella processRewardsAndPenalties 96.015 ms/op 96.748 ms/op 0.99
mainnet_e217614 - capella processRegistryUpdates 4.5040 us/op 4.5700 us/op 0.99
mainnet_e217614 - capella processSlashings 136.00 ns/op 147.00 ns/op 0.93
mainnet_e217614 - capella processEth1DataReset 134.00 ns/op 146.00 ns/op 0.92
mainnet_e217614 - capella processEffectiveBalanceUpdates 6.3404 ms/op 5.9866 ms/op 1.06
mainnet_e217614 - capella processSlashingsReset 670.00 ns/op 694.00 ns/op 0.97
mainnet_e217614 - capella processRandaoMixesReset 990.00 ns/op 1.3210 us/op 0.75
mainnet_e217614 - capella processHistoricalRootsUpdate 136.00 ns/op 155.00 ns/op 0.88
mainnet_e217614 - capella processParticipationFlagUpdates 447.00 ns/op 467.00 ns/op 0.96
mainnet_e217614 - capella afterProcessEpoch 108.20 ms/op 109.96 ms/op 0.98
phase0 processEpoch - mainnet_e58758 296.17 ms/op 315.15 ms/op 0.94
mainnet_e58758 - phase0 beforeProcessEpoch 64.655 ms/op 71.026 ms/op 0.91
mainnet_e58758 - phase0 processJustificationAndFinalization 6.0980 us/op 6.5470 us/op 0.93
mainnet_e58758 - phase0 processRewardsAndPenalties 15.740 ms/op 16.802 ms/op 0.94
mainnet_e58758 - phase0 processRegistryUpdates 2.3030 us/op 2.3240 us/op 0.99
mainnet_e58758 - phase0 processSlashings 136.00 ns/op 157.00 ns/op 0.87
mainnet_e58758 - phase0 processEth1DataReset 331.00 ns/op 156.00 ns/op 2.12
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 799.57 us/op 1.3485 ms/op 0.59
mainnet_e58758 - phase0 processSlashingsReset 856.00 ns/op 931.00 ns/op 0.92
mainnet_e58758 - phase0 processRandaoMixesReset 1.3660 us/op 1.3170 us/op 1.04
mainnet_e58758 - phase0 processHistoricalRootsUpdate 136.00 ns/op 161.00 ns/op 0.84
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.2630 us/op 1.1530 us/op 1.10
mainnet_e58758 - phase0 afterProcessEpoch 34.237 ms/op 34.029 ms/op 1.01
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.1020 ms/op 1.0407 ms/op 1.06
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.6282 ms/op 1.6731 ms/op 0.97
altair processInactivityUpdates - 250000 normalcase 10.475 ms/op 10.910 ms/op 0.96
altair processInactivityUpdates - 250000 worstcase 10.622 ms/op 10.626 ms/op 1.00
phase0 processRegistryUpdates - 250000 normalcase 2.3390 us/op 2.4390 us/op 0.96
phase0 processRegistryUpdates - 250000 badcase_full_deposits 147.24 us/op 144.99 us/op 1.02
phase0 processRegistryUpdates - 250000 worstcase 0.5 71.678 ms/op 51.709 ms/op 1.39
altair processRewardsAndPenalties - 250000 normalcase 14.654 ms/op 15.201 ms/op 0.96
altair processRewardsAndPenalties - 250000 worstcase 14.278 ms/op 15.602 ms/op 0.92
phase0 getAttestationDeltas - 250000 normalcase 5.1497 ms/op 5.4159 ms/op 0.95
phase0 getAttestationDeltas - 250000 worstcase 5.1807 ms/op 5.5034 ms/op 0.94
phase0 processSlashings - 250000 worstcase 57.853 us/op 62.399 us/op 0.93
altair processSyncCommitteeUpdates - 250000 9.7519 ms/op 10.201 ms/op 0.96
BeaconState.hashTreeRoot - No change 163.00 ns/op 191.00 ns/op 0.85
BeaconState.hashTreeRoot - 1 full validator 71.715 us/op 57.076 us/op 1.26
BeaconState.hashTreeRoot - 32 full validator 982.15 us/op 719.35 us/op 1.37
BeaconState.hashTreeRoot - 512 full validator 6.4433 ms/op 5.9999 ms/op 1.07
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 102.19 us/op 70.494 us/op 1.45
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.5912 ms/op 1.0456 ms/op 1.52
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 18.153 ms/op 12.820 ms/op 1.42
BeaconState.hashTreeRoot - 1 balances 99.319 us/op 55.867 us/op 1.78
BeaconState.hashTreeRoot - 32 balances 717.93 us/op 540.14 us/op 1.33
BeaconState.hashTreeRoot - 512 balances 5.6650 ms/op 4.6233 ms/op 1.23
BeaconState.hashTreeRoot - 250000 balances 162.50 ms/op 89.826 ms/op 1.81
aggregationBits - 2048 els - zipIndexesInBitList 19.803 us/op 20.194 us/op 0.98
regular array get 100000 times 22.919 us/op 22.932 us/op 1.00
wrappedArray get 100000 times 22.909 us/op 22.929 us/op 1.00
arrayWithProxy get 100000 times 12.449 ms/op 10.719 ms/op 1.16
ssz.Root.equals 21.409 ns/op 21.536 ns/op 0.99
byteArrayEquals 21.307 ns/op 21.362 ns/op 1.00
Buffer.compare 8.7910 ns/op 9.6450 ns/op 0.91
processSlot - 1 slots 8.8210 us/op 8.2710 us/op 1.07
processSlot - 32 slots 2.1574 ms/op 1.8571 ms/op 1.16
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 7.1103 ms/op 2.8854 ms/op 2.46
getCommitteeAssignments - req 1 vs - 250000 vc 1.6475 ms/op 1.6924 ms/op 0.97
getCommitteeAssignments - req 100 vs - 250000 vc 3.3987 ms/op 3.4554 ms/op 0.98
getCommitteeAssignments - req 1000 vs - 250000 vc 3.6393 ms/op 3.7095 ms/op 0.98
findModifiedValidators - 10000 modified validators 653.68 ms/op 661.28 ms/op 0.99
findModifiedValidators - 1000 modified validators 466.84 ms/op 556.43 ms/op 0.84
findModifiedValidators - 100 modified validators 257.49 ms/op 323.50 ms/op 0.80
findModifiedValidators - 10 modified validators 142.98 ms/op 279.33 ms/op 0.51
findModifiedValidators - 1 modified validators 170.27 ms/op 241.05 ms/op 0.71
findModifiedValidators - no difference 150.61 ms/op 204.13 ms/op 0.74
migrate state 1500000 validators, 3400 modified, 2000 new 3.4232 s/op 2.6743 s/op 1.28
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.4900 ns/op 3.8700 ns/op 0.90
state getBlockRootAtSlot - 250000 vs - 7PWei 454.77 ns/op 287.05 ns/op 1.58
computeProposerIndex 100000 validators 1.3224 ms/op 1.3246 ms/op 1.00
getNextSyncCommitteeIndices 1000 validators 2.8142 ms/op 2.8825 ms/op 0.98
getNextSyncCommitteeIndices 10000 validators 25.014 ms/op 25.180 ms/op 0.99
getNextSyncCommitteeIndices 100000 validators 82.702 ms/op 83.309 ms/op 0.99
computeProposers - vc 250000 536.95 us/op 549.11 us/op 0.98
computeEpochShuffling - vc 250000 40.365 ms/op 40.507 ms/op 1.00
getNextSyncCommittee - vc 250000 9.2849 ms/op 9.4038 ms/op 0.99
nodejs block root to RootHex using toHex 97.507 ns/op 104.82 ns/op 0.93
nodejs block root to RootHex using toRootHex 67.345 ns/op 69.665 ns/op 0.97
nodejs fromHex(blob) 796.99 us/op 809.38 us/op 0.98
nodejs fromHexInto(blob) 739.82 us/op 668.08 us/op 1.11
nodejs block root to RootHex using the deprecated toHexString 470.29 ns/op 486.38 ns/op 0.97
nodejs byteArrayEquals 32 bytes (block root) 25.644 ns/op 25.866 ns/op 0.99
nodejs byteArrayEquals 48 bytes (pubkey) 37.175 ns/op 37.414 ns/op 0.99
nodejs byteArrayEquals 96 bytes (signature) 39.788 ns/op 41.037 ns/op 0.97
nodejs byteArrayEquals 1024 bytes 42.762 ns/op 43.658 ns/op 0.98
nodejs byteArrayEquals 131072 bytes (blob) 1.7286 us/op 1.7615 us/op 0.98
browser block root to RootHex using toHex 144.10 ns/op 147.46 ns/op 0.98
browser block root to RootHex using toRootHex 129.61 ns/op 135.79 ns/op 0.95
browser fromHex(blob) 1.7169 ms/op 1.5818 ms/op 1.09
browser fromHexInto(blob) 738.58 us/op 670.45 us/op 1.10
browser block root to RootHex using the deprecated toHexString 331.62 ns/op 346.46 ns/op 0.96
browser byteArrayEquals 32 bytes (block root) 27.660 ns/op 27.966 ns/op 0.99
browser byteArrayEquals 48 bytes (pubkey) 38.978 ns/op 39.443 ns/op 0.99
browser byteArrayEquals 96 bytes (signature) 72.751 ns/op 73.660 ns/op 0.99
browser byteArrayEquals 1024 bytes 739.85 ns/op 751.59 ns/op 0.98
browser byteArrayEquals 131072 bytes (blob) 93.324 us/op 94.753 us/op 0.98

by benchmarkbot/action

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

Approving — this resolves the issue.

I independently reproduced the crash end-to-end first (Kurtosis, latest ethereum-package images — Lodestar v1.41.0 + Lighthouse v8.1.2). It fails with exactly the stack this fixes: TypeError: Cannot read properties of undefined (reading 'withdrawalCredentials') at processWithdrawalRequest.ts:86 ← :40 ← processOperations.ts:82, with the victim pinned one slot behind a finalized block until restart. The call site is unchanged since #7284, so this reproduces on v1.44/v1.45/unstable identically.

Fix review:

  • processWithdrawalRequest.ts!isValidatorKnown(state, validatorIndex) is the correct guard. It matches the existing pattern in processPendingDeposits and restores the spec-mandated silent no-op instead of throwing. isValidatorKnown takes ValidatorIndex | null and narrows, so the null case is still covered by the same check.
  • validator/index.ts (builder-registration filter) — good catch, this is the same shared-pubkeyCache hazard feeding headState.getValidator(...). validatorIndex >= headState.validatorCount is the right bound and returning false (skip the registration) is the correct behavior for a pubkey the head state doesn't hold.
  • Swept the other shared-cache consumers to be sure nothing else is exposed: beacon/state/utils.ts already bounds-checks (>= state.validatorCount); processConsolidationRequest / processDeposit / processPendingDeposits / upgradeStateToGloas all already guard via isPubkeyKnown / isValidatorKnown / an inline bound. No remaining unguarded site.
  • Regression test faithfully reproduces the poisoning: adds the pubkey to the shared cache through a clone at index validators.length, asserts getValidatorIndex resolves it out-of-range for the base state, then that processWithdrawalRequest no-ops without throwing.

CI green across the board. LGTM.

🤖 Generated with AI assistance

@nflaig
nflaig merged commit aa562e6 into unstable Aug 3, 2026
19 checks passed
@nflaig
nflaig deleted the nflaig/validate-cached-validator-indices branch August 3, 2026 09:39
markolazic01 pushed a commit to markolazic01/lodestar that referenced this pull request Aug 3, 2026
@wemeetagain

Copy link
Copy Markdown
Member

🎉 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

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants