Skip to content

feat: produce proposer slashings from observed equivocations - #9787

Merged
matthewkeil merged 6 commits into
unstablefrom
nflaig/lazy-proposer-slasher
Aug 7, 2026
Merged

feat: produce proposer slashings from observed equivocations#9787
matthewkeil merged 6 commits into
unstablefrom
nflaig/lazy-proposer-slasher

Conversation

@nflaig

@nflaig nflaig commented Aug 7, 2026

Copy link
Copy Markdown
Member

Follow-up to #9757 that produces proposer slashings from observed proposer equivocations

  • store the signed block header alongside each observed block root, the root is derived from the header so no extra hashing
  • build a proposer slashing from the two conflicting headers when an equivocation is observed via gossip or block import
  • fully validate the slashing, add it to the local op pool for block inclusion and publish it on gossip
  • do not produce slashings from blocks only observed via the beacon api so an unpublished block cannot leak equivocation evidence
  • add focused seen cache and gossip validation tests

Verified on glamsterdam-devnet-7, a slashing was produced and broadcast 137ms after an adversarial equivocation was published and the validator got slashed

@chatgpt-codex-connector

This comment was marked as resolved.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Performance Report

鉁旓笍 no performance regression detected

Full benchmark results
Benchmark suite Current: 60e44de Previous: f0f5d06 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 932.12 us/op 1.0444 ms/op 0.89
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 41.219 us/op 38.093 us/op 1.08
BLS verify - blst 718.02 us/op 721.71 us/op 0.99
BLS verifyMultipleSignatures 3 - blst 1.3709 ms/op 1.3134 ms/op 1.04
BLS verifyMultipleSignatures 8 - blst 2.1960 ms/op 2.0736 ms/op 1.06
BLS verifyMultipleSignatures 32 - blst 6.9030 ms/op 6.5306 ms/op 1.06
BLS verifyMultipleSignatures 64 - blst 13.445 ms/op 12.641 ms/op 1.06
BLS verifyMultipleSignatures 128 - blst 26.197 ms/op 24.381 ms/op 1.07
BLS deserializing 10000 signatures 646.56 ms/op 615.27 ms/op 1.05
BLS deserializing 100000 signatures 6.5691 s/op 6.0781 s/op 1.08
BLS verifyMultipleSignatures - same message - 3 - blst 768.95 us/op 719.50 us/op 1.07
BLS verifyMultipleSignatures - same message - 8 - blst 942.73 us/op 877.89 us/op 1.07
BLS verifyMultipleSignatures - same message - 32 - blst 1.5829 ms/op 1.4575 ms/op 1.09
BLS verifyMultipleSignatures - same message - 64 - blst 2.3040 ms/op 2.1782 ms/op 1.06
BLS verifyMultipleSignatures - same message - 128 - blst 4.0863 ms/op 3.8590 ms/op 1.06
BLS aggregatePubkeys 32 - blst 17.925 us/op 16.781 us/op 1.07
BLS aggregatePubkeys 128 - blst 63.960 us/op 59.532 us/op 1.07
getSlashingsAndExits - default max 56.522 us/op 44.912 us/op 1.26
getSlashingsAndExits - 2k 424.86 us/op 350.37 us/op 1.21
proposeBlockBody type=full, size=empty 1.5515 ms/op 618.40 us/op 2.51
isKnown best case - 1 super set check 165.00 ns/op 157.00 ns/op 1.05
isKnown normal case - 2 super set checks 165.00 ns/op 157.00 ns/op 1.05
isKnown worse case - 16 super set checks 165.00 ns/op 158.00 ns/op 1.04
validate api signedAggregateAndProof - struct 1.5494 ms/op 1.4338 ms/op 1.08
validate gossip signedAggregateAndProof - struct 1.5497 ms/op 1.4290 ms/op 1.08
batch validate gossip attestation - vc 640000 - chunk 32 108.75 us/op 103.51 us/op 1.05
batch validate gossip attestation - vc 640000 - chunk 64 98.401 us/op 91.805 us/op 1.07
batch validate gossip attestation - vc 640000 - chunk 128 91.709 us/op 85.228 us/op 1.08
batch validate gossip attestation - vc 640000 - chunk 256 86.709 us/op 82.141 us/op 1.06
bytes32 toHexString 294.00 ns/op 271.00 ns/op 1.08
bytes32 Buffer.toString(hex) 167.00 ns/op 161.00 ns/op 1.04
bytes32 Buffer.toString(hex) from Uint8Array 245.00 ns/op 228.00 ns/op 1.07
bytes32 Buffer.toString(hex) + 0x 171.00 ns/op 163.00 ns/op 1.05
Return object 10000 times 0.21670 ns/op 0.20550 ns/op 1.05
Throw Error 10000 times 3.4168 us/op 3.1778 us/op 1.08
toHex 107.19 ns/op 89.631 ns/op 1.20
Buffer.from 88.892 ns/op 81.502 ns/op 1.09
shared Buffer 61.375 ns/op 55.884 ns/op 1.10
fastMsgIdFn sha256 / 200 bytes 1.5170 us/op 1.4100 us/op 1.08
fastMsgIdFn h32 xxhash / 200 bytes 158.00 ns/op 154.00 ns/op 1.03
fastMsgIdFn h64 xxhash / 200 bytes 200.00 ns/op 193.00 ns/op 1.04
fastMsgIdFn sha256 / 1000 bytes 4.8340 us/op 4.5550 us/op 1.06
fastMsgIdFn h32 xxhash / 1000 bytes 248.00 ns/op 236.00 ns/op 1.05
fastMsgIdFn h64 xxhash / 1000 bytes 254.00 ns/op 242.00 ns/op 1.05
fastMsgIdFn sha256 / 10000 bytes 42.722 us/op 40.035 us/op 1.07
fastMsgIdFn h32 xxhash / 10000 bytes 1.3000 us/op 1.2140 us/op 1.07
fastMsgIdFn h64 xxhash / 10000 bytes 844.00 ns/op 779.00 ns/op 1.08
send data - 1000 256B messages 4.3513 ms/op 4.1762 ms/op 1.04
send data - 1000 512B messages 5.3062 ms/op 5.7575 ms/op 0.92
send data - 1000 1024B messages 5.5444 ms/op 5.5711 ms/op 1.00
send data - 1000 1200B messages 6.5504 ms/op 6.3337 ms/op 1.03
send data - 1000 2048B messages 24.101 ms/op 16.516 ms/op 1.46
send data - 1000 4096B messages 23.754 ms/op 28.418 ms/op 0.84
send data - 1000 16384B messages 314.90 ms/op 130.32 ms/op 2.42
send data - 1000 65536B messages 1.4950 s/op 757.21 ms/op 1.97
enrSubnets - fastDeserialize 64 bits 783.00 ns/op 715.00 ns/op 1.10
enrSubnets - ssz BitVector 64 bits 268.00 ns/op 260.00 ns/op 1.03
enrSubnets - fastDeserialize 4 bits 103.00 ns/op 100.00 ns/op 1.03
enrSubnets - ssz BitVector 4 bits 427.00 ns/op 254.00 ns/op 1.68
prioritizePeers score -10:0 att 32-0.1 sync 2-0 216.05 us/op 193.48 us/op 1.12
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 249.02 us/op 221.17 us/op 1.13
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 382.70 us/op 320.76 us/op 1.19
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 613.32 us/op 565.53 us/op 1.08
prioritizePeers score 0:0 att 64-1 sync 4-1 757.38 us/op 666.10 us/op 1.14
array of 16000 items push then shift 1.3269 us/op 1.2077 us/op 1.10
LinkedList of 16000 items push then shift 7.7030 ns/op 7.1320 ns/op 1.08
array of 16000 items push then pop 73.336 ns/op 62.966 ns/op 1.16
LinkedList of 16000 items push then pop 6.1930 ns/op 5.7190 ns/op 1.08
array of 24000 items push then shift 1.9600 us/op 1.7741 us/op 1.10
LinkedList of 24000 items push then shift 7.2780 ns/op 6.8390 ns/op 1.06
array of 24000 items push then pop 102.50 ns/op 87.807 ns/op 1.17
LinkedList of 24000 items push then pop 6.1680 ns/op 5.7870 ns/op 1.07
intersect bitArray bitLen 8 3.9410 ns/op 3.8810 ns/op 1.02
intersect array and set length 8 30.039 ns/op 27.903 ns/op 1.08
intersect bitArray bitLen 128 23.683 ns/op 22.732 ns/op 1.04
intersect array and set length 128 510.94 ns/op 473.67 ns/op 1.08
bitArray.getTrueBitIndexes() bitLen 128 956.00 ns/op 892.00 ns/op 1.07
bitArray.getTrueBitIndexes() bitLen 248 1.7200 us/op 1.6250 us/op 1.06
bitArray.getTrueBitIndexes() bitLen 512 3.7410 us/op 3.3550 us/op 1.12
Full columns - reconstruct all 6 blobs 133.45 us/op 222.56 us/op 0.60
Full columns - reconstruct half of the blobs out of 6 94.100 us/op 70.747 us/op 1.33
Full columns - reconstruct single blob out of 6 33.879 us/op 28.841 us/op 1.17
Half columns - reconstruct all 6 blobs 408.97 ms/op 370.19 ms/op 1.10
Half columns - reconstruct half of the blobs out of 6 199.47 ms/op 186.49 ms/op 1.07
Half columns - reconstruct single blob out of 6 70.433 ms/op 65.721 ms/op 1.07
Set add up to 64 items then delete first 1.6774 us/op 1.5548 us/op 1.08
OrderedSet add up to 64 items then delete first 2.5791 us/op 2.4044 us/op 1.07
Set add up to 64 items then delete last 1.9110 us/op 1.8089 us/op 1.06
OrderedSet add up to 64 items then delete last 2.8977 us/op 2.6645 us/op 1.09
Set add up to 64 items then delete middle 1.9001 us/op 1.7846 us/op 1.06
OrderedSet add up to 64 items then delete middle 4.3626 us/op 4.0611 us/op 1.07
Set add up to 128 items then delete first 3.8299 us/op 3.7077 us/op 1.03
OrderedSet add up to 128 items then delete first 5.9080 us/op 5.4468 us/op 1.08
Set add up to 128 items then delete last 3.7099 us/op 3.4637 us/op 1.07
OrderedSet add up to 128 items then delete last 5.4702 us/op 5.0893 us/op 1.07
Set add up to 128 items then delete middle 3.7163 us/op 3.4542 us/op 1.08
OrderedSet add up to 128 items then delete middle 11.481 us/op 10.913 us/op 1.05
Set add up to 256 items then delete first 7.5000 us/op 7.1842 us/op 1.04
OrderedSet add up to 256 items then delete first 12.013 us/op 11.306 us/op 1.06
Set add up to 256 items then delete last 7.3167 us/op 6.9262 us/op 1.06
OrderedSet add up to 256 items then delete last 11.282 us/op 10.705 us/op 1.05
Set add up to 256 items then delete middle 7.2432 us/op 7.0138 us/op 1.03
OrderedSet add up to 256 items then delete middle 35.708 us/op 33.342 us/op 1.07
runFastConfirmationRules vc:100000 bc:96 eq:0 4.8284 ms/op 4.2737 ms/op 1.13
runFastConfirmationRules vc:600000 bc:96 eq:0 35.972 ms/op 32.513 ms/op 1.11
runFastConfirmationRules vc:1000000 bc:96 eq:0 60.397 ms/op 54.980 ms/op 1.10
runFastConfirmationRules vc:600000 bc:320 eq:0 37.627 ms/op 33.289 ms/op 1.13
runFastConfirmationRules vc:100000 bc:96 eq:1000 1.2383 s/op 1.0525 s/op 1.18
pass gossip attestations to forkchoice per slot 3.0745 ms/op 2.5127 ms/op 1.22
forkChoice updateHead vc 100000 bc 64 eq 0 428.43 us/op 390.14 us/op 1.10
forkChoice updateHead vc 600000 bc 64 eq 0 2.5285 ms/op 2.3072 ms/op 1.10
forkChoice updateHead vc 1000000 bc 64 eq 0 4.1878 ms/op 3.8801 ms/op 1.08
forkChoice updateHead vc 600000 bc 320 eq 0 2.5265 ms/op 2.3481 ms/op 1.08
forkChoice updateHead vc 600000 bc 1200 eq 0 2.5970 ms/op 2.3718 ms/op 1.09
forkChoice updateHead vc 600000 bc 7200 eq 0 2.9565 ms/op 2.6638 ms/op 1.11
forkChoice updateHead vc 600000 bc 64 eq 1000 2.6185 ms/op 2.3388 ms/op 1.12
forkChoice updateHead vc 600000 bc 64 eq 10000 2.5867 ms/op 2.4208 ms/op 1.07
forkChoice updateHead vc 600000 bc 64 eq 300000 6.8139 ms/op 6.1352 ms/op 1.11
computeDeltas 1400000 validators 0% inactive 12.533 ms/op 11.579 ms/op 1.08
computeDeltas 1400000 validators 10% inactive 11.972 ms/op 11.033 ms/op 1.09
computeDeltas 1400000 validators 20% inactive 11.347 ms/op 10.393 ms/op 1.09
computeDeltas 1400000 validators 50% inactive 9.0425 ms/op 8.4998 ms/op 1.06
computeDeltas 2100000 validators 0% inactive 18.937 ms/op 17.511 ms/op 1.08
computeDeltas 2100000 validators 10% inactive 17.871 ms/op 16.527 ms/op 1.08
computeDeltas 2100000 validators 20% inactive 17.163 ms/op 15.580 ms/op 1.10
computeDeltas 2100000 validators 50% inactive 11.110 ms/op 11.240 ms/op 0.99
altair processAttestation - 250000 vs - 7PWei normalcase 2.2308 ms/op 1.8175 ms/op 1.23
altair processAttestation - 250000 vs - 7PWei worstcase 2.6606 ms/op 2.5503 ms/op 1.04
altair processAttestation - setStatus - 1/6 committees join 101.87 us/op 100.79 us/op 1.01
altair processAttestation - setStatus - 1/3 committees join 201.41 us/op 194.38 us/op 1.04
altair processAttestation - setStatus - 1/2 committees join 288.17 us/op 264.12 us/op 1.09
altair processAttestation - setStatus - 2/3 committees join 374.47 us/op 349.33 us/op 1.07
altair processAttestation - setStatus - 4/5 committees join 519.50 us/op 493.55 us/op 1.05
altair processAttestation - setStatus - 100% committees join 632.78 us/op 575.14 us/op 1.10
altair processBlock - 250000 vs - 7PWei normalcase 3.7050 ms/op 3.7974 ms/op 0.98
altair processBlock - 250000 vs - 7PWei normalcase hashState 13.391 ms/op 15.703 ms/op 0.85
altair processBlock - 250000 vs - 7PWei worstcase 21.841 ms/op 20.946 ms/op 1.04
altair processBlock - 250000 vs - 7PWei worstcase hashState 42.671 ms/op 49.506 ms/op 0.86
phase0 processBlock - 250000 vs - 7PWei normalcase 1.3603 ms/op 1.3485 ms/op 1.01
phase0 processBlock - 250000 vs - 7PWei worstcase 17.872 ms/op 16.723 ms/op 1.07
altair processEth1Data - 250000 vs - 7PWei normalcase 294.82 us/op 275.32 us/op 1.07
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 4.1860 us/op 4.2440 us/op 0.99
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 21.003 us/op 20.158 us/op 1.04
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.7690 us/op 6.8870 us/op 0.84
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 4.7470 us/op 4.1640 us/op 1.14
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 91.917 us/op 88.704 us/op 1.04
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3896 ms/op 1.3320 ms/op 1.04
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.8463 ms/op 1.7850 ms/op 1.03
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.8354 ms/op 1.7811 ms/op 1.03
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.7642 ms/op 3.5180 ms/op 1.07
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.1205 ms/op 2.1682 ms/op 0.98
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.9783 ms/op 4.3227 ms/op 0.92
Tree 40 250000 create 327.30 ms/op 319.97 ms/op 1.02
Tree 40 250000 get(125000) 97.329 ns/op 90.803 ns/op 1.07
Tree 40 250000 set(125000) 1.0327 us/op 978.68 ns/op 1.06
Tree 40 250000 toArray() 10.392 ms/op 13.588 ms/op 0.76
Tree 40 250000 iterate all - toArray() + loop 10.213 ms/op 13.753 ms/op 0.74
Tree 40 250000 iterate all - get(i) 39.644 ms/op 37.885 ms/op 1.05
Array 250000 create 2.3206 ms/op 2.1859 ms/op 1.06
Array 250000 clone - spread 706.95 us/op 688.74 us/op 1.03
Array 250000 get(125000) 0.30300 ns/op 0.28800 ns/op 1.05
Array 250000 set(125000) 0.30700 ns/op 0.29300 ns/op 1.05
Array 250000 iterate all - loop 58.446 us/op 56.932 us/op 1.03
phase0 afterProcessEpoch - 250000 vs - 7PWei 41.725 ms/op 39.746 ms/op 1.05
Array.fill - length 1000000 2.4963 ms/op 2.1314 ms/op 1.17
Array push - length 1000000 9.7383 ms/op 10.236 ms/op 0.95
Array.get 0.21191 ns/op 0.19961 ns/op 1.06
Uint8Array.get 0.25149 ns/op 0.22113 ns/op 1.14
phase0 beforeProcessEpoch - 250000 vs - 7PWei 21.073 ms/op 14.432 ms/op 1.46
altair processEpoch - mainnet_e81889 288.55 ms/op 272.56 ms/op 1.06
mainnet_e81889 - altair beforeProcessEpoch 21.717 ms/op 15.074 ms/op 1.44
mainnet_e81889 - altair processJustificationAndFinalization 6.6910 us/op 6.0520 us/op 1.11
mainnet_e81889 - altair processInactivityUpdates 3.5843 ms/op 3.5547 ms/op 1.01
mainnet_e81889 - altair processRewardsAndPenalties 20.393 ms/op 19.705 ms/op 1.03
mainnet_e81889 - altair processRegistryUpdates 587.00 ns/op 544.00 ns/op 1.08
mainnet_e81889 - altair processSlashings 144.00 ns/op 136.00 ns/op 1.06
mainnet_e81889 - altair processEth1DataReset 142.00 ns/op 132.00 ns/op 1.08
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.4468 ms/op 1.3038 ms/op 1.11
mainnet_e81889 - altair processSlashingsReset 727.00 ns/op 676.00 ns/op 1.08
mainnet_e81889 - altair processRandaoMixesReset 1.4000 us/op 1.1590 us/op 1.21
mainnet_e81889 - altair processHistoricalRootsUpdate 143.00 ns/op 132.00 ns/op 1.08
mainnet_e81889 - altair processParticipationFlagUpdates 459.00 ns/op 420.00 ns/op 1.09
mainnet_e81889 - altair processSyncCommitteeUpdates 114.00 ns/op 106.00 ns/op 1.08
mainnet_e81889 - altair afterProcessEpoch 42.464 ms/op 39.699 ms/op 1.07
capella processEpoch - mainnet_e217614 809.92 ms/op 825.63 ms/op 0.98
mainnet_e217614 - capella beforeProcessEpoch 57.628 ms/op 56.525 ms/op 1.02
mainnet_e217614 - capella processJustificationAndFinalization 6.5970 us/op 6.4250 us/op 1.03
mainnet_e217614 - capella processInactivityUpdates 14.519 ms/op 14.529 ms/op 1.00
mainnet_e217614 - capella processRewardsAndPenalties 94.412 ms/op 90.714 ms/op 1.04
mainnet_e217614 - capella processRegistryUpdates 4.6530 us/op 4.4960 us/op 1.03
mainnet_e217614 - capella processSlashings 144.00 ns/op 137.00 ns/op 1.05
mainnet_e217614 - capella processEth1DataReset 141.00 ns/op 136.00 ns/op 1.04
mainnet_e217614 - capella processEffectiveBalanceUpdates 12.961 ms/op 15.401 ms/op 0.84
mainnet_e217614 - capella processSlashingsReset 714.00 ns/op 663.00 ns/op 1.08
mainnet_e217614 - capella processRandaoMixesReset 1.3580 us/op 1.2550 us/op 1.08
mainnet_e217614 - capella processHistoricalRootsUpdate 145.00 ns/op 134.00 ns/op 1.08
mainnet_e217614 - capella processParticipationFlagUpdates 460.00 ns/op 427.00 ns/op 1.08
mainnet_e217614 - capella afterProcessEpoch 115.41 ms/op 106.83 ms/op 1.08
phase0 processEpoch - mainnet_e58758 303.27 ms/op 321.21 ms/op 0.94
mainnet_e58758 - phase0 beforeProcessEpoch 61.645 ms/op 71.514 ms/op 0.86
mainnet_e58758 - phase0 processJustificationAndFinalization 6.4560 us/op 6.6500 us/op 0.97
mainnet_e58758 - phase0 processRewardsAndPenalties 16.753 ms/op 16.748 ms/op 1.00
mainnet_e58758 - phase0 processRegistryUpdates 2.3230 us/op 2.2260 us/op 1.04
mainnet_e58758 - phase0 processSlashings 144.00 ns/op 142.00 ns/op 1.01
mainnet_e58758 - phase0 processEth1DataReset 141.00 ns/op 135.00 ns/op 1.04
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 850.48 us/op 915.05 us/op 0.93
mainnet_e58758 - phase0 processSlashingsReset 893.00 ns/op 879.00 ns/op 1.02
mainnet_e58758 - phase0 processRandaoMixesReset 1.2470 us/op 1.2140 us/op 1.03
mainnet_e58758 - phase0 processHistoricalRootsUpdate 141.00 ns/op 134.00 ns/op 1.05
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.1340 us/op 1.0760 us/op 1.05
mainnet_e58758 - phase0 afterProcessEpoch 33.434 ms/op 33.572 ms/op 1.00
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.0129 ms/op 982.20 us/op 1.03
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.7102 ms/op 1.5866 ms/op 1.08
altair processInactivityUpdates - 250000 normalcase 11.621 ms/op 10.671 ms/op 1.09
altair processInactivityUpdates - 250000 worstcase 11.419 ms/op 10.891 ms/op 1.05
phase0 processRegistryUpdates - 250000 normalcase 2.5000 us/op 2.0920 us/op 1.20
phase0 processRegistryUpdates - 250000 badcase_full_deposits 152.62 us/op 129.81 us/op 1.18
phase0 processRegistryUpdates - 250000 worstcase 0.5 88.020 ms/op 56.210 ms/op 1.57
altair processRewardsAndPenalties - 250000 normalcase 17.041 ms/op 14.736 ms/op 1.16
altair processRewardsAndPenalties - 250000 worstcase 16.750 ms/op 14.960 ms/op 1.12
phase0 getAttestationDeltas - 250000 normalcase 5.5029 ms/op 5.3317 ms/op 1.03
phase0 getAttestationDeltas - 250000 worstcase 5.4882 ms/op 5.3513 ms/op 1.03
phase0 processSlashings - 250000 worstcase 61.325 us/op 59.616 us/op 1.03
altair processSyncCommitteeUpdates - 250000 10.189 ms/op 9.6225 ms/op 1.06
BeaconState.hashTreeRoot - No change 176.00 ns/op 165.00 ns/op 1.07
BeaconState.hashTreeRoot - 1 full validator 66.256 us/op 73.658 us/op 0.90
BeaconState.hashTreeRoot - 32 full validator 764.45 us/op 763.87 us/op 1.00
BeaconState.hashTreeRoot - 512 full validator 6.0886 ms/op 7.1359 ms/op 0.85
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 77.279 us/op 86.998 us/op 0.89
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.1413 ms/op 1.3692 ms/op 0.83
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 13.674 ms/op 15.108 ms/op 0.91
BeaconState.hashTreeRoot - 1 balances 68.388 us/op 74.911 us/op 0.91
BeaconState.hashTreeRoot - 32 balances 680.15 us/op 728.76 us/op 0.93
BeaconState.hashTreeRoot - 512 balances 4.8122 ms/op 4.9646 ms/op 0.97
BeaconState.hashTreeRoot - 250000 balances 120.24 ms/op 119.44 ms/op 1.01
aggregationBits - 2048 els - zipIndexesInBitList 19.951 us/op 19.090 us/op 1.05
regular array get 100000 times 23.454 us/op 22.234 us/op 1.05
wrappedArray get 100000 times 23.334 us/op 22.190 us/op 1.05
arrayWithProxy get 100000 times 10.382 ms/op 12.014 ms/op 0.86
ssz.Root.equals 21.578 ns/op 20.579 ns/op 1.05
byteArrayEquals 21.376 ns/op 20.399 ns/op 1.05
Buffer.compare 8.9380 ns/op 8.5010 ns/op 1.05
processSlot - 1 slots 8.1780 us/op 8.7200 us/op 0.94
processSlot - 32 slots 1.8239 ms/op 2.1931 ms/op 0.83
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 3.7479 ms/op 4.4191 ms/op 0.85
getCommitteeAssignments - req 1 vs - 250000 vc 1.6549 ms/op 1.6046 ms/op 1.03
getCommitteeAssignments - req 100 vs - 250000 vc 3.4381 ms/op 3.3175 ms/op 1.04
getCommitteeAssignments - req 1000 vs - 250000 vc 3.6701 ms/op 3.5825 ms/op 1.02
findModifiedValidators - 10000 modified validators 756.16 ms/op 758.03 ms/op 1.00
findModifiedValidators - 1000 modified validators 516.71 ms/op 586.49 ms/op 0.88
findModifiedValidators - 100 modified validators 357.39 ms/op 285.94 ms/op 1.25
findModifiedValidators - 10 modified validators 250.16 ms/op 252.33 ms/op 0.99
findModifiedValidators - 1 modified validators 158.98 ms/op 144.88 ms/op 1.10
findModifiedValidators - no difference 145.12 ms/op 169.61 ms/op 0.86
migrate state 1500000 validators, 3400 modified, 2000 new 2.6543 s/op 2.9785 s/op 0.89
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.7000 ns/op 3.5600 ns/op 1.04
state getBlockRootAtSlot - 250000 vs - 7PWei 286.15 ns/op 347.05 ns/op 0.82
computeProposerIndex 100000 validators 1.3543 ms/op 1.2806 ms/op 1.06
getNextSyncCommitteeIndices 1000 validators 2.8808 ms/op 2.7510 ms/op 1.05
getNextSyncCommitteeIndices 10000 validators 25.691 ms/op 24.103 ms/op 1.07
getNextSyncCommitteeIndices 100000 validators 87.641 ms/op 84.584 ms/op 1.04
computeProposers - vc 250000 551.64 us/op 528.83 us/op 1.04
computeEpochShuffling - vc 250000 40.966 ms/op 38.704 ms/op 1.06
getNextSyncCommittee - vc 250000 9.5180 ms/op 9.1642 ms/op 1.04
nodejs block root to RootHex using toHex 99.702 ns/op 90.065 ns/op 1.11
nodejs block root to RootHex using toRootHex 65.081 ns/op 59.296 ns/op 1.10
nodejs fromHex(blob) 850.02 us/op 725.44 us/op 1.17
nodejs fromHexInto(blob) 662.10 us/op 597.78 us/op 1.11
nodejs block root to RootHex using the deprecated toHexString 491.23 ns/op 448.40 ns/op 1.10
nodejs byteArrayEquals 32 bytes (block root) 25.952 ns/op 24.834 ns/op 1.05
nodejs byteArrayEquals 48 bytes (pubkey) 37.675 ns/op 35.968 ns/op 1.05
nodejs byteArrayEquals 96 bytes (signature) 39.103 ns/op 33.392 ns/op 1.17
nodejs byteArrayEquals 1024 bytes 46.774 ns/op 40.255 ns/op 1.16
nodejs byteArrayEquals 131072 bytes (blob) 1.7633 us/op 1.7085 us/op 1.03
browser block root to RootHex using toHex 145.39 ns/op 138.12 ns/op 1.05
browser block root to RootHex using toRootHex 130.41 ns/op 125.17 ns/op 1.04
browser fromHex(blob) 1.5871 ms/op 1.4928 ms/op 1.06
browser fromHexInto(blob) 656.00 us/op 602.74 us/op 1.09
browser block root to RootHex using the deprecated toHexString 345.35 ns/op 444.28 ns/op 0.78
browser byteArrayEquals 32 bytes (block root) 28.114 ns/op 26.873 ns/op 1.05
browser byteArrayEquals 48 bytes (pubkey) 39.581 ns/op 37.985 ns/op 1.04
browser byteArrayEquals 96 bytes (signature) 74.213 ns/op 70.741 ns/op 1.05
browser byteArrayEquals 1024 bytes 774.93 ns/op 720.57 ns/op 1.08
browser byteArrayEquals 131072 bytes (blob) 96.487 us/op 90.832 us/op 1.06

by benchmarkbot/action

wemeetagain
wemeetagain previously approved these changes Aug 7, 2026
this.emitter.emit(routes.events.EventType.proposerSlashing, proposerSlashing);
this.emitter.emit(ChainEvent.publishProposerSlashing, proposerSlashing);
this.metrics?.opPool.proposerSlashingsProduced.inc();
this.logger.info("Produced proposer slashing from observed equivocation", {slot: blockSlot, proposerIndex});

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.

could consider using verbose here, but this is a really rare event anyways

Comment thread packages/beacon-node/src/network/network.ts Outdated
Co-authored-by: Nico Flaig <nflaig@protonmail.com>
Comment thread packages/beacon-node/src/chain/chain.ts Outdated

@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, self-review

@matthewkeil
matthewkeil enabled auto-merge (squash) August 7, 2026 15:05
@matthewkeil
matthewkeil merged commit f0f5d06 into unstable Aug 7, 2026
18 of 20 checks passed
@matthewkeil
matthewkeil deleted the nflaig/lazy-proposer-slasher branch August 7, 2026 15:05
nflaig added a commit that referenced this pull request Aug 7, 2026
)

Follow-up to #9787 that adds a debug log when proposer slashing
production is skipped because a slashing for the proposer is already
known

Without this the skip is silent and it is not possible to tell from logs
whether a node observed an equivocation and lost the production race to
another node or never detected it at all
return;
}

this.producingProposerSlashing.add(proposerIndex);

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.

would be great to log header roots here

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.

// Only produce a slashing while importing the block. A block that is verified before it is published
// must not be treated as equivocation evidence since it may never be seen by the network
if (opts.verifyOnly !== true && this.seenBlockProposers.isEquivocating(slot, proposerIndex)) {
this.processProposerEquivocation(slot, proposerIndex);

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.

wrap in callInNextEventLoop()?
this feels like a follow up task, not the main thing of this verifyBlock flow

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.

yeah this might be good, I don't think it's a lot of work to create the slashing but it doesn't need to be produced timely at all, ideally the next proposer receives it in-time but that should be the case most of the time, wrapped inside of callInNextEventLoop() in #9795

twoeths pushed a commit that referenced this pull request Aug 11, 2026
Follow-up to #9757 and #9787 based on @twoeths' comments

- remove `skipVerifyBlockSignatures` and always verify block signatures
- reuse the block input root when recording observed proposals
- defer proposer slashing production to the next event loop
- log both conflicting block header roots
- clarify the equivocation root-count constant name
@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

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants