Skip to content

feat: report parent_block_hash for safe/finalized post-Gloas - #9393

Merged
nflaig merged 9 commits into
unstablefrom
cayman/gloas-fcu-parent-hash
Aug 7, 2026
Merged

feat: report parent_block_hash for safe/finalized post-Gloas#9393
nflaig merged 9 commits into
unstablefrom
cayman/gloas-fcu-parent-hash

Conversation

@wemeetagain

@wemeetagain wemeetagain commented May 21, 2026

Copy link
Copy Markdown
Member

Motivation

Post-Gloas (ePBS) a block's own payload may not yet be confirmed canonical, so engine_forkchoiceUpdated must report the bid's parent_block_hash as the safe/finalized block hash.

Description

  • Add getFinalizedExecutionBlockHash and a shared fork-aware helper; switch all five FCU callsites
  • Post-Gloas blocks report the bid parent_block_hash; pre-Gloas behavior unchanged
  • Safe hash is based on the fast-confirmation confirmed block via new IForkChoice.getConfirmedBlock() (justified fallback when FCR is disabled), with warnings on zero-hash fallbacks
  • Genesis anchor: ZERO_HASH pre-Gloas (genesis body carries a default payload, so it is not an execution block); bid parent_block_hash for Gloas genesis

References:

AI Assistance Disclosure

  • Claude-assisted (rebase, genesis semantics, validation)

Implements consensus-specs PR-5197. Post-Gloas, engine_forkchoiceUpdated
must report the bid's parent_block_hash as both safeBlockHash and
finalizedBlockHash rather than the block's own execution payload hash:
under ePBS the safe/finalized block's own payload may not yet be confirmed
canonical, but its parent EL block has been.

Adds getFinalizedExecutionBlockHash to mirror getSafeExecutionBlockHash and
switches all five FCU callsites to the new fork-aware helpers.
@wemeetagain
wemeetagain requested a review from a team as a code owner May 21, 2026 16:12

@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 logic to correctly handle execution block hashes for the engine_forkchoiceUpdated call in preparation for the Gloas fork. It adds a new utility function getFinalizedExecutionBlockHash and refactors getSafeExecutionBlockHash to return the parent_block_hash for Gloas blocks, ensuring compliance with the updated consensus specifications. These utilities are integrated across the beacon node's block import and production flows, and new unit tests have been added to verify the logic for both pre-Gloas and post-Gloas scenarios. I have no feedback to provide.

@github-actions

github-actions Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: 5de0287 Previous: 49b1d65 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 881.28 us/op 980.59 us/op 0.90
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 39.230 us/op 39.630 us/op 0.99
BLS verify - blst 670.66 us/op 741.24 us/op 0.90
BLS verifyMultipleSignatures 3 - blst 1.2793 ms/op 1.3304 ms/op 0.96
BLS verifyMultipleSignatures 8 - blst 2.0264 ms/op 2.1694 ms/op 0.93
BLS verifyMultipleSignatures 32 - blst 6.3644 ms/op 6.7654 ms/op 0.94
BLS verifyMultipleSignatures 64 - blst 12.589 ms/op 13.109 ms/op 0.96
BLS verifyMultipleSignatures 128 - blst 24.475 ms/op 25.280 ms/op 0.97
BLS deserializing 10000 signatures 618.25 ms/op 632.69 ms/op 0.98
BLS deserializing 100000 signatures 6.4049 s/op 6.3359 s/op 1.01
BLS verifyMultipleSignatures - same message - 3 - blst 719.02 us/op 782.04 us/op 0.92
BLS verifyMultipleSignatures - same message - 8 - blst 898.53 us/op 889.38 us/op 1.01
BLS verifyMultipleSignatures - same message - 32 - blst 1.5660 ms/op 1.5444 ms/op 1.01
BLS verifyMultipleSignatures - same message - 64 - blst 2.3669 ms/op 2.3775 ms/op 1.00
BLS verifyMultipleSignatures - same message - 128 - blst 4.2427 ms/op 4.0373 ms/op 1.05
BLS aggregatePubkeys 32 - blst 17.842 us/op 17.640 us/op 1.01
BLS aggregatePubkeys 128 - blst 63.636 us/op 62.476 us/op 1.02
getSlashingsAndExits - default max 53.648 us/op 58.860 us/op 0.91
getSlashingsAndExits - 2k 421.58 us/op 387.86 us/op 1.09
proposeBlockBody type=full, size=empty 831.68 us/op 825.33 us/op 1.01
isKnown best case - 1 super set check 163.00 ns/op 163.00 ns/op 1.00
isKnown normal case - 2 super set checks 165.00 ns/op 162.00 ns/op 1.02
isKnown worse case - 16 super set checks 167.00 ns/op 162.00 ns/op 1.03
validate api signedAggregateAndProof - struct 1.5120 ms/op 1.5063 ms/op 1.00
validate gossip signedAggregateAndProof - struct 1.5436 ms/op 1.4961 ms/op 1.03
batch validate gossip attestation - vc 640000 - chunk 32 115.20 us/op 113.19 us/op 1.02
batch validate gossip attestation - vc 640000 - chunk 64 96.304 us/op 98.475 us/op 0.98
batch validate gossip attestation - vc 640000 - chunk 128 91.827 us/op 91.488 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 256 87.970 us/op 89.952 us/op 0.98
bytes32 toHexString 276.00 ns/op 281.00 ns/op 0.98
bytes32 Buffer.toString(hex) 163.00 ns/op 167.00 ns/op 0.98
bytes32 Buffer.toString(hex) from Uint8Array 229.00 ns/op 239.00 ns/op 0.96
bytes32 Buffer.toString(hex) + 0x 167.00 ns/op 172.00 ns/op 0.97
Return object 10000 times 0.21300 ns/op 0.21310 ns/op 1.00
Throw Error 10000 times 3.3422 us/op 3.3575 us/op 1.00
toHex 91.631 ns/op 94.424 ns/op 0.97
Buffer.from 84.646 ns/op 85.753 ns/op 0.99
shared Buffer 57.786 ns/op 58.452 ns/op 0.99
fastMsgIdFn sha256 / 200 bytes 1.4670 us/op 1.4580 us/op 1.01
fastMsgIdFn h32 xxhash / 200 bytes 162.00 ns/op 153.00 ns/op 1.06
fastMsgIdFn h64 xxhash / 200 bytes 216.00 ns/op 202.00 ns/op 1.07
fastMsgIdFn sha256 / 1000 bytes 4.7640 us/op 4.7280 us/op 1.01
fastMsgIdFn h32 xxhash / 1000 bytes 252.00 ns/op 243.00 ns/op 1.04
fastMsgIdFn h64 xxhash / 1000 bytes 273.00 ns/op 248.00 ns/op 1.10
fastMsgIdFn sha256 / 10000 bytes 40.842 us/op 41.492 us/op 0.98
fastMsgIdFn h32 xxhash / 10000 bytes 1.2550 us/op 1.2770 us/op 0.98
fastMsgIdFn h64 xxhash / 10000 bytes 803.00 ns/op 823.00 ns/op 0.98
send data - 1000 256B messages 5.1766 ms/op 4.6733 ms/op 1.11
send data - 1000 512B messages 6.0108 ms/op 5.5376 ms/op 1.09
send data - 1000 1024B messages 6.3062 ms/op 6.4742 ms/op 0.97
send data - 1000 1200B messages 7.4408 ms/op 7.2261 ms/op 1.03
send data - 1000 2048B messages 14.585 ms/op 21.475 ms/op 0.68
send data - 1000 4096B messages 29.465 ms/op 78.310 ms/op 0.38
send data - 1000 16384B messages 424.72 ms/op 302.03 ms/op 1.41
send data - 1000 65536B messages 1.4757 s/op 1.4651 s/op 1.01
enrSubnets - fastDeserialize 64 bits 761.00 ns/op 807.00 ns/op 0.94
enrSubnets - ssz BitVector 64 bits 262.00 ns/op 255.00 ns/op 1.03
enrSubnets - fastDeserialize 4 bits 97.000 ns/op 109.00 ns/op 0.89
enrSubnets - ssz BitVector 4 bits 262.00 ns/op 258.00 ns/op 1.02
prioritizePeers score -10:0 att 32-0.1 sync 2-0 201.83 us/op 208.59 us/op 0.97
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 235.67 us/op 239.60 us/op 0.98
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 340.69 us/op 348.57 us/op 0.98
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 614.20 us/op 615.39 us/op 1.00
prioritizePeers score 0:0 att 64-1 sync 4-1 700.18 us/op 719.25 us/op 0.97
array of 16000 items push then shift 1.2476 us/op 1.2991 us/op 0.96
LinkedList of 16000 items push then shift 7.8330 ns/op 8.0680 ns/op 0.97
array of 16000 items push then pop 71.962 ns/op 82.430 ns/op 0.87
LinkedList of 16000 items push then pop 6.0030 ns/op 6.7430 ns/op 0.89
array of 24000 items push then shift 1.8162 us/op 1.9072 us/op 0.95
LinkedList of 24000 items push then shift 7.3280 ns/op 8.0160 ns/op 0.91
array of 24000 items push then pop 101.58 ns/op 119.40 ns/op 0.85
LinkedList of 24000 items push then pop 6.0430 ns/op 6.4520 ns/op 0.94
intersect bitArray bitLen 8 3.8090 ns/op 3.9640 ns/op 0.96
intersect array and set length 8 29.023 ns/op 30.406 ns/op 0.95
intersect bitArray bitLen 128 22.816 ns/op 23.815 ns/op 0.96
intersect array and set length 128 506.45 ns/op 509.08 ns/op 0.99
bitArray.getTrueBitIndexes() bitLen 128 920.00 ns/op 977.00 ns/op 0.94
bitArray.getTrueBitIndexes() bitLen 248 1.6570 us/op 1.7450 us/op 0.95
bitArray.getTrueBitIndexes() bitLen 512 3.4340 us/op 3.6310 us/op 0.95
Full columns - reconstruct all 6 blobs 233.67 us/op 183.56 us/op 1.27
Full columns - reconstruct half of the blobs out of 6 94.494 us/op 72.714 us/op 1.30
Full columns - reconstruct single blob out of 6 35.393 us/op 33.270 us/op 1.06
Half columns - reconstruct all 6 blobs 388.94 ms/op 385.34 ms/op 1.01
Half columns - reconstruct half of the blobs out of 6 194.52 ms/op 196.37 ms/op 0.99
Half columns - reconstruct single blob out of 6 69.729 ms/op 69.379 ms/op 1.01
Set add up to 64 items then delete first 1.6199 us/op 2.1449 us/op 0.76
OrderedSet add up to 64 items then delete first 2.4683 us/op 3.3623 us/op 0.73
Set add up to 64 items then delete last 1.7980 us/op 2.2163 us/op 0.81
OrderedSet add up to 64 items then delete last 2.7816 us/op 3.1705 us/op 0.88
Set add up to 64 items then delete middle 1.8153 us/op 2.0369 us/op 0.89
OrderedSet add up to 64 items then delete middle 4.1186 us/op 4.7617 us/op 0.86
Set add up to 128 items then delete first 4.3312 us/op 4.1974 us/op 1.03
OrderedSet add up to 128 items then delete first 6.9900 us/op 6.8339 us/op 1.02
Set add up to 128 items then delete last 4.3320 us/op 4.0601 us/op 1.07
OrderedSet add up to 128 items then delete last 6.5875 us/op 6.5869 us/op 1.00
Set add up to 128 items then delete middle 3.7402 us/op 4.3799 us/op 0.85
OrderedSet add up to 128 items then delete middle 11.155 us/op 13.445 us/op 0.83
Set add up to 256 items then delete first 6.9997 us/op 8.4960 us/op 0.82
OrderedSet add up to 256 items then delete first 11.825 us/op 14.295 us/op 0.83
Set add up to 256 items then delete last 7.1694 us/op 8.0855 us/op 0.89
OrderedSet add up to 256 items then delete last 11.482 us/op 11.829 us/op 0.97
Set add up to 256 items then delete middle 6.8450 us/op 9.1645 us/op 0.75
OrderedSet add up to 256 items then delete middle 34.231 us/op 40.100 us/op 0.85
runFastConfirmationRules vc:100000 bc:96 eq:0 4.5605 ms/op 6.7721 ms/op 0.67
runFastConfirmationRules vc:600000 bc:96 eq:0 35.522 ms/op 38.800 ms/op 0.92
runFastConfirmationRules vc:1000000 bc:96 eq:0 60.925 ms/op 61.378 ms/op 0.99
runFastConfirmationRules vc:600000 bc:320 eq:0 37.441 ms/op 36.638 ms/op 1.02
runFastConfirmationRules vc:100000 bc:96 eq:1000 1.1260 s/op 1.5146 s/op 0.74
pass gossip attestations to forkchoice per slot 2.6454 ms/op 2.6983 ms/op 0.98
forkChoice updateHead vc 100000 bc 64 eq 0 413.87 us/op 412.39 us/op 1.00
forkChoice updateHead vc 600000 bc 64 eq 0 2.4616 ms/op 2.7964 ms/op 0.88
forkChoice updateHead vc 1000000 bc 64 eq 0 4.1034 ms/op 4.1176 ms/op 1.00
forkChoice updateHead vc 600000 bc 320 eq 0 2.4843 ms/op 2.5195 ms/op 0.99
forkChoice updateHead vc 600000 bc 1200 eq 0 2.6028 ms/op 2.6101 ms/op 1.00
forkChoice updateHead vc 600000 bc 7200 eq 0 3.6299 ms/op 4.0262 ms/op 0.90
forkChoice updateHead vc 600000 bc 64 eq 1000 2.4639 ms/op 2.4950 ms/op 0.99
forkChoice updateHead vc 600000 bc 64 eq 10000 2.5441 ms/op 2.5684 ms/op 0.99
forkChoice updateHead vc 600000 bc 64 eq 300000 6.5268 ms/op 7.2150 ms/op 0.90
computeDeltas 1400000 validators 0% inactive 12.119 ms/op 12.277 ms/op 0.99
computeDeltas 1400000 validators 10% inactive 11.537 ms/op 11.693 ms/op 0.99
computeDeltas 1400000 validators 20% inactive 10.986 ms/op 10.967 ms/op 1.00
computeDeltas 1400000 validators 50% inactive 11.233 ms/op 8.9552 ms/op 1.25
computeDeltas 2100000 validators 0% inactive 17.949 ms/op 18.340 ms/op 0.98
computeDeltas 2100000 validators 10% inactive 17.093 ms/op 17.349 ms/op 0.99
computeDeltas 2100000 validators 20% inactive 16.392 ms/op 16.613 ms/op 0.99
computeDeltas 2100000 validators 50% inactive 10.746 ms/op 10.934 ms/op 0.98
altair processAttestation - 250000 vs - 7PWei normalcase 2.4090 ms/op 2.6191 ms/op 0.92
altair processAttestation - 250000 vs - 7PWei worstcase 3.5293 ms/op 3.4604 ms/op 1.02
altair processAttestation - setStatus - 1/6 committees join 100.84 us/op 120.74 us/op 0.84
altair processAttestation - setStatus - 1/3 committees join 201.82 us/op 222.65 us/op 0.91
altair processAttestation - setStatus - 1/2 committees join 275.20 us/op 296.38 us/op 0.93
altair processAttestation - setStatus - 2/3 committees join 357.25 us/op 396.52 us/op 0.90
altair processAttestation - setStatus - 4/5 committees join 485.26 us/op 585.29 us/op 0.83
altair processAttestation - setStatus - 100% committees join 584.18 us/op 670.13 us/op 0.87
altair processBlock - 250000 vs - 7PWei normalcase 3.8642 ms/op 6.0124 ms/op 0.64
altair processBlock - 250000 vs - 7PWei normalcase hashState 16.070 ms/op 16.632 ms/op 0.97
altair processBlock - 250000 vs - 7PWei worstcase 22.231 ms/op 24.099 ms/op 0.92
altair processBlock - 250000 vs - 7PWei worstcase hashState 42.319 ms/op 46.882 ms/op 0.90
phase0 processBlock - 250000 vs - 7PWei normalcase 1.4126 ms/op 1.7497 ms/op 0.81
phase0 processBlock - 250000 vs - 7PWei worstcase 20.316 ms/op 19.468 ms/op 1.04
altair processEth1Data - 250000 vs - 7PWei normalcase 320.15 us/op 302.85 us/op 1.06
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 6.5320 us/op 5.2750 us/op 1.24
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 25.944 us/op 23.087 us/op 1.12
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 7.6780 us/op 7.5120 us/op 1.02
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.8680 us/op 4.0830 us/op 0.95
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 85.789 us/op 98.842 us/op 0.87
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3847 ms/op 1.5070 ms/op 0.92
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.7833 ms/op 2.2745 ms/op 0.78
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7534 ms/op 2.2717 ms/op 0.77
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.8037 ms/op 4.9988 ms/op 0.76
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0607 ms/op 2.2787 ms/op 0.90
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 4.7966 ms/op 5.9076 ms/op 0.81
Tree 40 250000 create 349.80 ms/op 410.62 ms/op 0.85
Tree 40 250000 get(125000) 90.579 ns/op 96.440 ns/op 0.94
Tree 40 250000 set(125000) 976.40 ns/op 1.0479 us/op 0.93
Tree 40 250000 toArray() 16.295 ms/op 19.358 ms/op 0.84
Tree 40 250000 iterate all - toArray() + loop 16.321 ms/op 19.955 ms/op 0.82
Tree 40 250000 iterate all - get(i) 39.775 ms/op 44.631 ms/op 0.89
Array 250000 create 2.1504 ms/op 2.9817 ms/op 0.72
Array 250000 clone - spread 695.45 us/op 883.47 us/op 0.79
Array 250000 get(125000) 0.30300 ns/op 0.30300 ns/op 1.00
Array 250000 set(125000) 0.30200 ns/op 0.30500 ns/op 0.99
Array 250000 iterate all - loop 57.517 us/op 60.052 us/op 0.96
phase0 afterProcessEpoch - 250000 vs - 7PWei 40.872 ms/op 58.045 ms/op 0.70
Array.fill - length 1000000 2.4585 ms/op 5.0917 ms/op 0.48
Array push - length 1000000 9.1099 ms/op 12.799 ms/op 0.71
Array.get 0.21104 ns/op 0.20988 ns/op 1.01
Uint8Array.get 0.23800 ns/op 0.24171 ns/op 0.98
phase0 beforeProcessEpoch - 250000 vs - 7PWei 15.866 ms/op 25.283 ms/op 0.63
altair processEpoch - mainnet_e81889 313.35 ms/op 333.27 ms/op 0.94
mainnet_e81889 - altair beforeProcessEpoch 17.822 ms/op 19.044 ms/op 0.94
mainnet_e81889 - altair processJustificationAndFinalization 7.3580 us/op 6.6880 us/op 1.10
mainnet_e81889 - altair processInactivityUpdates 6.9211 ms/op 6.0116 ms/op 1.15
mainnet_e81889 - altair processRewardsAndPenalties 21.388 ms/op 20.645 ms/op 1.04
mainnet_e81889 - altair processRegistryUpdates 610.00 ns/op 573.00 ns/op 1.06
mainnet_e81889 - altair processSlashings 147.00 ns/op 143.00 ns/op 1.03
mainnet_e81889 - altair processEth1DataReset 143.00 ns/op 136.00 ns/op 1.05
mainnet_e81889 - altair processEffectiveBalanceUpdates 6.3523 ms/op 6.3489 ms/op 1.00
mainnet_e81889 - altair processSlashingsReset 955.00 ns/op 732.00 ns/op 1.30
mainnet_e81889 - altair processRandaoMixesReset 1.4920 us/op 1.4410 us/op 1.04
mainnet_e81889 - altair processHistoricalRootsUpdate 143.00 ns/op 145.00 ns/op 0.99
mainnet_e81889 - altair processParticipationFlagUpdates 481.00 ns/op 471.00 ns/op 1.02
mainnet_e81889 - altair processSyncCommitteeUpdates 115.00 ns/op 118.00 ns/op 0.97
mainnet_e81889 - altair afterProcessEpoch 44.245 ms/op 41.893 ms/op 1.06
capella processEpoch - mainnet_e217614 828.45 ms/op 917.21 ms/op 0.90
mainnet_e217614 - capella beforeProcessEpoch 61.572 ms/op 62.320 ms/op 0.99
mainnet_e217614 - capella processJustificationAndFinalization 6.8750 us/op 7.3570 us/op 0.93
mainnet_e217614 - capella processInactivityUpdates 19.048 ms/op 17.775 ms/op 1.07
mainnet_e217614 - capella processRewardsAndPenalties 103.08 ms/op 100.42 ms/op 1.03
mainnet_e217614 - capella processRegistryUpdates 4.5030 us/op 4.6030 us/op 0.98
mainnet_e217614 - capella processSlashings 143.00 ns/op 146.00 ns/op 0.98
mainnet_e217614 - capella processEth1DataReset 138.00 ns/op 140.00 ns/op 0.99
mainnet_e217614 - capella processEffectiveBalanceUpdates 18.635 ms/op 19.996 ms/op 0.93
mainnet_e217614 - capella processSlashingsReset 697.00 ns/op 696.00 ns/op 1.00
mainnet_e217614 - capella processRandaoMixesReset 1.4210 us/op 1.5300 us/op 0.93
mainnet_e217614 - capella processHistoricalRootsUpdate 143.00 ns/op 143.00 ns/op 1.00
mainnet_e217614 - capella processParticipationFlagUpdates 463.00 ns/op 472.00 ns/op 0.98
mainnet_e217614 - capella afterProcessEpoch 111.34 ms/op 110.66 ms/op 1.01
phase0 processEpoch - mainnet_e58758 360.54 ms/op 380.59 ms/op 0.95
mainnet_e58758 - phase0 beforeProcessEpoch 81.376 ms/op 86.966 ms/op 0.94
mainnet_e58758 - phase0 processJustificationAndFinalization 7.0350 us/op 7.1650 us/op 0.98
mainnet_e58758 - phase0 processRewardsAndPenalties 16.674 ms/op 18.630 ms/op 0.90
mainnet_e58758 - phase0 processRegistryUpdates 2.2980 us/op 2.3560 us/op 0.98
mainnet_e58758 - phase0 processSlashings 145.00 ns/op 142.00 ns/op 1.02
mainnet_e58758 - phase0 processEth1DataReset 138.00 ns/op 331.00 ns/op 0.42
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 1.0434 ms/op 878.79 us/op 1.19
mainnet_e58758 - phase0 processSlashingsReset 909.00 ns/op 946.00 ns/op 0.96
mainnet_e58758 - phase0 processRandaoMixesReset 1.3720 us/op 1.4960 us/op 0.92
mainnet_e58758 - phase0 processHistoricalRootsUpdate 142.00 ns/op 143.00 ns/op 0.99
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.3050 us/op 1.2420 us/op 1.05
mainnet_e58758 - phase0 afterProcessEpoch 34.183 ms/op 34.509 ms/op 0.99
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.0736 ms/op 996.83 us/op 1.08
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.6353 ms/op 1.8532 ms/op 0.88
altair processInactivityUpdates - 250000 normalcase 13.532 ms/op 14.398 ms/op 0.94
altair processInactivityUpdates - 250000 worstcase 13.199 ms/op 14.611 ms/op 0.90
phase0 processRegistryUpdates - 250000 normalcase 3.0230 us/op 3.7560 us/op 0.80
phase0 processRegistryUpdates - 250000 badcase_full_deposits 143.84 us/op 153.08 us/op 0.94
phase0 processRegistryUpdates - 250000 worstcase 0.5 79.413 ms/op 85.873 ms/op 0.92
altair processRewardsAndPenalties - 250000 normalcase 16.789 ms/op 16.789 ms/op 1.00
altair processRewardsAndPenalties - 250000 worstcase 17.043 ms/op 15.926 ms/op 1.07
phase0 getAttestationDeltas - 250000 normalcase 5.7761 ms/op 5.8047 ms/op 1.00
phase0 getAttestationDeltas - 250000 worstcase 5.4672 ms/op 5.7913 ms/op 0.94
phase0 processSlashings - 250000 worstcase 62.008 us/op 63.428 us/op 0.98
altair processSyncCommitteeUpdates - 250000 11.125 ms/op 13.240 ms/op 0.84
BeaconState.hashTreeRoot - No change 174.00 ns/op 174.00 ns/op 1.00
BeaconState.hashTreeRoot - 1 full validator 78.335 us/op 81.032 us/op 0.97
BeaconState.hashTreeRoot - 32 full validator 835.52 us/op 811.45 us/op 1.03
BeaconState.hashTreeRoot - 512 full validator 8.6190 ms/op 12.444 ms/op 0.69
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 106.15 us/op 106.54 us/op 1.00
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4615 ms/op 1.4466 ms/op 1.01
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 21.011 ms/op 22.002 ms/op 0.95
BeaconState.hashTreeRoot - 1 balances 87.335 us/op 85.851 us/op 1.02
BeaconState.hashTreeRoot - 32 balances 776.79 us/op 751.02 us/op 1.03
BeaconState.hashTreeRoot - 512 balances 6.1816 ms/op 7.7244 ms/op 0.80
BeaconState.hashTreeRoot - 250000 balances 147.75 ms/op 218.30 ms/op 0.68
aggregationBits - 2048 els - zipIndexesInBitList 20.325 us/op 20.896 us/op 0.97
regular array get 100000 times 22.985 us/op 23.264 us/op 0.99
wrappedArray get 100000 times 22.873 us/op 23.119 us/op 0.99
arrayWithProxy get 100000 times 9.7899 ms/op 10.028 ms/op 0.98
ssz.Root.equals 21.655 ns/op 21.638 ns/op 1.00
byteArrayEquals 21.530 ns/op 21.480 ns/op 1.00
Buffer.compare 8.9030 ns/op 8.8650 ns/op 1.00
processSlot - 1 slots 14.360 us/op 10.066 us/op 1.43
processSlot - 32 slots 2.0297 ms/op 2.2142 ms/op 0.92
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 5.3890 ms/op 6.3451 ms/op 0.85
getCommitteeAssignments - req 1 vs - 250000 vc 1.6959 ms/op 1.6793 ms/op 1.01
getCommitteeAssignments - req 100 vs - 250000 vc 3.4365 ms/op 3.4203 ms/op 1.00
getCommitteeAssignments - req 1000 vs - 250000 vc 3.6634 ms/op 3.7146 ms/op 0.99
findModifiedValidators - 10000 modified validators 814.31 ms/op 832.85 ms/op 0.98
findModifiedValidators - 1000 modified validators 529.84 ms/op 443.69 ms/op 1.19
findModifiedValidators - 100 modified validators 343.88 ms/op 371.07 ms/op 0.93
findModifiedValidators - 10 modified validators 262.67 ms/op 270.12 ms/op 0.97
findModifiedValidators - 1 modified validators 168.79 ms/op 170.05 ms/op 0.99
findModifiedValidators - no difference 221.52 ms/op 173.16 ms/op 1.28
migrate state 1500000 validators, 3400 modified, 2000 new 3.1021 s/op 3.4987 s/op 0.89
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.7200 ns/op 3.7600 ns/op 0.99
state getBlockRootAtSlot - 250000 vs - 7PWei 411.07 ns/op 435.10 ns/op 0.94
computeProposerIndex 100000 validators 1.3866 ms/op 1.3697 ms/op 1.01
getNextSyncCommitteeIndices 1000 validators 2.9034 ms/op 2.9808 ms/op 0.97
getNextSyncCommitteeIndices 10000 validators 25.439 ms/op 26.103 ms/op 0.97
getNextSyncCommitteeIndices 100000 validators 91.103 ms/op 93.561 ms/op 0.97
computeProposers - vc 250000 549.40 us/op 556.48 us/op 0.99
computeEpochShuffling - vc 250000 38.835 ms/op 40.693 ms/op 0.95
getNextSyncCommittee - vc 250000 9.2717 ms/op 10.467 ms/op 0.89
nodejs block root to RootHex using toHex 93.135 ns/op 97.104 ns/op 0.96
nodejs block root to RootHex using toRootHex 60.578 ns/op 62.470 ns/op 0.97
nodejs fromHex(blob) 777.75 us/op 881.16 us/op 0.88
nodejs fromHexInto(blob) 624.61 us/op 636.35 us/op 0.98
nodejs block root to RootHex using the deprecated toHexString 464.01 ns/op 495.94 ns/op 0.94
nodejs byteArrayEquals 32 bytes (block root) 26.363 ns/op 26.247 ns/op 1.00
nodejs byteArrayEquals 48 bytes (pubkey) 38.170 ns/op 37.868 ns/op 1.01
nodejs byteArrayEquals 96 bytes (signature) 34.266 ns/op 36.658 ns/op 0.93
nodejs byteArrayEquals 1024 bytes 42.437 ns/op 40.609 ns/op 1.05
nodejs byteArrayEquals 131072 bytes (blob) 1.8139 us/op 1.7820 us/op 1.02
browser block root to RootHex using toHex 145.68 ns/op 146.80 ns/op 0.99
browser block root to RootHex using toRootHex 130.57 ns/op 131.44 ns/op 0.99
browser fromHex(blob) 1.7421 ms/op 1.6848 ms/op 1.03
browser fromHexInto(blob) 631.15 us/op 626.56 us/op 1.01
browser block root to RootHex using the deprecated toHexString 321.91 ns/op 329.38 ns/op 0.98
browser byteArrayEquals 32 bytes (block root) 27.887 ns/op 27.641 ns/op 1.01
browser byteArrayEquals 48 bytes (pubkey) 39.356 ns/op 38.652 ns/op 1.02
browser byteArrayEquals 96 bytes (signature) 73.735 ns/op 72.136 ns/op 1.02
browser byteArrayEquals 1024 bytes 747.19 ns/op 752.42 ns/op 0.99
browser byteArrayEquals 131072 bytes (blob) 95.462 us/op 94.981 us/op 1.01

by benchmarkbot/action

Comment thread packages/fork-choice/src/forkChoice/safeBlocks.ts Outdated
Comment thread packages/fork-choice/src/forkChoice/safeBlocks.ts Outdated
Comment thread packages/fork-choice/src/forkChoice/safeBlocks.ts Outdated
@nflaig

nflaig commented Jul 7, 2026

Copy link
Copy Markdown
Member

@wemeetagain please address review comments and resolve conflicts

@nflaig

nflaig commented Jul 8, 2026

Copy link
Copy Markdown
Member

@nazarhussain maybe you can take this over? we need this so fcr works correctly on gloas

…parent-hash

# Conflicts:
#	packages/beacon-node/src/chain/prepareNextSlot.ts
#	packages/fork-choice/src/forkChoice/safeBlocks.ts
@nazarhussain nazarhussain self-assigned this Aug 6, 2026
nazarhussain and others added 2 commits August 6, 2026 21:51
Genesis block body carries a default payload, so it is not an
execution block per spec (is_execution_block); proto array's anchor
hash comes from the state header and must not be reported as
safe/finalized. Gloas genesis still reports the bid parent_block_hash
(consensus-specs PR-5449 convention).

- pin spec doc links to v1.7.0-alpha.13, fix broken anchors
- mock getConfirmedBlock in prepareNextSlot test (FCU path threw,
  getFinalizedBlock never called)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/fork-choice/src/forkChoice/safeBlocks.ts Outdated
Comment thread packages/fork-choice/src/forkChoice/safeBlocks.ts Outdated
nflaig
nflaig previously approved these changes Aug 7, 2026
@nflaig nflaig added this to the v1.46.0 milestone Aug 7, 2026
@nflaig
nflaig merged commit 3d8f7cf into unstable Aug 7, 2026
19 checks passed
@nflaig
nflaig deleted the cayman/gloas-fcu-parent-hash branch August 7, 2026 14:49
nazarhussain added a commit that referenced this pull request Aug 7, 2026
Gloas alpha.13 state transition and the gloas-modified
get_safe_execution_block_hash landed on unstable (#9393), so the suite
passes fully, safe_execution_block_hash assertions included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
return confirmedBlock.executionPayloadBlockHash;
}
export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.warn>): RootHex {
const confirmedBlock = forkChoice.getConfirmedBlock();

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.

need to log when confirmed block is the finalized block

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.

added in #9794

*
* @deprecated The merged fast-confirmation spec only defines `get_safe_execution_block_hash`.
*/
export function getSafeBeaconBlockRoot(fc: IForkChoice): Root {

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.

this function is not in use anymore

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.

cleaned up here #9794

export function getSafeExecutionBlockHash(forkChoice: IForkChoice, logger?: Pick<Logger, LogLevel.warn>): RootHex {
const confirmedBlock = forkChoice.getConfirmedBlock();
if (confirmedBlock === null) {
logger?.warn("Confirmed block not found, using zero safe execution block hash", {

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 think we should throw error instead
this should not happen on any cases, even when FCR is enabled is disabled
otherwise, we'll have other issues in downstream flows, and the CL <-> EL investigate always take time

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.

agree with this, had same thought when reviewing this pr, did another quick audit of code and getConfirmedBlock() returns this.fcStore.justified.checkpoint.rootHex so that should always be there, also addressed in #9794

if (block.executionPayloadBlockHash === null) {
logger?.warn("Execution payload block hash not found, using zero hash", {
blockRoot: block.blockRoot,
slot: block.slot,

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.

same to above, I think we should throw error instead
the only case executionPayloadBlockHash could be null is when pre-bellatrix

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.

also updated in #9794

matthewkeil pushed a commit that referenced this pull request Aug 10, 2026
**Motivation**

Update spec tests to v1.7.0-alpha.13 FCR fixes proposed from #9690
([consensus-specs#5489](ethereum/consensus-specs#5489),
[consensus-specs#5490](ethereum/consensus-specs#5490))
and complete the missing FCR assertions.

**Description**

- Unskip `is_one_confirmed_fails_large_validator_slashed`, fixed
upstream by
[consensus-specs#5490](ethereum/consensus-specs#5490)
- Enable the gloas `fast_confirmation` suite — gloas alpha.13 state
transition and `get_safe_execution_block_hash` landed via #9393
- Assert `safe_execution_block_hash`
([consensus-specs#5449](ethereum/consensus-specs#5449))
and the `FastConfirmationStore` variables, exposed via
`IForkChoice.getFastConfirmationStore()` (debug API endpoint in a
follow-up PR)
- Skip vectors blocked on upstream vector artifacts, documented inline;
the schedule-related ones are already fixed upstream
([consensus-specs#5498](ethereum/consensus-specs#5498),
[consensus-specs#5499](ethereum/consensus-specs#5499))
and unskip on the next spec-tests release

`fast_confirmation` (minimal): 1416 passed / 20 skipped / 0 failed. Full
spec suites green: minimal 70,899 passed, mainnet 13,586 passed, 0
failures.

Refs #9690

**AI Assistance Disclosure**

- [x] I have read the [contributor
guidelines](https://github.com/ChainSafe/lodestar/blob/unstable/CONTRIBUTING.md#ai-assistance-notice)
and disclosed my usage of AI below.

Implemented and verified with AI assistance (Claude Code); all changes
reviewed and tests executed locally.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
nflaig added a commit that referenced this pull request Aug 11, 2026
Follow-up on #9393 based on
@twoeths' comments
- log when the confirmed block equals the finalized block
- throw typed errors for missing fork-choice execution data
- preserve valid pre-Merge zero-hash behavior
- remove the unused safe beacon block helper
@wemeetagain

Copy link
Copy Markdown
Member Author

🎉 This PR is included in v1.46.0 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

7 participants