Skip to content

chore: fix BlockInputSync metrics and logs#9481

Merged
nflaig merged 8 commits into
unstablefrom
te/fix_block_input_sync_metrics_logs
Jun 9, 2026
Merged

chore: fix BlockInputSync metrics and logs#9481
nflaig merged 8 commits into
unstablefrom
te/fix_block_input_sync_metrics_logs

Conversation

@twoeths

@twoeths twoeths commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Motivation

  • better logs + metrics for BlockInputSync, this is very useful to debug unstable networks

Description

  • dedup unknown block vs unknown payload metrics
  • add delaySec whenever we have a slot, more logs
  • add slot to ChainEvent.unknownEnvelopeBlockRoot event

AI Assistance Disclosure

  • created with the help of Claude

@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 enhances the BlockInputSync and payload syncing mechanism by tracking and propagating the message slot (as a logging and pruning hint) through the unknownEnvelopeBlockRoot event and pending payload structures. It also refines the pending block types and adds new metrics to track payload sync triggers. Regarding the feedback, the newly introduced metric lodestar_payload_input_sync_source_total should be registered as a Prometheus counter rather than a gauge to correctly reflect cumulative counts and support rate calculations.

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/metrics/metrics/lodestar.ts Outdated
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

⚠️ Performance Alert ⚠️

Possible performance regression was detected for some benchmarks.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold.

Benchmark suite Current: 4a6c04b Previous: 8d5a6a4 Ratio
Full columns - reconstruct half of the blobs out of 20 716.22 us/op 224.03 us/op 3.20
Full benchmark results
Benchmark suite Current: 4a6c04b Previous: 8d5a6a4 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 980.15 us/op 1.1092 ms/op 0.88
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 40.535 us/op 41.301 us/op 0.98
BLS verify - blst 742.21 us/op 707.14 us/op 1.05
BLS verifyMultipleSignatures 3 - blst 1.3765 ms/op 1.3665 ms/op 1.01
BLS verifyMultipleSignatures 8 - blst 2.2064 ms/op 2.1761 ms/op 1.01
BLS verifyMultipleSignatures 32 - blst 6.9192 ms/op 6.8677 ms/op 1.01
BLS verifyMultipleSignatures 64 - blst 13.960 ms/op 13.462 ms/op 1.04
BLS verifyMultipleSignatures 128 - blst 25.948 ms/op 26.027 ms/op 1.00
BLS deserializing 10000 signatures 639.22 ms/op 638.25 ms/op 1.00
BLS deserializing 100000 signatures 6.4570 s/op 6.2371 s/op 1.04
BLS verifyMultipleSignatures - same message - 3 - blst 714.20 us/op 778.13 us/op 0.92
BLS verifyMultipleSignatures - same message - 8 - blst 943.24 us/op 908.86 us/op 1.04
BLS verifyMultipleSignatures - same message - 32 - blst 1.5818 ms/op 1.4708 ms/op 1.08
BLS verifyMultipleSignatures - same message - 64 - blst 2.3976 ms/op 2.4521 ms/op 0.98
BLS verifyMultipleSignatures - same message - 128 - blst 4.1195 ms/op 4.1329 ms/op 1.00
BLS aggregatePubkeys 32 - blst 17.837 us/op 17.972 us/op 0.99
BLS aggregatePubkeys 128 - blst 64.285 us/op 63.954 us/op 1.01
getSlashingsAndExits - default max 50.053 us/op 50.648 us/op 0.99
getSlashingsAndExits - 2k 350.27 us/op 345.36 us/op 1.01
proposeBlockBody type=full, size=empty 678.16 us/op 684.40 us/op 0.99
isKnown best case - 1 super set check 161.00 ns/op 164.00 ns/op 0.98
isKnown normal case - 2 super set checks 159.00 ns/op 163.00 ns/op 0.98
isKnown worse case - 16 super set checks 161.00 ns/op 165.00 ns/op 0.98
validate api signedAggregateAndProof - struct 1.5396 ms/op 1.5635 ms/op 0.98
validate gossip signedAggregateAndProof - struct 1.5417 ms/op 1.5522 ms/op 0.99
batch validate gossip attestation - vc 640000 - chunk 32 108.13 us/op 109.10 us/op 0.99
batch validate gossip attestation - vc 640000 - chunk 64 95.119 us/op 94.949 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 128 88.573 us/op 88.654 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 256 85.425 us/op 85.384 us/op 1.00
bytes32 toHexString 289.00 ns/op 292.00 ns/op 0.99
bytes32 Buffer.toString(hex) 155.00 ns/op 161.00 ns/op 0.96
bytes32 Buffer.toString(hex) from Uint8Array 225.00 ns/op 227.00 ns/op 0.99
bytes32 Buffer.toString(hex) + 0x 158.00 ns/op 162.00 ns/op 0.98
Return object 10000 times 0.21720 ns/op 0.21020 ns/op 1.03
Throw Error 10000 times 3.4992 us/op 3.2355 us/op 1.08
toHex 100.83 ns/op 85.822 ns/op 1.17
Buffer.from 86.408 ns/op 78.183 ns/op 1.11
shared Buffer 57.933 ns/op 50.954 ns/op 1.14
fastMsgIdFn sha256 / 200 bytes 1.5060 us/op 1.4530 us/op 1.04
fastMsgIdFn h32 xxhash / 200 bytes 156.00 ns/op 147.00 ns/op 1.06
fastMsgIdFn h64 xxhash / 200 bytes 205.00 ns/op 198.00 ns/op 1.04
fastMsgIdFn sha256 / 1000 bytes 4.8310 us/op 4.6490 us/op 1.04
fastMsgIdFn h32 xxhash / 1000 bytes 241.00 ns/op 237.00 ns/op 1.02
fastMsgIdFn h64 xxhash / 1000 bytes 243.00 ns/op 246.00 ns/op 0.99
fastMsgIdFn sha256 / 10000 bytes 42.927 us/op 41.145 us/op 1.04
fastMsgIdFn h32 xxhash / 10000 bytes 1.3020 us/op 1.2760 us/op 1.02
fastMsgIdFn h64 xxhash / 10000 bytes 846.00 ns/op 829.00 ns/op 1.02
enrSubnets - fastDeserialize 64 bits 729.00 ns/op 719.00 ns/op 1.01
enrSubnets - ssz BitVector 64 bits 261.00 ns/op 261.00 ns/op 1.00
enrSubnets - fastDeserialize 4 bits 100.00 ns/op 97.000 ns/op 1.03
enrSubnets - ssz BitVector 4 bits 262.00 ns/op 267.00 ns/op 0.98
prioritizePeers score -10:0 att 32-0.1 sync 2-0 212.63 us/op 203.82 us/op 1.04
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 242.30 us/op 239.71 us/op 1.01
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 355.33 us/op 345.93 us/op 1.03
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 622.61 us/op 626.09 us/op 0.99
prioritizePeers score 0:0 att 64-1 sync 4-1 724.19 us/op 728.91 us/op 0.99
array of 16000 items push then shift 1.3194 us/op 1.2707 us/op 1.04
LinkedList of 16000 items push then shift 7.2230 ns/op 7.5230 ns/op 0.96
array of 16000 items push then pop 69.387 ns/op 66.206 ns/op 1.05
LinkedList of 16000 items push then pop 6.2050 ns/op 6.1570 ns/op 1.01
array of 24000 items push then shift 1.9355 us/op 1.9529 us/op 0.99
LinkedList of 24000 items push then shift 6.6020 ns/op 6.8820 ns/op 0.96
array of 24000 items push then pop 95.101 ns/op 95.429 ns/op 1.00
LinkedList of 24000 items push then pop 6.1180 ns/op 6.1770 ns/op 0.99
intersect bitArray bitLen 8 4.7800 ns/op 4.9090 ns/op 0.97
intersect array and set length 8 30.623 ns/op 30.238 ns/op 1.01
intersect bitArray bitLen 128 24.348 ns/op 25.070 ns/op 0.97
intersect array and set length 128 515.17 ns/op 516.03 ns/op 1.00
bitArray.getTrueBitIndexes() bitLen 128 980.00 ns/op 998.00 ns/op 0.98
bitArray.getTrueBitIndexes() bitLen 248 1.7580 us/op 1.7510 us/op 1.00
bitArray.getTrueBitIndexes() bitLen 512 3.6270 us/op 3.6210 us/op 1.00
Full columns - reconstruct all 6 blobs 151.36 us/op 341.80 us/op 0.44
Full columns - reconstruct half of the blobs out of 6 79.841 us/op 16.829 ms/op 0.00
Full columns - reconstruct single blob out of 6 33.207 us/op 28.957 us/op 1.15
Half columns - reconstruct all 6 blobs 402.39 ms/op 391.83 ms/op 1.03
Half columns - reconstruct half of the blobs out of 6 200.60 ms/op 197.73 ms/op 1.01
Half columns - reconstruct single blob out of 6 72.578 ms/op 71.366 ms/op 1.02
Full columns - reconstruct all 10 blobs 305.77 us/op 187.33 us/op 1.63
Full columns - reconstruct half of the blobs out of 10 152.82 us/op 101.04 us/op 1.51
Full columns - reconstruct single blob out of 10 34.848 us/op 33.532 us/op 1.04
Half columns - reconstruct all 10 blobs 671.97 ms/op 646.96 ms/op 1.04
Half columns - reconstruct half of the blobs out of 10 339.07 ms/op 328.30 ms/op 1.03
Half columns - reconstruct single blob out of 10 71.899 ms/op 73.097 ms/op 0.98
Full columns - reconstruct all 20 blobs 1.5632 ms/op 1.8586 ms/op 0.84
Full columns - reconstruct half of the blobs out of 20 716.22 us/op 224.03 us/op 3.20
Full columns - reconstruct single blob out of 20 34.796 us/op 28.721 us/op 1.21
Half columns - reconstruct all 20 blobs 1.3405 s/op 1.3149 s/op 1.02
Half columns - reconstruct half of the blobs out of 20 673.04 ms/op 647.34 ms/op 1.04
Half columns - reconstruct single blob out of 20 71.402 ms/op 70.402 ms/op 1.01
Set add up to 64 items then delete first 2.6823 us/op 2.1275 us/op 1.26
OrderedSet add up to 64 items then delete first 3.4510 us/op 3.3856 us/op 1.02
Set add up to 64 items then delete last 2.4739 us/op 2.3998 us/op 1.03
OrderedSet add up to 64 items then delete last 3.3977 us/op 3.3288 us/op 1.02
Set add up to 64 items then delete middle 2.2066 us/op 2.1416 us/op 1.03
OrderedSet add up to 64 items then delete middle 4.8527 us/op 4.8069 us/op 1.01
Set add up to 128 items then delete first 4.4671 us/op 4.3117 us/op 1.04
OrderedSet add up to 128 items then delete first 6.7938 us/op 7.1454 us/op 0.95
Set add up to 128 items then delete last 4.2933 us/op 3.9195 us/op 1.10
OrderedSet add up to 128 items then delete last 5.9963 us/op 5.8986 us/op 1.02
Set add up to 128 items then delete middle 4.0699 us/op 3.9031 us/op 1.04
OrderedSet add up to 128 items then delete middle 11.966 us/op 11.819 us/op 1.01
Set add up to 256 items then delete first 8.3051 us/op 7.9596 us/op 1.04
OrderedSet add up to 256 items then delete first 12.746 us/op 13.432 us/op 0.95
Set add up to 256 items then delete last 8.0284 us/op 7.7276 us/op 1.04
OrderedSet add up to 256 items then delete last 12.022 us/op 11.596 us/op 1.04
Set add up to 256 items then delete middle 7.8823 us/op 7.6824 us/op 1.03
OrderedSet add up to 256 items then delete middle 36.053 us/op 35.378 us/op 1.02
runFastConfirmationRules vc:100000 bc:96 eq:0 3.3740 us/op 2.9260 us/op 1.15
runFastConfirmationRules vc:600000 bc:96 eq:0 8.3500 us/op 3.8000 us/op 2.20
runFastConfirmationRules vc:1000000 bc:96 eq:0 10.736 us/op 3.8160 us/op 2.81
runFastConfirmationRules vc:600000 bc:320 eq:0 9.0440 us/op 6.3100 us/op 1.43
runFastConfirmationRules vc:600000 bc:1200 eq:0 32.897 us/op 29.167 us/op 1.13
runFastConfirmationRules vc:600000 bc:96 eq:1000 5.0890 us/op 3.6160 us/op 1.41
runFastConfirmationRules vc:600000 bc:96 eq:10000 5.7920 us/op 3.7800 us/op 1.53
runFastConfirmationRules vc:600000 bc:96 eq:300000 19.054 us/op 6.9770 us/op 2.73
pass gossip attestations to forkchoice per slot 2.5814 ms/op 2.5789 ms/op 1.00
forkChoice updateHead vc 100000 bc 64 eq 0 474.85 us/op 434.18 us/op 1.09
forkChoice updateHead vc 600000 bc 64 eq 0 2.8718 ms/op 2.5704 ms/op 1.12
forkChoice updateHead vc 1000000 bc 64 eq 0 4.7436 ms/op 4.3130 ms/op 1.10
forkChoice updateHead vc 600000 bc 320 eq 0 2.8782 ms/op 2.5751 ms/op 1.12
forkChoice updateHead vc 600000 bc 1200 eq 0 3.0588 ms/op 2.6042 ms/op 1.17
forkChoice updateHead vc 600000 bc 7200 eq 0 3.4394 ms/op 3.6089 ms/op 0.95
forkChoice updateHead vc 600000 bc 64 eq 1000 3.0556 ms/op 2.3743 ms/op 1.29
forkChoice updateHead vc 600000 bc 64 eq 10000 2.9776 ms/op 2.4749 ms/op 1.20
forkChoice updateHead vc 600000 bc 64 eq 300000 7.5143 ms/op 6.9063 ms/op 1.09
computeDeltas 1400000 validators 0% inactive 13.605 ms/op 17.182 ms/op 0.79
computeDeltas 1400000 validators 10% inactive 12.727 ms/op 15.654 ms/op 0.81
computeDeltas 1400000 validators 20% inactive 11.868 ms/op 14.043 ms/op 0.85
computeDeltas 1400000 validators 50% inactive 9.2800 ms/op 10.883 ms/op 0.85
computeDeltas 2100000 validators 0% inactive 20.508 ms/op 25.857 ms/op 0.79
computeDeltas 2100000 validators 10% inactive 19.370 ms/op 23.566 ms/op 0.82
computeDeltas 2100000 validators 20% inactive 17.805 ms/op 21.026 ms/op 0.85
computeDeltas 2100000 validators 50% inactive 13.804 ms/op 16.389 ms/op 0.84
altair processAttestation - 250000 vs - 7PWei normalcase 1.8655 ms/op 1.8343 ms/op 1.02
altair processAttestation - 250000 vs - 7PWei worstcase 2.6246 ms/op 2.6124 ms/op 1.00
altair processAttestation - setStatus - 1/6 committees join 107.91 us/op 104.04 us/op 1.04
altair processAttestation - setStatus - 1/3 committees join 220.91 us/op 210.06 us/op 1.05
altair processAttestation - setStatus - 1/2 committees join 312.44 us/op 291.31 us/op 1.07
altair processAttestation - setStatus - 2/3 committees join 379.69 us/op 379.31 us/op 1.00
altair processAttestation - setStatus - 4/5 committees join 532.38 us/op 536.54 us/op 0.99
altair processAttestation - setStatus - 100% committees join 621.32 us/op 619.22 us/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase 4.4673 ms/op 4.0319 ms/op 1.11
altair processBlock - 250000 vs - 7PWei normalcase hashState 16.777 ms/op 14.720 ms/op 1.14
altair processBlock - 250000 vs - 7PWei worstcase 26.058 ms/op 20.472 ms/op 1.27
altair processBlock - 250000 vs - 7PWei worstcase hashState 44.558 ms/op 41.267 ms/op 1.08
phase0 processBlock - 250000 vs - 7PWei normalcase 1.3364 ms/op 1.3574 ms/op 0.98
phase0 processBlock - 250000 vs - 7PWei worstcase 19.564 ms/op 16.361 ms/op 1.20
altair processEth1Data - 250000 vs - 7PWei normalcase 301.97 us/op 284.29 us/op 1.06
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.3610 us/op 3.1090 us/op 1.08
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 22.382 us/op 20.279 us/op 1.10
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 7.1590 us/op 6.2530 us/op 1.14
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 5.0330 us/op 4.3710 us/op 1.15
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 98.182 us/op 93.958 us/op 1.04
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.4537 ms/op 1.3782 ms/op 1.05
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.9289 ms/op 1.7425 ms/op 1.11
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.9028 ms/op 1.8060 ms/op 1.05
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.7489 ms/op 3.5801 ms/op 1.05
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.1879 ms/op 1.9690 ms/op 1.11
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.3817 ms/op 3.9110 ms/op 1.12
Tree 40 250000 create 379.39 ms/op 343.11 ms/op 1.11
Tree 40 250000 get(125000) 105.45 ns/op 90.254 ns/op 1.17
Tree 40 250000 set(125000) 1.1639 us/op 952.46 ns/op 1.22
Tree 40 250000 toArray() 15.940 ms/op 12.365 ms/op 1.29
Tree 40 250000 iterate all - toArray() + loop 14.642 ms/op 12.011 ms/op 1.22
Tree 40 250000 iterate all - get(i) 43.611 ms/op 39.647 ms/op 1.10
Array 250000 create 2.3443 ms/op 2.0653 ms/op 1.14
Array 250000 clone - spread 700.57 us/op 646.24 us/op 1.08
Array 250000 get(125000) 0.29700 ns/op 0.28500 ns/op 1.04
Array 250000 set(125000) 0.30200 ns/op 0.29100 ns/op 1.04
Array 250000 iterate all - loop 58.554 us/op 55.013 us/op 1.06
phase0 afterProcessEpoch - 250000 vs - 7PWei 39.527 ms/op 38.498 ms/op 1.03
Array.fill - length 1000000 2.4631 ms/op 2.3175 ms/op 1.06
Array push - length 1000000 9.3757 ms/op 10.345 ms/op 0.91
Array.get 0.21079 ns/op 0.20599 ns/op 1.02
Uint8Array.get 0.26106 ns/op 0.24164 ns/op 1.08
phase0 beforeProcessEpoch - 250000 vs - 7PWei 16.149 ms/op 20.319 ms/op 0.79
altair processEpoch - mainnet_e81889 274.37 ms/op 331.19 ms/op 0.83
mainnet_e81889 - altair beforeProcessEpoch 54.940 ms/op 19.055 ms/op 2.88
mainnet_e81889 - altair processJustificationAndFinalization 4.5130 us/op 6.6350 us/op 0.68
mainnet_e81889 - altair processInactivityUpdates 3.7222 ms/op 6.9472 ms/op 0.54
mainnet_e81889 - altair processRewardsAndPenalties 19.776 ms/op 19.126 ms/op 1.03
mainnet_e81889 - altair processRegistryUpdates 567.00 ns/op 547.00 ns/op 1.04
mainnet_e81889 - altair processSlashings 144.00 ns/op 137.00 ns/op 1.05
mainnet_e81889 - altair processEth1DataReset 140.00 ns/op 134.00 ns/op 1.04
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.4046 ms/op 1.7196 ms/op 0.82
mainnet_e81889 - altair processSlashingsReset 738.00 ns/op 678.00 ns/op 1.09
mainnet_e81889 - altair processRandaoMixesReset 1.0280 us/op 1.3370 us/op 0.77
mainnet_e81889 - altair processHistoricalRootsUpdate 144.00 ns/op 133.00 ns/op 1.08
mainnet_e81889 - altair processParticipationFlagUpdates 458.00 ns/op 487.00 ns/op 0.94
mainnet_e81889 - altair processSyncCommitteeUpdates 115.00 ns/op 110.00 ns/op 1.05
mainnet_e81889 - altair afterProcessEpoch 43.186 ms/op 42.623 ms/op 1.01
capella processEpoch - mainnet_e217614 732.69 ms/op 955.01 ms/op 0.77
mainnet_e217614 - capella beforeProcessEpoch 60.731 ms/op 62.205 ms/op 0.98
mainnet_e217614 - capella processJustificationAndFinalization 4.7860 us/op 7.2750 us/op 0.66
mainnet_e217614 - capella processInactivityUpdates 13.076 ms/op 22.210 ms/op 0.59
mainnet_e217614 - capella processRewardsAndPenalties 99.585 ms/op 92.495 ms/op 1.08
mainnet_e217614 - capella processRegistryUpdates 4.7440 us/op 4.9980 us/op 0.95
mainnet_e217614 - capella processSlashings 147.00 ns/op 135.00 ns/op 1.09
mainnet_e217614 - capella processEth1DataReset 144.00 ns/op 133.00 ns/op 1.08
mainnet_e217614 - capella processEffectiveBalanceUpdates 7.9435 ms/op 4.6242 ms/op 1.72
mainnet_e217614 - capella processSlashingsReset 736.00 ns/op 696.00 ns/op 1.06
mainnet_e217614 - capella processRandaoMixesReset 1.1310 us/op 1.2590 us/op 0.90
mainnet_e217614 - capella processHistoricalRootsUpdate 138.00 ns/op 134.00 ns/op 1.03
mainnet_e217614 - capella processParticipationFlagUpdates 482.00 ns/op 433.00 ns/op 1.11
mainnet_e217614 - capella afterProcessEpoch 112.80 ms/op 114.90 ms/op 0.98
phase0 processEpoch - mainnet_e58758 321.88 ms/op 339.85 ms/op 0.95
mainnet_e58758 - phase0 beforeProcessEpoch 67.118 ms/op 58.335 ms/op 1.15
mainnet_e58758 - phase0 processJustificationAndFinalization 6.1780 us/op 6.1840 us/op 1.00
mainnet_e58758 - phase0 processRewardsAndPenalties 16.086 ms/op 15.583 ms/op 1.03
mainnet_e58758 - phase0 processRegistryUpdates 2.3620 us/op 2.2600 us/op 1.05
mainnet_e58758 - phase0 processSlashings 145.00 ns/op 123.00 ns/op 1.18
mainnet_e58758 - phase0 processEth1DataReset 138.00 ns/op 134.00 ns/op 1.03
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.0853 ms/op 829.89 us/op 1.31
mainnet_e58758 - phase0 processSlashingsReset 936.00 ns/op 894.00 ns/op 1.05
mainnet_e58758 - phase0 processRandaoMixesReset 1.2070 us/op 1.4060 us/op 0.86
mainnet_e58758 - phase0 processHistoricalRootsUpdate 145.00 ns/op 134.00 ns/op 1.08
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.0960 us/op 1.2250 us/op 0.89
mainnet_e58758 - phase0 afterProcessEpoch 34.351 ms/op 34.696 ms/op 0.99
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.4921 ms/op 1.0278 ms/op 1.45
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 2.0957 ms/op 1.6136 ms/op 1.30
altair processInactivityUpdates - 250000 normalcase 13.975 ms/op 13.053 ms/op 1.07
altair processInactivityUpdates - 250000 worstcase 13.058 ms/op 13.048 ms/op 1.00
phase0 processRegistryUpdates - 250000 normalcase 2.5840 us/op 2.4860 us/op 1.04
phase0 processRegistryUpdates - 250000 badcase_full_deposits 148.90 us/op 150.16 us/op 0.99
phase0 processRegistryUpdates - 250000 worstcase 0.5 63.360 ms/op 67.855 ms/op 0.93
altair processRewardsAndPenalties - 250000 normalcase 16.359 ms/op 15.755 ms/op 1.04
altair processRewardsAndPenalties - 250000 worstcase 17.588 ms/op 15.571 ms/op 1.13
phase0 getAttestationDeltas - 250000 normalcase 5.6172 ms/op 5.4271 ms/op 1.04
phase0 getAttestationDeltas - 250000 worstcase 5.7272 ms/op 5.1832 ms/op 1.10
phase0 processSlashings - 250000 worstcase 68.734 us/op 57.284 us/op 1.20
altair processSyncCommitteeUpdates - 250000 11.597 ms/op 9.8152 ms/op 1.18
BeaconState.hashTreeRoot - No change 181.00 ns/op 164.00 ns/op 1.10
BeaconState.hashTreeRoot - 1 full validator 87.228 us/op 78.554 us/op 1.11
BeaconState.hashTreeRoot - 32 full validator 961.87 us/op 1.0558 ms/op 0.91
BeaconState.hashTreeRoot - 512 full validator 9.6897 ms/op 7.1627 ms/op 1.35
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 104.98 us/op 95.201 us/op 1.10
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4672 ms/op 1.8481 ms/op 0.79
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 17.319 ms/op 15.770 ms/op 1.10
BeaconState.hashTreeRoot - 1 balances 75.835 us/op 77.121 us/op 0.98
BeaconState.hashTreeRoot - 32 balances 782.22 us/op 560.56 us/op 1.40
BeaconState.hashTreeRoot - 512 balances 6.3579 ms/op 5.6874 ms/op 1.12
BeaconState.hashTreeRoot - 250000 balances 143.96 ms/op 147.27 ms/op 0.98
aggregationBits - 2048 els - zipIndexesInBitList 21.469 us/op 19.248 us/op 1.12
regular array get 100000 times 23.503 us/op 22.165 us/op 1.06
wrappedArray get 100000 times 23.533 us/op 22.267 us/op 1.06
arrayWithProxy get 100000 times 14.884 ms/op 16.858 ms/op 0.88
ssz.Root.equals 21.893 ns/op 70.257 ns/op 0.31
byteArrayEquals 21.707 ns/op 21.583 ns/op 1.01
Buffer.compare 9.1700 ns/op 8.9600 ns/op 1.02
processSlot - 1 slots 10.991 us/op 9.6570 us/op 1.14
processSlot - 32 slots 2.3058 ms/op 2.0365 ms/op 1.13
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 5.5387 ms/op 4.7115 ms/op 1.18
getCommitteeAssignments - req 1 vs - 250000 vc 1.7148 ms/op 1.6888 ms/op 1.02
getCommitteeAssignments - req 100 vs - 250000 vc 3.4816 ms/op 3.4709 ms/op 1.00
getCommitteeAssignments - req 1000 vs - 250000 vc 3.7979 ms/op 3.7403 ms/op 1.02
findModifiedValidators - 10000 modified validators 944.97 ms/op 842.94 ms/op 1.12
findModifiedValidators - 1000 modified validators 614.56 ms/op 428.32 ms/op 1.43
findModifiedValidators - 100 modified validators 428.85 ms/op 288.07 ms/op 1.49
findModifiedValidators - 10 modified validators 297.87 ms/op 206.25 ms/op 1.44
findModifiedValidators - 1 modified validators 322.72 ms/op 183.53 ms/op 1.76
findModifiedValidators - no difference 241.89 ms/op 183.83 ms/op 1.32
migrate state 1500000 validators, 3400 modified, 2000 new 3.5783 s/op 3.7565 s/op 0.95
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.9000 ns/op 3.6300 ns/op 1.07
state getBlockRootAtSlot - 250000 vs - 7PWei 401.81 ns/op 452.66 ns/op 0.89
computeProposerIndex 100000 validators 1.3860 ms/op 1.3560 ms/op 1.02
getNextSyncCommitteeIndices 1000 validators 2.9620 ms/op 2.8965 ms/op 1.02
getNextSyncCommitteeIndices 10000 validators 25.839 ms/op 25.717 ms/op 1.00
getNextSyncCommitteeIndices 100000 validators 90.683 ms/op 88.903 ms/op 1.02
computeProposers - vc 250000 568.80 us/op 535.52 us/op 1.06
computeEpochShuffling - vc 250000 40.737 ms/op 39.669 ms/op 1.03
getNextSyncCommittee - vc 250000 9.8518 ms/op 9.2531 ms/op 1.06
nodejs block root to RootHex using toHex 95.366 ns/op 84.308 ns/op 1.13
nodejs block root to RootHex using toRootHex 58.738 ns/op 51.002 ns/op 1.15
nodejs fromHex(blob) 943.84 us/op 857.19 us/op 1.10
nodejs fromHexInto(blob) 639.18 us/op 612.46 us/op 1.04
nodejs block root to RootHex using the deprecated toHexString 513.11 ns/op 346.62 ns/op 1.48
nodejs byteArrayEquals 32 bytes (block root) 26.467 ns/op 25.303 ns/op 1.05
nodejs byteArrayEquals 48 bytes (pubkey) 38.262 ns/op 36.537 ns/op 1.05
nodejs byteArrayEquals 96 bytes (signature) 39.413 ns/op 32.751 ns/op 1.20
nodejs byteArrayEquals 1024 bytes 44.657 ns/op 39.358 ns/op 1.13
nodejs byteArrayEquals 131072 bytes (blob) 1.8120 us/op 1.7062 us/op 1.06
browser block root to RootHex using toHex 148.66 ns/op 140.13 ns/op 1.06
browser block root to RootHex using toRootHex 133.80 ns/op 129.31 ns/op 1.03
browser fromHex(blob) 1.6847 ms/op 1.6686 ms/op 1.01
browser fromHexInto(blob) 680.91 us/op 651.82 us/op 1.04
browser block root to RootHex using the deprecated toHexString 381.37 ns/op 500.17 ns/op 0.76
browser byteArrayEquals 32 bytes (block root) 28.844 ns/op 29.176 ns/op 0.99
browser byteArrayEquals 48 bytes (pubkey) 40.518 ns/op 40.920 ns/op 0.99
browser byteArrayEquals 96 bytes (signature) 75.500 ns/op 76.206 ns/op 0.99
browser byteArrayEquals 1024 bytes 767.74 ns/op 778.58 ns/op 0.99
browser byteArrayEquals 131072 bytes (blob) 97.312 us/op 98.550 us/op 0.99

by benchmarkbot/action

@twoeths twoeths marked this pull request as ready for review June 9, 2026 10:54
@twoeths twoeths requested a review from a team as a code owner June 9, 2026 10:54
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.59%. Comparing base (de5436c) to head (f98eb0d).
⚠️ Report is 5 commits behind head on unstable.

Additional details and impacted files
@@            Coverage Diff            @@
##           unstable    #9481   +/-   ##
=========================================
  Coverage     52.59%   52.59%           
=========================================
  Files           848      848           
  Lines         60890    60886    -4     
  Branches       4485     4485           
=========================================
- Hits          32023    32022    -1     
+ Misses        28805    28802    -3     
  Partials         62       62           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

nflaig
nflaig previously approved these changes Jun 9, 2026
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
nflaig
nflaig previously approved these changes Jun 9, 2026
Comment thread packages/beacon-node/src/metrics/metrics/lodestar.ts
@lodekeeper

Copy link
Copy Markdown
Contributor

Re Gemini's lodestar_payload_input_sync_source_total observation: already addressed — registered as register.counter<{source: BlockInputSource}> at packages/beacon-node/src/metrics/metrics/lodestar.ts:613, which is what Gemini suggested. Inline thread closed (discussion_r3380232625).

…resolution (#9488)

## Summary

- Restructures the "downloads the block and retries payload import when
EL reports block not in fork choice" test in `unknownBlock.test.ts` so
its `processBlock` mock no longer needs a `let emitter!:
ChainEventEmitter` definite-assignment assertion plus a
destructuring-assignment dance.
- That pattern caused tsgo's overload resolution to widen `emitter`'s
inferred type and fall back to the `EventEmitter` base overload
(expecting `unique symbol` event names) for the subsequent
`emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...)` site — surfaced
as the `TS2769` check-types failure on this PR's CI.

## Diagnosis

Failing job: `Type Checks (24)` → `packages/beacon-node check-types`.

```
test/unit/sync/unknownBlock.test.ts(1027,20): error TS2769: No overload matches this call.
  Argument of type 'ChainEvent.unknownEnvelopeBlockRoot' is not assignable to parameter of type 'unique symbol'.
```

The data shape is fine — `slot: 0` is already included at line 1024, and
the e2e at `unknownBlockSync.test.ts:236` also includes `slot:
headSlot`. The 5 other
`emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...)` sites in the
same file (lines 762/836/926/1079/1129) all typecheck fine because they
use plain `const {emitter} = setupPayloadSyncTest(...)` rather than `let
!` + destructuring-assignment.

## Fix

Declare `processBlock = vi.fn()` upfront, destructure `emitter` as a
`const`, then attach `processBlock.mockImplementation(...)` after
`setupPayloadSyncTest` returns. This matches the pattern used by every
other test in the file and removes the pattern that confused tsgo.

Safe because no event fires between `setupPayloadSyncTest` and the next
`emitter.emit(...)` — `processBlock` is never invoked before its
implementation is attached.

## Test plan

- [ ] CI: `Type Checks (24)` passes (no TS2769 on
`unknownBlock.test.ts`).
- [ ] CI: the "downloads the block and retries payload import when EL
reports block not in fork choice" unit test still passes (still asserts
`processBlock` called once, `processExecutionPayload` called twice).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: lodekeeper <lodekeeper@noreply.invalid>
@nflaig

nflaig commented Jun 9, 2026

Copy link
Copy Markdown
Member

@lodekeeper type checks are still failing

@lodekeeper

Copy link
Copy Markdown
Contributor

You're right — #9488's restructure removed the let ! pattern but tsgo still picks the wrong overload at the same site. Same TS2769 error on the current head (fda72f7). The remaining trigger is the sibling closure capture: processBlock's mock body emits routes.events.EventType.block which captures emitter, and that's enough to make tsgo lose the ChainEvent.X overload at the subsequent emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...).

Opened #9491 against this branch with the minimal cast workaround — (emitter as ChainEventEmitter).emit(ChainEvent.unknownEnvelopeBlockRoot, {...}) at the single failing site. The 5 other emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...) calls in the file remain untouched because they aren't reached through a sibling closure capture.

#9491

…verload (#9491)

## Summary

Follow-up to #9488 — the restructure removed the `let !` + destructuring
pattern but tsgo's overload-resolution miss persists at the same emit
site because `emitter` is also captured by a sibling closure (the
`processBlock` mock body that emits `routes.events.EventType.block`).
Same `TS2769` error reproduces on the current head:

```
test/unit/sync/unknownBlock.test.ts(1027,20): error TS2769: No overload matches this call.
  Argument of type 'ChainEvent.unknownEnvelopeBlockRoot' is not assignable to parameter of type 'unique symbol'.
```

## Fix

Cast `emitter` at the failing site to `ChainEventEmitter` to re-anchor
the `StrictEventEmitter` overload for `ChainEvent.X` keys. Minimal
change — single line cast at line 1023, with a comment explaining why.
The 5 other `emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...)`
sites in the file remain untouched because they aren't reached through a
sibling closure capture.

The previous restructure (now in the base branch) is still worth keeping
— it removed an unnecessary indirection — but it wasn't sufficient on
its own.

## Test plan

- [ ] CI: `Type Checks (24)` passes (no TS2769 on
`unknownBlock.test.ts`).
- [ ] CI: unit tests for the "downloads the block and retries payload
import when EL reports block not in fork choice" test still pass — emit
semantics unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
nflaig
nflaig previously approved these changes Jun 9, 2026
@nflaig nflaig enabled auto-merge (squash) June 9, 2026 12:30
@nflaig

nflaig commented Jun 9, 2026

Copy link
Copy Markdown
Member

@lodekeeper how did type check pass in #9491 but are failing here now? (see CI run)

@lodekeeper

Copy link
Copy Markdown
Contributor

It's a base-mismatch — #9491's CI passed Type Checks because its base was te/fix_block_input_sync_metrics_logs, so the synthetic merge GitHub creates for CI ran against the branch tip with no extra unstable context. This PR (#9481) bases on unstable, so its CI merges against current unstable HEAD (8d5a6a4), and te/fix_block_input_sync_metrics_logs is 6 commits behind unstable:

8d5a6a4 chore: update gossipsub to v16.0.2 (#9487)
fb3e80a feat: emit fast_confirmation SSE event per beacon-APIs (#9439)
407d8c5 fix: ensure block in forkchoice before validate by_root payload (#9479)
9666fc8 fix: remove TOO_MANY_SKIPPED_SLOTS block error (#9484)
3dd09a8 chore: track payload timing on dashboard (#9482)
1b4e24f chore: remove resolved todo about queuing payload envelopes (#9474)

The key one is #9439: it adds EventType.fastConfirmation to routes.events.EventType, which ApiEvents in ChainEventEmitter derives from — so IChainEvents's overload set expands when that commit is in scope. That's the new context tsgo's overload resolution sees in the synthetic merge that wasn't there for #9491's run. The cast (emitter as ChainEventEmitter) from #9491 is apparently not strong enough once the expanded ApiEvents is layered in.

Want me to push a stronger fix? Cleanest option I see is a locally-typed const emit: ChainEventEmitter["emit"] = emitter.emit.bind(emitter) (or equivalent) at the failing site so the StrictEventEmitter overload signature is bound explicitly before tsgo's overload pass — happy to open it as a PR against this branch if you'd rather not merge unstable in directly. Otherwise the GitHub "Update branch" button + a follow-up if CI flags the same site is the same end state.

@nflaig

nflaig commented Jun 9, 2026

Copy link
Copy Markdown
Member

@lodekeeper I updated the base branch, please revisit the changes and make sure type checks are passing now, open another PR if needed to apply fixes

@lodekeeper

Copy link
Copy Markdown
Contributor

Same pattern bit again — the merge brought in #9479's new test ("defers envelope validation until the block is in fork choice when payload input is seeded from the block body") which reuses the let emitter!: ChainEventEmitter + destructuring + sibling closure capture pattern that #9491 already mitigated for the existing failing site below. The original cast at the previous site (now at line 1126) still typechecks fine under the expanded EventType union from #9439 — only the newly-merged test's emit at line 1027 fires the same TS2769.

Also #9479's emit predates this PR's addition of slot: Slot to ChainEvent.unknownEnvelopeBlockRoot, so the data is missing the now-required slot field after the merge.

Opened #9492 against this branch with the same minimal cast + slot: 0:

-      emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {
+      (emitter as ChainEventEmitter).emit(ChainEvent.unknownEnvelopeBlockRoot, {
         rootHex: blockRootHex,
+        slot: 0,
         peer,
         source: BlockInputSource.gossip,
       });

#9492

…emit (#9492)

## Summary

The base-branch update brought in #9479's new test ("defers envelope
validation until the block is in fork choice when payload input is
seeded from the block body") which uses the same `let emitter!:
ChainEventEmitter` + destructuring-assignment + sibling closure capture
pattern that #9491 already mitigated in the original failing test below.
Same `TS2769` fires at the new test's emit site:

```
test/unit/sync/unknownBlock.test.ts(1027,20): error TS2769: No overload matches this call.
  Argument of type 'ChainEvent.unknownEnvelopeBlockRoot' is not assignable to parameter of type 'unique symbol'.
```

Also, #9479's emit predates this PR's addition of `slot: Slot` to the
`ChainEvent.unknownEnvelopeBlockRoot` event signature, so the emit data
is missing the required `slot` field after the merge.

## Fix

Same minimal cast workaround as #9491 plus the required `slot: 0` field:

```diff
-      emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, {
+      // tsgo overload-resolution miss when emit is reached through a closure that captures emitter
+      // first; cast re-anchors the StrictEventEmitter overload for ChainEvent keys (see #9491).
+      (emitter as ChainEventEmitter).emit(ChainEvent.unknownEnvelopeBlockRoot, {
         rootHex: blockRootHex,
+        slot: 0,
         peer,
         source: BlockInputSource.gossip,
       });
```

Single-site change. The 5 other
`emitter.emit(ChainEvent.unknownEnvelopeBlockRoot, ...)` sites in the
file remain unchanged because they aren't reached through a sibling
closure capture; the cast at the sibling test's emit (introduced in
#9491, currently at line 1126) also remains as-is and continues to
typecheck cleanly with the expanded `EventType` union from #9439.

## Test plan

- [ ] CI: `Type Checks (24)` passes (no TS2769 on
`unknownBlock.test.ts`).
- [ ] CI: the new `defers envelope validation until the block is in fork
choice when payload input is seeded from the block body` test still
passes — emit semantics unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
@nflaig nflaig merged commit b00d95d into unstable Jun 9, 2026
18 of 22 checks passed
@nflaig nflaig deleted the te/fix_block_input_sync_metrics_logs branch June 9, 2026 18:00
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.

3 participants