Skip to content

fix: introduce NativeBeaconStateView and simplify bindings#9412

Merged
wemeetagain merged 5 commits into
unstablefrom
te/avoid_BitArray_binding
May 29, 2026
Merged

fix: introduce NativeBeaconStateView and simplify bindings#9412
wemeetagain merged 5 commits into
unstablefrom
te/avoid_BitArray_binding

Conversation

@twoeths

@twoeths twoeths commented May 27, 2026

Copy link
Copy Markdown
Contributor

Motivation

  • it's tricky to use BitArray, which is defined in ssz for binding, see this concern

Description

  • the native binding does not have to do anything with BitArray, use {uint8Array: Uint8Array; bitLen: number} instead, the binding needs to conform toIBeaconStateViewNative overall
  • implement NativeBeaconStateView wrapper that conform to the public api of IBeaconStateViewLatestFork so beacon-node does not need to change. It also contains a cache layer so that it does not need to fetch native multiple times for the same data

@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 an AbstractBeaconStateView base class to abstract the executionPayloadAvailability getter, wrapping a minimal {uint8Array, bitLen} shape into a BitArray for consumers. The review feedback suggests optimizing this abstraction by checking if the raw value is already a BitArray to avoid redundant instantiation, and returning the BitArray directly from BeaconStateView to prevent creating temporary objects.

Comment thread packages/state-transition/src/stateView/abstractBeaconStateView.ts Outdated
Comment thread packages/state-transition/src/stateView/beaconStateView.ts Outdated
@twoeths twoeths marked this pull request as ready for review May 27, 2026 07:03
@twoeths twoeths requested a review from a team as a code owner May 27, 2026 07:03
@github-actions

github-actions Bot commented May 27, 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: f78a2e0 Previous: f715896 Ratio
phase0 getAttestationDeltas - 250000 worstcase 18.301 ms/op 5.3226 ms/op 3.44
Full benchmark results
Benchmark suite Current: f78a2e0 Previous: f715896 Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 1.2700 ms/op 900.60 us/op 1.41
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 40.738 us/op 39.278 us/op 1.04
BLS verify - blst 751.37 us/op 701.64 us/op 1.07
BLS verifyMultipleSignatures 3 - blst 1.3577 ms/op 1.3146 ms/op 1.03
BLS verifyMultipleSignatures 8 - blst 2.1767 ms/op 2.0931 ms/op 1.04
BLS verifyMultipleSignatures 32 - blst 6.7844 ms/op 6.6452 ms/op 1.02
BLS verifyMultipleSignatures 64 - blst 13.154 ms/op 13.063 ms/op 1.01
BLS verifyMultipleSignatures 128 - blst 25.883 ms/op 25.542 ms/op 1.01
BLS deserializing 10000 signatures 652.12 ms/op 634.53 ms/op 1.03
BLS deserializing 100000 signatures 6.5873 s/op 6.2642 s/op 1.05
BLS verifyMultipleSignatures - same message - 3 - blst 711.11 us/op 792.59 us/op 0.90
BLS verifyMultipleSignatures - same message - 8 - blst 887.39 us/op 881.25 us/op 1.01
BLS verifyMultipleSignatures - same message - 32 - blst 1.4920 ms/op 1.5474 ms/op 0.96
BLS verifyMultipleSignatures - same message - 64 - blst 2.3045 ms/op 2.3132 ms/op 1.00
BLS verifyMultipleSignatures - same message - 128 - blst 4.0550 ms/op 3.9757 ms/op 1.02
BLS aggregatePubkeys 32 - blst 17.844 us/op 17.495 us/op 1.02
BLS aggregatePubkeys 128 - blst 62.136 us/op 62.679 us/op 0.99
getSlashingsAndExits - default max 63.546 us/op 46.489 us/op 1.37
getSlashingsAndExits - 2k 461.77 us/op 329.75 us/op 1.40
proposeBlockBody type=full, size=empty 691.05 us/op 677.61 us/op 1.02
isKnown best case - 1 super set check 168.00 ns/op 172.00 ns/op 0.98
isKnown normal case - 2 super set checks 165.00 ns/op 160.00 ns/op 1.03
isKnown worse case - 16 super set checks 165.00 ns/op 162.00 ns/op 1.02
validate api signedAggregateAndProof - struct 1.4759 ms/op 1.4759 ms/op 1.00
validate gossip signedAggregateAndProof - struct 1.4554 ms/op 1.4668 ms/op 0.99
batch validate gossip attestation - vc 640000 - chunk 32 103.78 us/op 104.46 us/op 0.99
batch validate gossip attestation - vc 640000 - chunk 64 92.307 us/op 93.023 us/op 0.99
batch validate gossip attestation - vc 640000 - chunk 128 86.200 us/op 85.986 us/op 1.00
batch validate gossip attestation - vc 640000 - chunk 256 82.665 us/op 82.075 us/op 1.01
bytes32 toHexString 281.00 ns/op 282.00 ns/op 1.00
bytes32 Buffer.toString(hex) 163.00 ns/op 158.00 ns/op 1.03
bytes32 Buffer.toString(hex) from Uint8Array 225.00 ns/op 223.00 ns/op 1.01
bytes32 Buffer.toString(hex) + 0x 162.00 ns/op 156.00 ns/op 1.04
Return object 10000 times 0.20680 ns/op 0.21100 ns/op 0.98
Throw Error 10000 times 3.1857 us/op 3.2239 us/op 0.99
toHex 84.115 ns/op 86.148 ns/op 0.98
Buffer.from 79.645 ns/op 78.985 ns/op 1.01
shared Buffer 49.915 ns/op 50.867 ns/op 0.98
fastMsgIdFn sha256 / 200 bytes 1.4500 us/op 1.4490 us/op 1.00
fastMsgIdFn h32 xxhash / 200 bytes 146.00 ns/op 161.00 ns/op 0.91
fastMsgIdFn h64 xxhash / 200 bytes 198.00 ns/op 203.00 ns/op 0.98
fastMsgIdFn sha256 / 1000 bytes 4.5860 us/op 4.6530 us/op 0.99
fastMsgIdFn h32 xxhash / 1000 bytes 235.00 ns/op 249.00 ns/op 0.94
fastMsgIdFn h64 xxhash / 1000 bytes 245.00 ns/op 255.00 ns/op 0.96
fastMsgIdFn sha256 / 10000 bytes 40.339 us/op 41.035 us/op 0.98
fastMsgIdFn h32 xxhash / 10000 bytes 1.2280 us/op 1.2700 us/op 0.97
fastMsgIdFn h64 xxhash / 10000 bytes 797.00 ns/op 832.00 ns/op 0.96
send data - 1000 256B messages 4.2946 ms/op 4.3675 ms/op 0.98
send data - 1000 512B messages 4.3522 ms/op 4.3062 ms/op 1.01
send data - 1000 1024B messages 4.6649 ms/op 4.3473 ms/op 1.07
send data - 1000 1200B messages 4.8694 ms/op 4.6494 ms/op 1.05
send data - 1000 2048B messages 4.8982 ms/op 4.7135 ms/op 1.04
send data - 1000 4096B messages 5.7350 ms/op 5.5779 ms/op 1.03
send data - 1000 16384B messages 66.201 ms/op 33.578 ms/op 1.97
send data - 1000 65536B messages 131.03 ms/op 126.68 ms/op 1.03
enrSubnets - fastDeserialize 64 bits 738.00 ns/op 754.00 ns/op 0.98
enrSubnets - ssz BitVector 64 bits 255.00 ns/op 257.00 ns/op 0.99
enrSubnets - fastDeserialize 4 bits 103.00 ns/op 106.00 ns/op 0.97
enrSubnets - ssz BitVector 4 bits 258.00 ns/op 268.00 ns/op 0.96
prioritizePeers score -10:0 att 32-0.1 sync 2-0 199.87 us/op 202.24 us/op 0.99
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 227.88 us/op 244.58 us/op 0.93
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 336.49 us/op 337.04 us/op 1.00
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 582.40 us/op 592.75 us/op 0.98
prioritizePeers score 0:0 att 64-1 sync 4-1 683.61 us/op 691.26 us/op 0.99
array of 16000 items push then shift 1.2209 us/op 1.2583 us/op 0.97
LinkedList of 16000 items push then shift 7.2450 ns/op 7.3190 ns/op 0.99
array of 16000 items push then pop 73.625 ns/op 68.227 ns/op 1.08
LinkedList of 16000 items push then pop 5.8510 ns/op 5.9070 ns/op 0.99
array of 24000 items push then shift 1.8104 us/op 1.8471 us/op 0.98
LinkedList of 24000 items push then shift 7.0220 ns/op 6.9420 ns/op 1.01
array of 24000 items push then pop 107.29 ns/op 94.938 ns/op 1.13
LinkedList of 24000 items push then pop 5.8340 ns/op 5.9150 ns/op 0.99
intersect bitArray bitLen 8 4.8010 ns/op 4.7100 ns/op 1.02
intersect array and set length 8 28.606 ns/op 28.827 ns/op 0.99
intersect bitArray bitLen 128 23.655 ns/op 23.715 ns/op 1.00
intersect array and set length 128 487.90 ns/op 487.78 ns/op 1.00
bitArray.getTrueBitIndexes() bitLen 128 1.1100 us/op 1.1050 us/op 1.00
bitArray.getTrueBitIndexes() bitLen 248 1.9000 us/op 1.9560 us/op 0.97
bitArray.getTrueBitIndexes() bitLen 512 3.7750 us/op 3.9390 us/op 0.96
Full columns - reconstruct all 6 blobs 187.20 us/op 201.96 us/op 0.93
Full columns - reconstruct half of the blobs out of 6 127.85 us/op 152.57 us/op 0.84
Full columns - reconstruct single blob out of 6 33.677 us/op 47.154 us/op 0.71
Half columns - reconstruct all 6 blobs 372.76 ms/op 379.95 ms/op 0.98
Half columns - reconstruct half of the blobs out of 6 187.94 ms/op 190.51 ms/op 0.99
Half columns - reconstruct single blob out of 6 67.495 ms/op 67.736 ms/op 1.00
Full columns - reconstruct all 10 blobs 229.22 us/op 289.76 us/op 0.79
Full columns - reconstruct half of the blobs out of 10 240.07 us/op 185.60 us/op 1.29
Full columns - reconstruct single blob out of 10 54.651 us/op 28.578 us/op 1.91
Half columns - reconstruct all 10 blobs 619.63 ms/op 621.12 ms/op 1.00
Half columns - reconstruct half of the blobs out of 10 314.75 ms/op 313.06 ms/op 1.01
Half columns - reconstruct single blob out of 10 67.263 ms/op 66.611 ms/op 1.01
Full columns - reconstruct all 20 blobs 530.41 us/op 885.64 us/op 0.60
Full columns - reconstruct half of the blobs out of 20 364.68 us/op 258.69 us/op 1.41
Full columns - reconstruct single blob out of 20 31.039 us/op 51.541 us/op 0.60
Half columns - reconstruct all 20 blobs 1.2569 s/op 1.2466 s/op 1.01
Half columns - reconstruct half of the blobs out of 20 626.65 ms/op 626.14 ms/op 1.00
Half columns - reconstruct single blob out of 20 68.197 ms/op 67.830 ms/op 1.01
Set add up to 64 items then delete first 2.1546 us/op 2.0233 us/op 1.06
OrderedSet add up to 64 items then delete first 3.5010 us/op 3.2477 us/op 1.08
Set add up to 64 items then delete last 2.1090 us/op 2.0511 us/op 1.03
OrderedSet add up to 64 items then delete last 3.2700 us/op 3.1988 us/op 1.02
Set add up to 64 items then delete middle 2.1123 us/op 2.0283 us/op 1.04
OrderedSet add up to 64 items then delete middle 4.7368 us/op 4.5530 us/op 1.04
Set add up to 128 items then delete first 4.1668 us/op 4.0474 us/op 1.03
OrderedSet add up to 128 items then delete first 6.5095 us/op 6.1664 us/op 1.06
Set add up to 128 items then delete last 3.7888 us/op 3.7599 us/op 1.01
OrderedSet add up to 128 items then delete last 5.7132 us/op 5.5743 us/op 1.02
Set add up to 128 items then delete middle 3.7438 us/op 3.7043 us/op 1.01
OrderedSet add up to 128 items then delete middle 11.393 us/op 11.636 us/op 0.98
Set add up to 256 items then delete first 7.7104 us/op 7.5901 us/op 1.02
OrderedSet add up to 256 items then delete first 12.002 us/op 11.807 us/op 1.02
Set add up to 256 items then delete last 7.4892 us/op 7.4189 us/op 1.01
OrderedSet add up to 256 items then delete last 11.791 us/op 11.223 us/op 1.05
Set add up to 256 items then delete middle 7.4383 us/op 7.4611 us/op 1.00
OrderedSet add up to 256 items then delete middle 34.424 us/op 34.372 us/op 1.00
pass gossip attestations to forkchoice per slot 2.5120 ms/op 2.4882 ms/op 1.01
forkChoice updateHead vc 100000 bc 64 eq 0 383.81 us/op 469.03 us/op 0.82
forkChoice updateHead vc 600000 bc 64 eq 0 2.2884 ms/op 2.3180 ms/op 0.99
forkChoice updateHead vc 1000000 bc 64 eq 0 3.7967 ms/op 3.8118 ms/op 1.00
forkChoice updateHead vc 600000 bc 320 eq 0 2.2875 ms/op 2.3023 ms/op 0.99
forkChoice updateHead vc 600000 bc 1200 eq 0 2.3369 ms/op 2.3129 ms/op 1.01
forkChoice updateHead vc 600000 bc 7200 eq 0 2.6740 ms/op 2.5947 ms/op 1.03
forkChoice updateHead vc 600000 bc 64 eq 1000 2.8816 ms/op 2.9163 ms/op 0.99
forkChoice updateHead vc 600000 bc 64 eq 10000 2.9447 ms/op 3.1321 ms/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 300000 6.5416 ms/op 6.6203 ms/op 0.99
computeDeltas 1400000 validators 0% inactive 12.237 ms/op 12.444 ms/op 0.98
computeDeltas 1400000 validators 10% inactive 11.435 ms/op 11.714 ms/op 0.98
computeDeltas 1400000 validators 20% inactive 10.454 ms/op 10.666 ms/op 0.98
computeDeltas 1400000 validators 50% inactive 8.0352 ms/op 8.2176 ms/op 0.98
computeDeltas 2100000 validators 0% inactive 18.335 ms/op 18.632 ms/op 0.98
computeDeltas 2100000 validators 10% inactive 17.319 ms/op 17.362 ms/op 1.00
computeDeltas 2100000 validators 20% inactive 15.600 ms/op 15.772 ms/op 0.99
computeDeltas 2100000 validators 50% inactive 9.3323 ms/op 9.1998 ms/op 1.01
altair processAttestation - 250000 vs - 7PWei normalcase 2.5194 ms/op 1.8298 ms/op 1.38
altair processAttestation - 250000 vs - 7PWei worstcase 3.5035 ms/op 2.5459 ms/op 1.38
altair processAttestation - setStatus - 1/6 committees join 97.286 us/op 100.91 us/op 0.96
altair processAttestation - setStatus - 1/3 committees join 203.69 us/op 203.23 us/op 1.00
altair processAttestation - setStatus - 1/2 committees join 281.88 us/op 280.66 us/op 1.00
altair processAttestation - setStatus - 2/3 committees join 358.77 us/op 379.36 us/op 0.95
altair processAttestation - setStatus - 4/5 committees join 504.44 us/op 508.37 us/op 0.99
altair processAttestation - setStatus - 100% committees join 600.94 us/op 602.27 us/op 1.00
altair processBlock - 250000 vs - 7PWei normalcase 3.9641 ms/op 3.8067 ms/op 1.04
altair processBlock - 250000 vs - 7PWei normalcase hashState 14.247 ms/op 13.292 ms/op 1.07
altair processBlock - 250000 vs - 7PWei worstcase 21.897 ms/op 21.060 ms/op 1.04
altair processBlock - 250000 vs - 7PWei worstcase hashState 45.280 ms/op 40.573 ms/op 1.12
phase0 processBlock - 250000 vs - 7PWei normalcase 1.3630 ms/op 1.3669 ms/op 1.00
phase0 processBlock - 250000 vs - 7PWei worstcase 16.296 ms/op 17.020 ms/op 0.96
altair processEth1Data - 250000 vs - 7PWei normalcase 283.35 us/op 293.99 us/op 0.96
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 5.1500 us/op 3.7400 us/op 1.38
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 20.046 us/op 20.106 us/op 1.00
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.6260 us/op 5.4780 us/op 1.03
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.4290 us/op 3.4560 us/op 0.99
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 89.375 us/op 89.093 us/op 1.00
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3777 ms/op 1.3500 ms/op 1.02
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.8080 ms/op 1.7643 ms/op 1.02
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7947 ms/op 1.7761 ms/op 1.01
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.6160 ms/op 3.6749 ms/op 0.98
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0258 ms/op 2.0248 ms/op 1.00
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.8993 ms/op 3.8102 ms/op 1.02
Tree 40 250000 create 343.03 ms/op 308.36 ms/op 1.11
Tree 40 250000 get(125000) 92.536 ns/op 92.436 ns/op 1.00
Tree 40 250000 set(125000) 1.0820 us/op 976.72 ns/op 1.11
Tree 40 250000 toArray() 13.101 ms/op 11.237 ms/op 1.17
Tree 40 250000 iterate all - toArray() + loop 13.052 ms/op 11.135 ms/op 1.17
Tree 40 250000 iterate all - get(i) 37.271 ms/op 35.191 ms/op 1.06
Array 250000 create 2.3621 ms/op 2.0821 ms/op 1.13
Array 250000 clone - spread 723.22 us/op 646.42 us/op 1.12
Array 250000 get(125000) 0.29200 ns/op 0.29200 ns/op 1.00
Array 250000 set(125000) 0.29400 ns/op 0.29700 ns/op 0.99
Array 250000 iterate all - loop 57.281 us/op 56.797 us/op 1.01
phase0 afterProcessEpoch - 250000 vs - 7PWei 56.418 ms/op 39.731 ms/op 1.42
Array.fill - length 1000000 2.1648 ms/op 1.9339 ms/op 1.12
Array push - length 1000000 9.0095 ms/op 7.2446 ms/op 1.24
Array.get 0.20684 ns/op 0.20251 ns/op 1.02
Uint8Array.get 0.23531 ns/op 0.23864 ns/op 0.99
phase0 beforeProcessEpoch - 250000 vs - 7PWei 16.945 ms/op 14.202 ms/op 1.19
altair processEpoch - mainnet_e81889 270.60 ms/op 258.16 ms/op 1.05
mainnet_e81889 - altair beforeProcessEpoch 14.719 ms/op 14.757 ms/op 1.00
mainnet_e81889 - altair processJustificationAndFinalization 6.3350 us/op 5.4650 us/op 1.16
mainnet_e81889 - altair processInactivityUpdates 3.4708 ms/op 3.4334 ms/op 1.01
mainnet_e81889 - altair processRewardsAndPenalties 19.722 ms/op 18.969 ms/op 1.04
mainnet_e81889 - altair processRegistryUpdates 532.00 ns/op 525.00 ns/op 1.01
mainnet_e81889 - altair processSlashings 128.00 ns/op 131.00 ns/op 0.98
mainnet_e81889 - altair processEth1DataReset 130.00 ns/op 126.00 ns/op 1.03
mainnet_e81889 - altair processEffectiveBalanceUpdates 2.3880 ms/op 1.3102 ms/op 1.82
mainnet_e81889 - altair processSlashingsReset 700.00 ns/op 667.00 ns/op 1.05
mainnet_e81889 - altair processRandaoMixesReset 1.2250 us/op 1.1080 us/op 1.11
mainnet_e81889 - altair processHistoricalRootsUpdate 127.00 ns/op 127.00 ns/op 1.00
mainnet_e81889 - altair processParticipationFlagUpdates 417.00 ns/op 424.00 ns/op 0.98
mainnet_e81889 - altair processSyncCommitteeUpdates 104.00 ns/op 104.00 ns/op 1.00
mainnet_e81889 - altair afterProcessEpoch 41.368 ms/op 41.587 ms/op 0.99
capella processEpoch - mainnet_e217614 826.16 ms/op 811.08 ms/op 1.02
mainnet_e217614 - capella beforeProcessEpoch 62.976 ms/op 55.783 ms/op 1.13
mainnet_e217614 - capella processJustificationAndFinalization 6.8010 us/op 5.5030 us/op 1.24
mainnet_e217614 - capella processInactivityUpdates 14.893 ms/op 15.504 ms/op 0.96
mainnet_e217614 - capella processRewardsAndPenalties 93.359 ms/op 85.625 ms/op 1.09
mainnet_e217614 - capella processRegistryUpdates 4.5450 us/op 4.4490 us/op 1.02
mainnet_e217614 - capella processSlashings 132.00 ns/op 135.00 ns/op 0.98
mainnet_e217614 - capella processEth1DataReset 128.00 ns/op 132.00 ns/op 0.97
mainnet_e217614 - capella processEffectiveBalanceUpdates 12.130 ms/op 11.803 ms/op 1.03
mainnet_e217614 - capella processSlashingsReset 682.00 ns/op 684.00 ns/op 1.00
mainnet_e217614 - capella processRandaoMixesReset 1.3340 us/op 1.1370 us/op 1.17
mainnet_e217614 - capella processHistoricalRootsUpdate 129.00 ns/op 131.00 ns/op 0.98
mainnet_e217614 - capella processParticipationFlagUpdates 427.00 ns/op 421.00 ns/op 1.01
mainnet_e217614 - capella afterProcessEpoch 107.10 ms/op 111.49 ms/op 0.96
phase0 processEpoch - mainnet_e58758 330.31 ms/op 295.05 ms/op 1.12
mainnet_e58758 - phase0 beforeProcessEpoch 68.611 ms/op 60.368 ms/op 1.14
mainnet_e58758 - phase0 processJustificationAndFinalization 6.7550 us/op 6.1540 us/op 1.10
mainnet_e58758 - phase0 processRewardsAndPenalties 16.263 ms/op 16.007 ms/op 1.02
mainnet_e58758 - phase0 processRegistryUpdates 2.2510 us/op 2.2720 us/op 0.99
mainnet_e58758 - phase0 processSlashings 135.00 ns/op 133.00 ns/op 1.02
mainnet_e58758 - phase0 processEth1DataReset 132.00 ns/op 131.00 ns/op 1.01
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 811.31 us/op 824.40 us/op 0.98
mainnet_e58758 - phase0 processSlashingsReset 889.00 ns/op 863.00 ns/op 1.03
mainnet_e58758 - phase0 processRandaoMixesReset 1.3210 us/op 1.2640 us/op 1.05
mainnet_e58758 - phase0 processHistoricalRootsUpdate 135.00 ns/op 134.00 ns/op 1.01
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.1720 us/op 1.0040 us/op 1.17
mainnet_e58758 - phase0 afterProcessEpoch 33.358 ms/op 33.668 ms/op 0.99
phase0 processEffectiveBalanceUpdates - 250000 normalcase 1.1163 ms/op 1.0120 ms/op 1.10
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.5611 ms/op 1.5817 ms/op 0.99
altair processInactivityUpdates - 250000 normalcase 12.811 ms/op 14.467 ms/op 0.89
altair processInactivityUpdates - 250000 worstcase 13.029 ms/op 13.412 ms/op 0.97
phase0 processRegistryUpdates - 250000 normalcase 2.1710 us/op 2.2860 us/op 0.95
phase0 processRegistryUpdates - 250000 badcase_full_deposits 145.86 us/op 138.30 us/op 1.05
phase0 processRegistryUpdates - 250000 worstcase 0.5 64.763 ms/op 56.791 ms/op 1.14
altair processRewardsAndPenalties - 250000 normalcase 16.216 ms/op 15.413 ms/op 1.05
altair processRewardsAndPenalties - 250000 worstcase 15.868 ms/op 14.547 ms/op 1.09
phase0 getAttestationDeltas - 250000 normalcase 5.3366 ms/op 8.3761 ms/op 0.64
phase0 getAttestationDeltas - 250000 worstcase 18.301 ms/op 5.3226 ms/op 3.44
phase0 processSlashings - 250000 worstcase 58.875 us/op 58.531 us/op 1.01
altair processSyncCommitteeUpdates - 250000 10.204 ms/op 10.139 ms/op 1.01
BeaconState.hashTreeRoot - No change 184.00 ns/op 162.00 ns/op 1.14
BeaconState.hashTreeRoot - 1 full validator 80.276 us/op 70.803 us/op 1.13
BeaconState.hashTreeRoot - 32 full validator 934.18 us/op 847.74 us/op 1.10
BeaconState.hashTreeRoot - 512 full validator 8.1997 ms/op 6.3600 ms/op 1.29
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 103.06 us/op 88.940 us/op 1.16
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4824 ms/op 1.2658 ms/op 1.17
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 18.691 ms/op 13.812 ms/op 1.35
BeaconState.hashTreeRoot - 1 balances 78.717 us/op 59.489 us/op 1.32
BeaconState.hashTreeRoot - 32 balances 769.63 us/op 667.36 us/op 1.15
BeaconState.hashTreeRoot - 512 balances 6.4515 ms/op 5.0513 ms/op 1.28
BeaconState.hashTreeRoot - 250000 balances 143.32 ms/op 113.97 ms/op 1.26
aggregationBits - 2048 els - zipIndexesInBitList 19.231 us/op 19.043 us/op 1.01
regular array get 100000 times 22.763 us/op 22.785 us/op 1.00
wrappedArray get 100000 times 22.732 us/op 22.788 us/op 1.00
arrayWithProxy get 100000 times 12.023 ms/op 9.5548 ms/op 1.26
ssz.Root.equals 21.317 ns/op 21.246 ns/op 1.00
byteArrayEquals 21.268 ns/op 21.076 ns/op 1.01
Buffer.compare 8.8080 ns/op 8.7540 ns/op 1.01
processSlot - 1 slots 8.7190 us/op 8.6020 us/op 1.01
processSlot - 32 slots 2.0089 ms/op 1.6941 ms/op 1.19
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 5.5222 ms/op 3.0272 ms/op 1.82
getCommitteeAssignments - req 1 vs - 250000 vc 1.6918 ms/op 1.6869 ms/op 1.00
getCommitteeAssignments - req 100 vs - 250000 vc 3.4402 ms/op 3.4173 ms/op 1.01
getCommitteeAssignments - req 1000 vs - 250000 vc 3.7072 ms/op 3.6765 ms/op 1.01
findModifiedValidators - 10000 modified validators 634.32 ms/op 637.81 ms/op 0.99
findModifiedValidators - 1000 modified validators 393.73 ms/op 446.60 ms/op 0.88
findModifiedValidators - 100 modified validators 274.32 ms/op 277.04 ms/op 0.99
findModifiedValidators - 10 modified validators 211.51 ms/op 201.50 ms/op 1.05
findModifiedValidators - 1 modified validators 161.11 ms/op 136.29 ms/op 1.18
findModifiedValidators - no difference 151.68 ms/op 151.47 ms/op 1.00
migrate state 1500000 validators, 3400 modified, 2000 new 3.0593 s/op 2.7766 s/op 1.10
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.7800 ns/op 3.7100 ns/op 1.02
state getBlockRootAtSlot - 250000 vs - 7PWei 382.53 ns/op 333.11 ns/op 1.15
computeProposerIndex 100000 validators 1.3392 ms/op 1.3008 ms/op 1.03
getNextSyncCommitteeIndices 1000 validators 2.8718 ms/op 2.8205 ms/op 1.02
getNextSyncCommitteeIndices 10000 validators 25.114 ms/op 24.877 ms/op 1.01
getNextSyncCommitteeIndices 100000 validators 87.812 ms/op 84.644 ms/op 1.04
computeProposers - vc 250000 557.56 us/op 543.84 us/op 1.03
computeEpochShuffling - vc 250000 39.795 ms/op 38.696 ms/op 1.03
getNextSyncCommittee - vc 250000 9.5235 ms/op 9.3502 ms/op 1.02
nodejs block root to RootHex using toHex 88.940 ns/op 89.126 ns/op 1.00
nodejs block root to RootHex using toRootHex 51.514 ns/op 51.254 ns/op 1.01
nodejs fromHex(blob) 742.09 us/op 703.07 us/op 1.06
nodejs fromHexInto(blob) 627.33 us/op 620.88 us/op 1.01
nodejs block root to RootHex using the deprecated toHexString 549.24 ns/op 475.04 ns/op 1.16
nodejs byteArrayEquals 32 bytes (block root) 25.805 ns/op 25.540 ns/op 1.01
nodejs byteArrayEquals 48 bytes (pubkey) 37.367 ns/op 37.097 ns/op 1.01
nodejs byteArrayEquals 96 bytes (signature) 33.660 ns/op 33.009 ns/op 1.02
nodejs byteArrayEquals 1024 bytes 41.686 ns/op 40.691 ns/op 1.02
nodejs byteArrayEquals 131072 bytes (blob) 1.7576 us/op 1.7302 us/op 1.02
browser block root to RootHex using toHex 143.93 ns/op 141.75 ns/op 1.02
browser block root to RootHex using toRootHex 131.34 ns/op 129.11 ns/op 1.02
browser fromHex(blob) 1.5226 ms/op 1.4315 ms/op 1.06
browser fromHexInto(blob) 625.45 us/op 618.32 us/op 1.01
browser block root to RootHex using the deprecated toHexString 363.08 ns/op 464.64 ns/op 0.78
browser byteArrayEquals 32 bytes (block root) 27.826 ns/op 27.767 ns/op 1.00
browser byteArrayEquals 48 bytes (pubkey) 39.448 ns/op 39.241 ns/op 1.01
browser byteArrayEquals 96 bytes (signature) 73.837 ns/op 73.322 ns/op 1.01
browser byteArrayEquals 1024 bytes 751.79 ns/op 745.88 ns/op 1.01
browser byteArrayEquals 131072 bytes (blob) 94.615 us/op 93.904 us/op 1.01

by benchmarkbot/action

@wemeetagain

Copy link
Copy Markdown
Member

How would we hook the NativeBeaconStateView to AbstractBeaconStateView?
I don't understand how the POJO object returned from the NativeBeaconStateView gets turned into a BitArray here

@twoeths

twoeths commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

How would we hook the NativeBeaconStateView to AbstractBeaconStateView?
I don't understand how the POJO object returned from the NativeBeaconStateView gets turned into a BitArray here

I did not fully implement the solution. The idea is to keep IBeaconStateViewLatestFork with BitArray for beacon-node to work with, while separate to an IBeaconStateViewNative interface with {uint8Array: Uint8Array; bitLen: number} for native to implement

@twoeths twoeths marked this pull request as draft May 28, 2026 10:39
@twoeths

twoeths commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

@wemeetagain I ended up with implementing NativeBeaconStateView, binding needs to implement IBeaconStateViewNative
at a 1st glance, it feels too much, but we need a cache layer inside NativeBeaconStateView anyway, ie we should not always call native for the same data from NodeJS side
this makes it ready to switch to NativeBeaconStateView later

@twoeths twoeths marked this pull request as ready for review May 28, 2026 13:06
@codecov

codecov Bot commented May 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 52.56%. Comparing base (fc6798b) to head (376be33).
⚠️ Report is 161 commits behind head on unstable.

Additional details and impacted files
@@             Coverage Diff              @@
##           unstable    #9412      +/-   ##
============================================
+ Coverage     52.46%   52.56%   +0.09%     
============================================
  Files           848      848              
  Lines         62953    60937    -2016     
  Branches       4658     4485     -173     
============================================
- Hits          33030    32031     -999     
+ Misses        29855    28844    -1011     
+ Partials         68       62       -6     
🚀 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: 376be33b7f

ℹ️ 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".

* pass-through. Methods with arguments are pass-through too — caching them
* would need a per-arg map and isn't worth it without a hot-path signal.
*/
export class NativeBeaconStateView extends AbstractBeaconStateView implements IBeaconStateViewLatestFork {

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 Export the native view contract for consumers

When the Zig/.node binding is built outside this package, it cannot import this wrapper from @lodestar/state-transition: packages/state-transition/package.json exposes only the root entry point, and src/index.ts does not re-export NativeBeaconStateView or IBeaconStateViewNative (a repo-wide search also shows no exported stateView subpath). The tests use relative paths, so they do not catch that the new binding contract is unreachable to external native consumers; export the wrapper/type from the package entry point or an exported subpath.

Useful? React with 👍 / 👎.

@wemeetagain

Copy link
Copy Markdown
Member

at a 1st glance, it feels too much, but we need a cache layer

totally agree. Imo this looks great. Also gives us some flexibility on the lodestar-z side.

One thing now tho, I don't think we need the AbstractBeaconStateView. My preference is for a concrete implementation on both sides. For example, the TS implementation shouldn't need the bitarray wrapper! its just needed for the native wrapper. So lets just leave it there.

@spiral-ladder

Copy link
Copy Markdown
Contributor

So AbstractBeaconStateView is an additional layer for APIs incompatible with the incoming zig native view?

@twoeths twoeths changed the title fix: change BeaconStateView binding without BitArray fix: introduce NativeBeaconStateView and simplify bindings May 29, 2026
@twoeths

twoeths commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

So AbstractBeaconStateView is an additional layer for APIs incompatible with the incoming zig native view?

just removed it, the binding layer needs to follow IBeaconStateViewNative after this PR, which avoid BitArray and use the POJO {uint8Array: Uint8Array; bitLen: number} instead

@wemeetagain wemeetagain merged commit 9d8b487 into unstable May 29, 2026
20 of 21 checks passed
@wemeetagain wemeetagain deleted the te/avoid_BitArray_binding branch May 29, 2026 20:04
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