Skip to content

chore: implement forkchoice debug endpoint v2#9444

Merged
wemeetagain merged 3 commits into
unstablefrom
te/enhance_fc_debug_endpoint
Jun 2, 2026
Merged

chore: implement forkchoice debug endpoint v2#9444
wemeetagain merged 3 commits into
unstablefrom
te/enhance_fc_debug_endpoint

Conversation

@twoeths

@twoeths twoeths commented Jun 2, 2026

Copy link
Copy Markdown
Member

Motivation

Description

  • sample EMPTY node
{
  "payload_status": "empty",
  "slot": "9",
  "block_root": "0x37d931610a0f4ff0ec7a4057f9905799e459a75fe49c76f258d5e11d47d1d79c",
  "parent_root": "0x2301a10ddc86d8cea5bbb05d0aa0dca8823123d3bfa6c2f8a7a6ff4450636d6e",
  "weight": "0",
  "validity": "valid",
  "execution_block_hash": "0xbbc1f010c338817286e384fcc129b96885d63619e206ce2729969f135252b81d",
  "extra_data": {
    "execution_optimistic": false,
    "timestamp": "1780386554",
    "target": "0x2301a10ddc86d8cea5bbb05d0aa0dca8823123d3bfa6c2f8a7a6ff4450636d6e",
    "justified_epoch": "0",
    "finalized_epoch": "0",
    "unrealized_justified_epoch": "0",
    "unrealized_finalized_epoch": "0",
    "payload_attester_count": null,
    "payload_availability_yes_count": null,
    "payload_data_availability_yes_count": null,
    "gas_limit": null
  }
}
  • sample FULL node
{
  "payload_status": "full",
  "slot": "9",
  "block_root": "0x37d931610a0f4ff0ec7a4057f9905799e459a75fe49c76f258d5e11d47d1d79c",
  "parent_root": "0x2301a10ddc86d8cea5bbb05d0aa0dca8823123d3bfa6c2f8a7a6ff4450636d6e",
  "weight": "44",
  "validity": "valid",
  "execution_block_hash": "0xec7766e17b1df22a82a447d97c457301c4b6be3b66928d13c87224dc3bc0ab76",
  "extra_data": {
    "execution_optimistic": false,
    "timestamp": "1780386554",
    "target": "0x2301a10ddc86d8cea5bbb05d0aa0dca8823123d3bfa6c2f8a7a6ff4450636d6e",
    "justified_epoch": "0",
    "finalized_epoch": "0",
    "unrealized_justified_epoch": "0",
    "unrealized_finalized_epoch": "0",
    "payload_attester_count": "16",
    "payload_availability_yes_count": "16",
    "payload_data_availability_yes_count": "16",
    "gas_limit": "30000000"
  }
}

Testing

  • node ./bin/lodestar.js dev --genesisValidators 8 --startValidators 0..7 --params.GLOAS_FORK_EPOCH 1 --enr.ip 127.0.0.1 --dataDir .lodestar/gloas-node --reset --rest --rest.namespace '*' --metrics
  • curl http://localhost:9596/eth/v2/debug/fork_choice

AI Assistance Disclosure

  • Created with the help ofClaude

@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 /eth/v2/debug/fork_choice endpoint (getDebugForkChoiceV2) to retrieve the current fork choice context, including Payload Timeliness Committee (PTC) vote tallies and unrealized checkpoints. It adds the necessary SSZ container types, implements the API handler, and extends ForkChoice and ProtoArray to support retrieving PTC vote counts. Feedback on the implementation suggests correcting the gasLimit logic, which currently returns null for pre-Gloas blocks despite them being FULL blocks with valid gas limits, by directly checking the node's payload status.

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/debug/index.ts Outdated
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: f04ffce Previous: 86fc005 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 890.22 us/op 882.97 us/op 1.01
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 40.309 us/op 37.518 us/op 1.07
BLS verify - blst 752.60 us/op 725.96 us/op 1.04
BLS verifyMultipleSignatures 3 - blst 1.3678 ms/op 1.3111 ms/op 1.04
BLS verifyMultipleSignatures 8 - blst 2.1864 ms/op 2.0750 ms/op 1.05
BLS verifyMultipleSignatures 32 - blst 6.8803 ms/op 6.4218 ms/op 1.07
BLS verifyMultipleSignatures 64 - blst 13.813 ms/op 12.441 ms/op 1.11
BLS verifyMultipleSignatures 128 - blst 25.999 ms/op 24.207 ms/op 1.07
BLS deserializing 10000 signatures 634.10 ms/op 618.87 ms/op 1.02
BLS deserializing 100000 signatures 6.5155 s/op 6.2186 s/op 1.05
BLS verifyMultipleSignatures - same message - 3 - blst 807.95 us/op 708.40 us/op 1.14
BLS verifyMultipleSignatures - same message - 8 - blst 961.05 us/op 894.08 us/op 1.07
BLS verifyMultipleSignatures - same message - 32 - blst 1.5714 ms/op 1.5043 ms/op 1.04
BLS verifyMultipleSignatures - same message - 64 - blst 2.5093 ms/op 2.3882 ms/op 1.05
BLS verifyMultipleSignatures - same message - 128 - blst 4.1811 ms/op 4.0176 ms/op 1.04
BLS aggregatePubkeys 32 - blst 18.054 us/op 17.635 us/op 1.02
BLS aggregatePubkeys 128 - blst 64.378 us/op 62.432 us/op 1.03
getSlashingsAndExits - default max 50.478 us/op 44.699 us/op 1.13
getSlashingsAndExits - 2k 357.82 us/op 330.30 us/op 1.08
proposeBlockBody type=full, size=empty 1.0681 ms/op 569.46 us/op 1.88
isKnown best case - 1 super set check 175.00 ns/op 163.00 ns/op 1.07
isKnown normal case - 2 super set checks 188.00 ns/op 162.00 ns/op 1.16
isKnown worse case - 16 super set checks 173.00 ns/op 158.00 ns/op 1.09
validate api signedAggregateAndProof - struct 1.5693 ms/op 1.4571 ms/op 1.08
validate gossip signedAggregateAndProof - struct 1.5548 ms/op 1.4486 ms/op 1.07
batch validate gossip attestation - vc 640000 - chunk 32 112.43 us/op 106.94 us/op 1.05
batch validate gossip attestation - vc 640000 - chunk 64 96.391 us/op 91.116 us/op 1.06
batch validate gossip attestation - vc 640000 - chunk 128 91.174 us/op 84.741 us/op 1.08
batch validate gossip attestation - vc 640000 - chunk 256 91.409 us/op 83.243 us/op 1.10
bytes32 toHexString 296.00 ns/op 279.00 ns/op 1.06
bytes32 Buffer.toString(hex) 173.00 ns/op 159.00 ns/op 1.09
bytes32 Buffer.toString(hex) from Uint8Array 230.00 ns/op 231.00 ns/op 1.00
bytes32 Buffer.toString(hex) + 0x 175.00 ns/op 153.00 ns/op 1.14
Return object 10000 times 0.22080 ns/op 0.20750 ns/op 1.06
Throw Error 10000 times 3.5033 us/op 3.3031 us/op 1.06
toHex 102.32 ns/op 85.828 ns/op 1.19
Buffer.from 85.715 ns/op 76.528 ns/op 1.12
shared Buffer 55.195 ns/op 50.019 ns/op 1.10
fastMsgIdFn sha256 / 200 bytes 1.4960 us/op 1.4550 us/op 1.03
fastMsgIdFn h32 xxhash / 200 bytes 162.00 ns/op 163.00 ns/op 0.99
fastMsgIdFn h64 xxhash / 200 bytes 207.00 ns/op 214.00 ns/op 0.97
fastMsgIdFn sha256 / 1000 bytes 4.8790 us/op 4.6380 us/op 1.05
fastMsgIdFn h32 xxhash / 1000 bytes 257.00 ns/op 247.00 ns/op 1.04
fastMsgIdFn h64 xxhash / 1000 bytes 258.00 ns/op 262.00 ns/op 0.98
fastMsgIdFn sha256 / 10000 bytes 43.206 us/op 40.660 us/op 1.06
fastMsgIdFn h32 xxhash / 10000 bytes 1.3230 us/op 1.2520 us/op 1.06
fastMsgIdFn h64 xxhash / 10000 bytes 851.00 ns/op 819.00 ns/op 1.04
send data - 1000 256B messages 4.5473 ms/op 4.2340 ms/op 1.07
send data - 1000 512B messages 4.5012 ms/op 4.3021 ms/op 1.05
send data - 1000 1024B messages 4.7287 ms/op 4.7742 ms/op 0.99
send data - 1000 1200B messages 5.1604 ms/op 4.4187 ms/op 1.17
send data - 1000 2048B messages 5.3592 ms/op 4.5431 ms/op 1.18
send data - 1000 4096B messages 5.9801 ms/op 5.6197 ms/op 1.06
send data - 1000 16384B messages 34.235 ms/op 19.497 ms/op 1.76
send data - 1000 65536B messages 179.85 ms/op 139.35 ms/op 1.29
enrSubnets - fastDeserialize 64 bits 821.00 ns/op 747.00 ns/op 1.10
enrSubnets - ssz BitVector 64 bits 284.00 ns/op 260.00 ns/op 1.09
enrSubnets - fastDeserialize 4 bits 107.00 ns/op 103.00 ns/op 1.04
enrSubnets - ssz BitVector 4 bits 284.00 ns/op 261.00 ns/op 1.09
prioritizePeers score -10:0 att 32-0.1 sync 2-0 217.63 us/op 200.86 us/op 1.08
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 244.65 us/op 229.43 us/op 1.07
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 364.00 us/op 328.39 us/op 1.11
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 642.41 us/op 592.72 us/op 1.08
prioritizePeers score 0:0 att 64-1 sync 4-1 742.04 us/op 674.27 us/op 1.10
array of 16000 items push then shift 1.3368 us/op 1.2297 us/op 1.09
LinkedList of 16000 items push then shift 8.0430 ns/op 7.3420 ns/op 1.10
array of 16000 items push then pop 71.223 ns/op 65.032 ns/op 1.10
LinkedList of 16000 items push then pop 6.1970 ns/op 5.8520 ns/op 1.06
array of 24000 items push then shift 1.9489 us/op 1.8122 us/op 1.08
LinkedList of 24000 items push then shift 7.0210 ns/op 6.9140 ns/op 1.02
array of 24000 items push then pop 95.195 ns/op 91.107 ns/op 1.04
LinkedList of 24000 items push then pop 6.1640 ns/op 5.8430 ns/op 1.05
intersect bitArray bitLen 8 4.8470 ns/op 4.6150 ns/op 1.05
intersect array and set length 8 30.104 ns/op 28.552 ns/op 1.05
intersect bitArray bitLen 128 24.530 ns/op 23.789 ns/op 1.03
intersect array and set length 128 511.38 ns/op 513.30 ns/op 1.00
bitArray.getTrueBitIndexes() bitLen 128 1.1120 us/op 1.0460 us/op 1.06
bitArray.getTrueBitIndexes() bitLen 248 1.7820 us/op 1.7770 us/op 1.00
bitArray.getTrueBitIndexes() bitLen 512 3.6950 us/op 3.6830 us/op 1.00
Full columns - reconstruct all 6 blobs 167.79 us/op 161.66 us/op 1.04
Full columns - reconstruct half of the blobs out of 6 67.032 us/op 99.502 us/op 0.67
Full columns - reconstruct single blob out of 6 33.848 us/op 53.671 us/op 0.63
Half columns - reconstruct all 6 blobs 398.96 ms/op 378.05 ms/op 1.06
Half columns - reconstruct half of the blobs out of 6 200.09 ms/op 189.07 ms/op 1.06
Half columns - reconstruct single blob out of 6 72.341 ms/op 67.945 ms/op 1.06
Full columns - reconstruct all 10 blobs 184.01 us/op 273.09 us/op 0.67
Full columns - reconstruct half of the blobs out of 10 148.50 us/op 150.79 us/op 0.98
Full columns - reconstruct single blob out of 10 30.440 us/op 28.710 us/op 1.06
Half columns - reconstruct all 10 blobs 658.74 ms/op 624.62 ms/op 1.05
Half columns - reconstruct half of the blobs out of 10 333.51 ms/op 315.32 ms/op 1.06
Half columns - reconstruct single blob out of 10 72.824 ms/op 66.587 ms/op 1.09
Full columns - reconstruct all 20 blobs 1.6603 ms/op 1.5965 ms/op 1.04
Full columns - reconstruct half of the blobs out of 20 251.32 us/op 171.42 us/op 1.47
Full columns - reconstruct single blob out of 20 33.469 us/op 45.834 us/op 0.73
Half columns - reconstruct all 20 blobs 1.3393 s/op 1.2521 s/op 1.07
Half columns - reconstruct half of the blobs out of 20 677.28 ms/op 625.21 ms/op 1.08
Half columns - reconstruct single blob out of 20 74.004 ms/op 67.935 ms/op 1.09
Set add up to 64 items then delete first 2.2189 us/op 2.4649 us/op 0.90
OrderedSet add up to 64 items then delete first 3.5398 us/op 3.3013 us/op 1.07
Set add up to 64 items then delete last 2.2493 us/op 2.3360 us/op 0.96
OrderedSet add up to 64 items then delete last 3.4593 us/op 3.2067 us/op 1.08
Set add up to 64 items then delete middle 2.2165 us/op 2.0974 us/op 1.06
OrderedSet add up to 64 items then delete middle 5.0005 us/op 4.6889 us/op 1.07
Set add up to 128 items then delete first 4.4309 us/op 4.2285 us/op 1.05
OrderedSet add up to 128 items then delete first 6.8686 us/op 6.4468 us/op 1.07
Set add up to 128 items then delete last 4.1475 us/op 3.9056 us/op 1.06
OrderedSet add up to 128 items then delete last 6.2111 us/op 5.8373 us/op 1.06
Set add up to 128 items then delete middle 4.2729 us/op 3.9536 us/op 1.08
OrderedSet add up to 128 items then delete middle 13.765 us/op 12.409 us/op 1.11
Set add up to 256 items then delete first 8.6147 us/op 7.9907 us/op 1.08
OrderedSet add up to 256 items then delete first 13.406 us/op 12.694 us/op 1.06
Set add up to 256 items then delete last 8.1756 us/op 7.8888 us/op 1.04
OrderedSet add up to 256 items then delete last 12.871 us/op 11.606 us/op 1.11
Set add up to 256 items then delete middle 8.4698 us/op 7.6014 us/op 1.11
OrderedSet add up to 256 items then delete middle 40.999 us/op 36.686 us/op 1.12
pass gossip attestations to forkchoice per slot 2.7336 ms/op 2.5537 ms/op 1.07
forkChoice updateHead vc 100000 bc 64 eq 0 415.88 us/op 390.24 us/op 1.07
forkChoice updateHead vc 600000 bc 64 eq 0 2.5402 ms/op 2.2958 ms/op 1.11
forkChoice updateHead vc 1000000 bc 64 eq 0 4.1420 ms/op 3.8873 ms/op 1.07
forkChoice updateHead vc 600000 bc 320 eq 0 2.5187 ms/op 2.3476 ms/op 1.07
forkChoice updateHead vc 600000 bc 1200 eq 0 2.5766 ms/op 2.3681 ms/op 1.09
forkChoice updateHead vc 600000 bc 7200 eq 0 3.2562 ms/op 2.8846 ms/op 1.13
forkChoice updateHead vc 600000 bc 64 eq 1000 3.1385 ms/op 2.9095 ms/op 1.08
forkChoice updateHead vc 600000 bc 64 eq 10000 3.3471 ms/op 2.9935 ms/op 1.12
forkChoice updateHead vc 600000 bc 64 eq 300000 7.3603 ms/op 6.8137 ms/op 1.08
computeDeltas 1400000 validators 0% inactive 13.423 ms/op 12.473 ms/op 1.08
computeDeltas 1400000 validators 10% inactive 12.416 ms/op 11.688 ms/op 1.06
computeDeltas 1400000 validators 20% inactive 11.301 ms/op 10.548 ms/op 1.07
computeDeltas 1400000 validators 50% inactive 8.7687 ms/op 8.1210 ms/op 1.08
computeDeltas 2100000 validators 0% inactive 19.922 ms/op 18.562 ms/op 1.07
computeDeltas 2100000 validators 10% inactive 18.694 ms/op 17.489 ms/op 1.07
computeDeltas 2100000 validators 20% inactive 17.095 ms/op 16.861 ms/op 1.01
computeDeltas 2100000 validators 50% inactive 10.148 ms/op 9.3326 ms/op 1.09
altair processAttestation - 250000 vs - 7PWei normalcase 2.1743 ms/op 1.9212 ms/op 1.13
altair processAttestation - 250000 vs - 7PWei worstcase 2.9746 ms/op 2.7443 ms/op 1.08
altair processAttestation - setStatus - 1/6 committees join 110.83 us/op 99.831 us/op 1.11
altair processAttestation - setStatus - 1/3 committees join 212.05 us/op 197.72 us/op 1.07
altair processAttestation - setStatus - 1/2 committees join 298.41 us/op 292.60 us/op 1.02
altair processAttestation - setStatus - 2/3 committees join 392.01 us/op 373.81 us/op 1.05
altair processAttestation - setStatus - 4/5 committees join 541.52 us/op 536.43 us/op 1.01
altair processAttestation - setStatus - 100% committees join 637.45 us/op 589.37 us/op 1.08
altair processBlock - 250000 vs - 7PWei normalcase 4.8895 ms/op 4.3282 ms/op 1.13
altair processBlock - 250000 vs - 7PWei normalcase hashState 19.404 ms/op 17.290 ms/op 1.12
altair processBlock - 250000 vs - 7PWei worstcase 23.682 ms/op 21.711 ms/op 1.09
altair processBlock - 250000 vs - 7PWei worstcase hashState 47.664 ms/op 42.775 ms/op 1.11
phase0 processBlock - 250000 vs - 7PWei normalcase 1.4487 ms/op 1.3505 ms/op 1.07
phase0 processBlock - 250000 vs - 7PWei worstcase 17.853 ms/op 16.776 ms/op 1.06
altair processEth1Data - 250000 vs - 7PWei normalcase 324.11 us/op 281.19 us/op 1.15
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 8.1510 us/op 3.9120 us/op 2.08
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 21.021 us/op 20.774 us/op 1.01
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.8300 us/op 5.3830 us/op 1.08
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.8940 us/op 3.4710 us/op 1.12
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 97.867 us/op 86.846 us/op 1.13
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.4425 ms/op 1.3386 ms/op 1.08
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.8897 ms/op 1.7368 ms/op 1.09
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.8826 ms/op 1.7711 ms/op 1.06
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 4.0770 ms/op 3.8693 ms/op 1.05
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.1778 ms/op 2.0236 ms/op 1.08
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.2250 ms/op 3.9127 ms/op 1.08
Tree 40 250000 create 359.17 ms/op 350.36 ms/op 1.03
Tree 40 250000 get(125000) 97.623 ns/op 90.573 ns/op 1.08
Tree 40 250000 set(125000) 1.0529 us/op 966.78 ns/op 1.09
Tree 40 250000 toArray() 15.750 ms/op 15.827 ms/op 1.00
Tree 40 250000 iterate all - toArray() + loop 13.867 ms/op 15.905 ms/op 0.87
Tree 40 250000 iterate all - get(i) 42.982 ms/op 39.041 ms/op 1.10
Array 250000 create 2.2608 ms/op 2.3018 ms/op 0.98
Array 250000 clone - spread 700.36 us/op 717.45 us/op 0.98
Array 250000 get(125000) 0.30900 ns/op 0.29200 ns/op 1.06
Array 250000 set(125000) 0.30800 ns/op 0.30100 ns/op 1.02
Array 250000 iterate all - loop 59.523 us/op 56.382 us/op 1.06
phase0 afterProcessEpoch - 250000 vs - 7PWei 40.716 ms/op 50.825 ms/op 0.80
Array.fill - length 1000000 2.4326 ms/op 2.1202 ms/op 1.15
Array push - length 1000000 10.779 ms/op 9.5252 ms/op 1.13
Array.get 0.21333 ns/op 0.20504 ns/op 1.04
Uint8Array.get 0.24378 ns/op 0.24509 ns/op 0.99
phase0 beforeProcessEpoch - 250000 vs - 7PWei 13.665 ms/op 14.623 ms/op 0.93
altair processEpoch - mainnet_e81889 253.97 ms/op 286.68 ms/op 0.89
mainnet_e81889 - altair beforeProcessEpoch 14.069 ms/op 16.380 ms/op 0.86
mainnet_e81889 - altair processJustificationAndFinalization 4.8020 us/op 6.5070 us/op 0.74
mainnet_e81889 - altair processInactivityUpdates 3.4587 ms/op 6.3821 ms/op 0.54
mainnet_e81889 - altair processRewardsAndPenalties 16.710 ms/op 20.480 ms/op 0.82
mainnet_e81889 - altair processRegistryUpdates 515.00 ns/op 523.00 ns/op 0.98
mainnet_e81889 - altair processSlashings 131.00 ns/op 134.00 ns/op 0.98
mainnet_e81889 - altair processEth1DataReset 131.00 ns/op 127.00 ns/op 1.03
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.6377 ms/op 5.9907 ms/op 0.27
mainnet_e81889 - altair processSlashingsReset 699.00 ns/op 687.00 ns/op 1.02
mainnet_e81889 - altair processRandaoMixesReset 997.00 ns/op 1.3140 us/op 0.76
mainnet_e81889 - altair processHistoricalRootsUpdate 131.00 ns/op 127.00 ns/op 1.03
mainnet_e81889 - altair processParticipationFlagUpdates 417.00 ns/op 420.00 ns/op 0.99
mainnet_e81889 - altair processSyncCommitteeUpdates 105.00 ns/op 108.00 ns/op 0.97
mainnet_e81889 - altair afterProcessEpoch 42.137 ms/op 41.701 ms/op 1.01
capella processEpoch - mainnet_e217614 788.30 ms/op 831.61 ms/op 0.95
mainnet_e217614 - capella beforeProcessEpoch 60.084 ms/op 60.131 ms/op 1.00
mainnet_e217614 - capella processJustificationAndFinalization 5.0350 us/op 6.4890 us/op 0.78
mainnet_e217614 - capella processInactivityUpdates 11.767 ms/op 16.282 ms/op 0.72
mainnet_e217614 - capella processRewardsAndPenalties 87.429 ms/op 95.947 ms/op 0.91
mainnet_e217614 - capella processRegistryUpdates 4.5460 us/op 4.4340 us/op 1.03
mainnet_e217614 - capella processSlashings 133.00 ns/op 154.00 ns/op 0.86
mainnet_e217614 - capella processEth1DataReset 133.00 ns/op 142.00 ns/op 0.94
mainnet_e217614 - capella processEffectiveBalanceUpdates 5.9460 ms/op 16.878 ms/op 0.35
mainnet_e217614 - capella processSlashingsReset 684.00 ns/op 700.00 ns/op 0.98
mainnet_e217614 - capella processRandaoMixesReset 1.0780 us/op 1.3370 us/op 0.81
mainnet_e217614 - capella processHistoricalRootsUpdate 127.00 ns/op 146.00 ns/op 0.87
mainnet_e217614 - capella processParticipationFlagUpdates 428.00 ns/op 425.00 ns/op 1.01
mainnet_e217614 - capella afterProcessEpoch 109.42 ms/op 108.98 ms/op 1.00
phase0 processEpoch - mainnet_e58758 258.55 ms/op 323.23 ms/op 0.80
mainnet_e58758 - phase0 beforeProcessEpoch 59.284 ms/op 69.514 ms/op 0.85
mainnet_e58758 - phase0 processJustificationAndFinalization 5.4660 us/op 6.5360 us/op 0.84
mainnet_e58758 - phase0 processRewardsAndPenalties 16.299 ms/op 16.385 ms/op 0.99
mainnet_e58758 - phase0 processRegistryUpdates 2.3070 us/op 2.2550 us/op 1.02
mainnet_e58758 - phase0 processSlashings 178.00 ns/op 134.00 ns/op 1.33
mainnet_e58758 - phase0 processEth1DataReset 132.00 ns/op 132.00 ns/op 1.00
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 834.54 us/op 1.3434 ms/op 0.62
mainnet_e58758 - phase0 processSlashingsReset 847.00 ns/op 863.00 ns/op 0.98
mainnet_e58758 - phase0 processRandaoMixesReset 1.1110 us/op 1.2770 us/op 0.87
mainnet_e58758 - phase0 processHistoricalRootsUpdate 134.00 ns/op 136.00 ns/op 0.99
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.0040 us/op 1.2350 us/op 0.81
mainnet_e58758 - phase0 afterProcessEpoch 34.137 ms/op 33.608 ms/op 1.02
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.0250 ms/op 995.22 us/op 1.03
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.6000 ms/op 1.5417 ms/op 1.04
altair processInactivityUpdates - 250000 normalcase 10.677 ms/op 11.076 ms/op 0.96
altair processInactivityUpdates - 250000 worstcase 10.709 ms/op 10.764 ms/op 0.99
phase0 processRegistryUpdates - 250000 normalcase 2.1250 us/op 2.9670 us/op 0.72
phase0 processRegistryUpdates - 250000 badcase_full_deposits 149.34 us/op 139.90 us/op 1.07
phase0 processRegistryUpdates - 250000 worstcase 0.5 54.659 ms/op 61.126 ms/op 0.89
altair processRewardsAndPenalties - 250000 normalcase 14.098 ms/op 15.789 ms/op 0.89
altair processRewardsAndPenalties - 250000 worstcase 13.563 ms/op 15.695 ms/op 0.86
phase0 getAttestationDeltas - 250000 normalcase 5.5369 ms/op 7.5083 ms/op 0.74
phase0 getAttestationDeltas - 250000 worstcase 5.6043 ms/op 5.5303 ms/op 1.01
phase0 processSlashings - 250000 worstcase 65.641 us/op 58.724 us/op 1.12
altair processSyncCommitteeUpdates - 250000 10.260 ms/op 12.436 ms/op 0.82
BeaconState.hashTreeRoot - No change 171.00 ns/op 162.00 ns/op 1.06
BeaconState.hashTreeRoot - 1 full validator 61.887 us/op 91.445 us/op 0.68
BeaconState.hashTreeRoot - 32 full validator 661.02 us/op 930.75 us/op 0.71
BeaconState.hashTreeRoot - 512 full validator 6.2914 ms/op 9.2349 ms/op 0.68
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 88.419 us/op 107.20 us/op 0.82
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.2044 ms/op 1.5056 ms/op 0.80
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 12.525 ms/op 20.944 ms/op 0.60
BeaconState.hashTreeRoot - 1 balances 56.091 us/op 87.713 us/op 0.64
BeaconState.hashTreeRoot - 32 balances 586.44 us/op 788.26 us/op 0.74
BeaconState.hashTreeRoot - 512 balances 4.5402 ms/op 6.7922 ms/op 0.67
BeaconState.hashTreeRoot - 250000 balances 94.913 ms/op 142.75 ms/op 0.66
aggregationBits - 2048 els - zipIndexesInBitList 19.494 us/op 19.403 us/op 1.00
regular array get 100000 times 23.039 us/op 22.818 us/op 1.01
wrappedArray get 100000 times 23.056 us/op 22.950 us/op 1.00
arrayWithProxy get 100000 times 10.027 ms/op 14.853 ms/op 0.68
ssz.Root.equals 21.813 ns/op 21.291 ns/op 1.02
byteArrayEquals 21.618 ns/op 21.182 ns/op 1.02
Buffer.compare 8.9660 ns/op 8.7410 ns/op 1.03
processSlot - 1 slots 8.1170 us/op 10.540 us/op 0.77
processSlot - 32 slots 1.5894 ms/op 2.2321 ms/op 0.71
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 2.9219 ms/op 3.8801 ms/op 0.75
getCommitteeAssignments - req 1 vs - 250000 vc 1.6930 ms/op 1.6543 ms/op 1.02
getCommitteeAssignments - req 100 vs - 250000 vc 3.4848 ms/op 3.3829 ms/op 1.03
getCommitteeAssignments - req 1000 vs - 250000 vc 3.7405 ms/op 3.6035 ms/op 1.04
findModifiedValidators - 10000 modified validators 805.67 ms/op 554.65 ms/op 1.45
findModifiedValidators - 1000 modified validators 470.21 ms/op 491.08 ms/op 0.96
findModifiedValidators - 100 modified validators 259.23 ms/op 322.00 ms/op 0.81
findModifiedValidators - 10 modified validators 156.12 ms/op 207.26 ms/op 0.75
findModifiedValidators - 1 modified validators 185.56 ms/op 141.69 ms/op 1.31
findModifiedValidators - no difference 161.77 ms/op 140.73 ms/op 1.15
migrate state 1500000 validators, 3400 modified, 2000 new 2.9494 s/op 2.9963 s/op 0.98
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.8100 ns/op 3.8500 ns/op 0.99
state getBlockRootAtSlot - 250000 vs - 7PWei 279.37 ns/op 390.10 ns/op 0.72
computeProposerIndex 100000 validators 1.4065 ms/op 1.3381 ms/op 1.05
getNextSyncCommitteeIndices 1000 validators 2.9709 ms/op 2.8932 ms/op 1.03
getNextSyncCommitteeIndices 10000 validators 26.221 ms/op 25.226 ms/op 1.04
getNextSyncCommitteeIndices 100000 validators 86.027 ms/op 88.357 ms/op 0.97
computeProposers - vc 250000 575.34 us/op 553.85 us/op 1.04
computeEpochShuffling - vc 250000 40.623 ms/op 40.164 ms/op 1.01
getNextSyncCommittee - vc 250000 9.6896 ms/op 9.8150 ms/op 0.99
nodejs block root to RootHex using toHex 96.110 ns/op 96.685 ns/op 0.99
nodejs block root to RootHex using toRootHex 55.503 ns/op 52.270 ns/op 1.06
nodejs fromHex(blob) 1.1430 ms/op 717.21 us/op 1.59
nodejs fromHexInto(blob) 652.20 us/op 627.22 us/op 1.04
nodejs block root to RootHex using the deprecated toHexString 504.50 ns/op 471.37 ns/op 1.07
nodejs byteArrayEquals 32 bytes (block root) 27.086 ns/op 26.173 ns/op 1.03
nodejs byteArrayEquals 48 bytes (pubkey) 39.033 ns/op 37.937 ns/op 1.03
nodejs byteArrayEquals 96 bytes (signature) 36.390 ns/op 35.574 ns/op 1.02
nodejs byteArrayEquals 1024 bytes 43.121 ns/op 41.882 ns/op 1.03
nodejs byteArrayEquals 131072 bytes (blob) 1.8097 us/op 1.7834 us/op 1.01
browser block root to RootHex using toHex 148.97 ns/op 144.84 ns/op 1.03
browser block root to RootHex using toRootHex 135.70 ns/op 131.76 ns/op 1.03
browser fromHex(blob) 1.8210 ms/op 1.4930 ms/op 1.22
browser fromHexInto(blob) 656.82 us/op 623.53 us/op 1.05
browser block root to RootHex using the deprecated toHexString 351.04 ns/op 326.64 ns/op 1.07
browser byteArrayEquals 32 bytes (block root) 29.250 ns/op 28.100 ns/op 1.04
browser byteArrayEquals 48 bytes (pubkey) 41.132 ns/op 39.536 ns/op 1.04
browser byteArrayEquals 96 bytes (signature) 77.474 ns/op 74.514 ns/op 1.04
browser byteArrayEquals 1024 bytes 781.85 ns/op 750.10 ns/op 1.04
browser byteArrayEquals 131072 bytes (blob) 98.795 us/op 94.114 us/op 1.05

by benchmarkbot/action

@twoeths twoeths marked this pull request as ready for review June 2, 2026 09:02
@twoeths twoeths requested a review from a team as a code owner June 2, 2026 09:02
@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.57%. Comparing base (b68fc56) to head (bc28c63).
⚠️ Report is 1 commits behind head on unstable.

Additional details and impacted files
@@            Coverage Diff            @@
##           unstable    #9444   +/-   ##
=========================================
  Coverage     52.56%   52.57%           
=========================================
  Files           848      848           
  Lines         60937    60924   -13     
  Branches       4485     4485           
=========================================
- Hits          32031    32029    -2     
+ Misses        28844    28833   -11     
  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.

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

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

forkChoiceNodes: forkChoice.getAllNodes().map((node) => {
// Payload-specific fields apply only to a revealed Gloas payload = the FULL variant of a
// Gloas block
const ptc = node.payloadStatus === PayloadStatus.FULL ? forkChoice.getPTCVoteCounts(node.blockRoot) : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Report PTC tallies on the pending fork-choice node

For Gloas blocks with PTC messages, this FULL-only guard makes the PENDING node return null for payload_attester_count and the yes counts even though ProtoArray initializes and updates those vote maps by block root as soon as the beacon block is seen. The referenced v2 fork-choice model carries the PTC attester/availability tallies on the PENDING consensus node, while FULL/EMPTY are payload variants, so this hides the counts during the pending period and later attaches them to the wrong node after the payload arrives.

Useful? React with 👍 / 👎.

@wemeetagain wemeetagain merged commit 2e689b4 into unstable Jun 2, 2026
18 of 19 checks passed
@wemeetagain wemeetagain deleted the te/enhance_fc_debug_endpoint branch June 2, 2026 09:46
},
},
getDebugForkChoiceV2: {
url: "/eth/v2/debug/fork_choice",

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.

do we really want a v2 for that? I am thinking since it's a debug endpoint and just used by us and since it only adds new fields + is json only, we should be fine with keeping v1 and adding new fields

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.

I guess there's a consumer of this api, it's in a spec for a reason
can change once we have an official beacon-api spec for it

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.

yes there are consumers like https://github.com/ethpandaops/forky, but what I am saying is that it might be simpler to add the new fields to v1 rather than introducing a v2 if it's a backward compatible change for all consumers, which someone has to confirm, I would expect so because it already returns a very loosely defined json dump, eg. it also has this extra_data field. But we can further discuss this if there is a spec PR for it, for now, this api as is will be useful for us to debug devnet issues

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.

there is a spec PR now but it's essentially based on the Prysm format, so I would assume our implementation already follows that

Comment on lines +258 to +264
transform: {
toResponse: (data) => ({
...(data as ForkChoiceResponseV2),
}),
fromResponse: (resp) => ({
data: resp as ForkChoiceResponseV2,
}),

@nflaig nflaig Jun 2, 2026

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.

if we go with a v2 endpoint, should at least make sure we wrap this inside data container to not have to do this custom transformation, I raised the same on the spec PR here ethereum/beacon-APIs#615 (comment)

Comment on lines -13 to +14
FULU_FORK_EPOCH: 1,
FULU_FORK_EPOCH: 0,
GLOAS_FORK_EPOCH: 1,

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.

I don't think it matters much but was this intentional? cc @twoeths

proposerBoostRoot: rootHex,
previousProposerBoostRoot: rootHex,
headRoot: rootHex,
},

@nflaig nflaig Jun 2, 2026

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.

we should remove this from extra_data field and move to top-level fields, related comment ethereum/beacon-APIs#615 (comment)

@twoeths

twoeths commented Jun 3, 2026

Copy link
Copy Markdown
Member Author

link to spec PR, may need to adopt later if there're something changed ethereum/beacon-APIs#615

@wemeetagain

Copy link
Copy Markdown
Member

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

3 participants