Skip to content

feat: add fork choice compliance test for pre-gloas forks - #9670

Merged
ensi321 merged 25 commits into
unstablefrom
nc/fork-choice-compliance
Jul 23, 2026
Merged

feat: add fork choice compliance test for pre-gloas forks#9670
ensi321 merged 25 commits into
unstablefrom
nc/fork-choice-compliance

Conversation

@ensi321

@ensi321 ensi321 commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

The suite is a standalone flow parallel to the standard spec tests, sharing only the fork-choice test runner:

  • pnpm download-comptests — fetches the comptests.tar.gz release asset (same version pin and repo as the standard spec tests, configured in spec-tests-version.json) into its own spec-tests-comptests/ directory, fully order-independent from download-spec-tests.
  • pnpm test:comptest — runs the suite via a dedicated comptest vitest project. The regular spec projects exclude it, so test:spec / test:spec:minimal never pick it up. A zero-test guard fails the run loudly when fixtures are absent (the workspace vitest config sets passWithNoTests: true).
  • The shared runner logic is extracted from presets/fork_choice.test.ts into utils/forkChoiceTestRunner.ts (mechanical move); the preset file and the new comptest entry file only register runners.
  • CI: nightly scheduled workflow (comptests.yml, 03:00 UTC + workflow_dispatch), following the Kurtosis sim-tests pattern — most PRs don't touch fork choice, so per-PR runs are not worth the cost (~10 min per fork, single vitest worker).

Runner/fork-choice changes needed for the new checks:

  • ForkChoice.getViableHeads() (test-only, not on IForkChoice): leaves of the spec's filtered block tree with weights, backing the suite's viable_for_head_roots_and_weights check — head equivalence alone can't catch filtered-tree/weight regressions. Gloas payload-status variants are reported per (root, payload_status, weight)
  • Exact weight comparison via proposer-boost emulation (bigint): lodestar tracks weights in EFFECTIVE_BALANCE_INCREMENT units and double-floors the boost score (up to 1.2 ETH below the spec's Gwei-precision value). Instead of comparing within a tolerance (which would mask small weight bugs), the runner normalizes the expected weight of the boosted entry using the production getCommitteeFraction and compares exactly.
  • Spec-semantics fixes in the runner: nested checks.head.payload_status (current vector shape), on_attestation one-slot-delay precondition, target-checkpoint shuffling for attestation decoding, bls_setting: 2 (placeholder signatures) handling, payload-attestation negative-test completeness (slot mismatch is a spec no-op success; missing PTC membership is a rejection).
  • specTestIterator: central SkipOpts.skippedTests now composes with runner-local shouldSkip (previously silently ignored for runners defining their own, e.g. fork_choice).

Results

vectors pre-gloas result
v1.7.0-alpha.11 (current pin) 8,832/8,832 pass (all 6 forks)
v1.7.0-alpha.12 8,831/8,832 — the single failure is #9666, skip-listed with issue link (that case name only exists in the alpha.12 vector set)

Supersedes #9314 — the runner and fork-choice work from that PR is carried forward as cherry-picked commits with authorship preserved. Coauthored by @GrapeBaBa

Part of #7637

GrapeBaBa and others added 20 commits July 15, 2026 23:24
The fork-choice compliance suite (consensus-specs#3831) introduces a
`viable_for_head_roots_and_weights` check that asserts the leaves and
weights of the internal `filter_block_tree(store, justified.root)`.
Head equivalence alone is too weak to catch filtered-tree regressions.

Add `IForkChoice.getViableHeads()` that returns the viable-for-head
leaves of the filtered tree paired with their weights:

- A node is a filter_block_tree leaf iff it is viable AND has no viable
  descendants. `maybeUpdateBestChildAndDescendant` only sets `bestChild`
  to a child that `nodeLeadsToViableHead`, so `bestChild === undefined`
  iff no viable descendant. Combined with `nodeIsViableForHead`, this
  matches the spec exactly. Same approach as Teku's
  `ForkChoiceStrategy.getChainHeads`.
- Weight is converted from internal increment units to Gwei on read
  (compliance fixtures expect Gwei). Note the proposer-boost score
  contribution is also stored in increments and may round down on
  minimal preset (102 vs 102.4 ETH); attestation weight is exact, the
  rounding only surfaces while boost is active. Mainnet boost values
  are integer ETH so this is a non-issue there.
Wire the consensus-specs Fork Choice Compliance suite (#3831) into
the existing `forkChoiceTest` runner. The on-disk layout matches the
standard spec-test layout
(`tests/<preset>/<fork>/fork_choice_compliance/<handler>/<suite>/<case>/`),
so it slots in alongside `fork_choice` and `sync` runners.

Three test-only accommodations the compliance fixtures require:

1. `bls_setting: 2` — every compliance fixture uses placeholder
   signatures. Pass `validSignatures: testcase.meta?.bls_setting !==
   BigInt(1)` to `chain.processBlock` so verification short-circuits.
   Standard `fork_choice` fixtures use `bls_setting: 1` so behavior
   there is unchanged.

2. `BLOCK_ERROR_ALREADY_KNOWN` — compliance fixtures intentionally
   re-import the same block (`dup_shift` mutations in their
   `meta.yaml`). Spec semantics for `on_block(store, known_block)` is
   a no-op success. Production block import correctly rejects with
   ALREADY_KNOWN; this runner treats that case as success only when
   the step is `valid: true`.

3. Cross-epoch attestation shuffling — `on_attestation` decodes
   aggregation_bits using the state at the attestation's target
   checkpoint, not the head state. The runner now resolves the right
   shuffling via ShufflingCache + regen (mirroring the production
   validation path) instead of `headState.epochCtx.getIndexedAttestation`,
   which only worked when the attestation's epoch happened to be in
   the head's epoch cache (±1 epoch) and broke on cross-epoch fork
   attestations surfaced by the compliance suite.

Adds support for two compliance-only check fields:

- `viable_for_head_roots_and_weights` (consensus-specs#3831): compared
  via `getViableHeads()`. Both sides are sorted by root before
  comparison since the spec doesn't fix order.
- `head_payload_status` (gloas): mapped between our internal enum
  ordering (PENDING=0, EMPTY=1, FULL=2) and spec ordering (EMPTY=0,
  FULL=1, PENDING=2).

Pass rate against the latest comptests workflow `small.tar.gz` artifact:

  fulu/fork_choice_compliance: 253/1472 cases pass (17.2%)

Top remaining failures:
- ~80% `Invalid proposer boost root` — consensus-specs#4807 introduced
  a `block.proposer_index == get_beacon_proposer_index(head_state)`
  guard in `update_proposer_boost_root` that we do not yet implement;
  affects all forks (not just gloas equivocation handling). Tracked
  for follow-up alongside #9233.
- ~1% `Invalid viable heads` — proposer-boost rounding on minimal
  preset (see `getViableHeads()` weight note).
…e gloas variants

Three corrections to the compliance-only getViableHeads getter, plus an
API-surface trim:

- Restrict leaves to descendants of the justified checkpoint block: the
  spec's get_filtered_block_tree is rooted at store.justified_checkpoint,
  so iterating all proto-array nodes over-included FFG-viable leaves
  hanging off the finalized checkpoint on branches not under the current
  justified checkpoint (~87 of 100 'Invalid viable heads' compliance
  failures were this, not proposer-boost rounding as previously assumed).
  The descendant walk follows parent links to the justified root — a
  slot-based getAncestor lookup returns the node itself for leaves whose
  own slot equals the justified epoch start slot — and stops early once
  it passes the justified block's slot (parent slots are non-increasing).

- Emit each block root at most once: gloas payload-status variants share
  a blockRoot and more than one can be a leaf (EMPTY and FULL are both
  parented under PENDING), which produced duplicate roots that broke the
  index-paired comparison in the compliance check. Which variant's weight
  the spec expects is part of the open gloas vote-attribution divergence;
  keep the heaviest qualifying variant deterministically.

- Drop getViableHeads from IForkChoice: it is compliance-test-only and
  its single caller accesses the ForkChoice class directly.

Verified against consensus-specs compliance vectors (run 28413328593,
minimal fulu): viable-head root-set failures 100 -> 0; standard minimal
fork_choice+sync spectests unaffected (397 passed).
Changes to the shared fork-choice runner, each anchored to a test-format
or spec contract (not compliance-suite identity), so they apply uniformly
to fork_choice/sync/fork_choice_compliance:

- Register fork_choice_compliance in coveredTestRunners: without it every
  other spec suite iterating the same fixture tree (ssz_static, operations,
  sanity, ...) throws 'No test runner for fork_choice_compliance' once
  compliance fixtures are downloaded.

- Attestation timing precondition: spec validate_on_attestation requires
  get_current_slot(store) >= data.slot + 1. Lodestar enforces this 1-slot
  delay in the gossip/attestation-pool layer, not forkChoice.onAttestation;
  the runner calls onAttestation directly, so replicate the precondition
  (Lighthouse's runner excuses the same case post-hoc: DidntFail tolerated
  when data.slot >= current_slot). Clears all 298 negative-attestation
  compliance failures.

- Attestation step hardening: an unknown beacon block root on a valid:true
  step now fails loudly instead of being silently skipped, and the
  shuffling resolution runs inside the negative-test try/catch so that
  errors on valid:false steps (e.g. attesting to a future block) count as
  the expected rejection instead of crashing the case.

- Skip gloas ePBS signature verification unless bls_setting == 1: the
  test format mandates skipping verification for placeholder signatures
  (bls_setting: 2), which the block-import path already honors via
  validSignatures. Extend the same handling to the execution_payload and
  payload_attestation_message steps (Teku disables BLS at spec level for
  bls_setting IGNORED; Lighthouse compiles compliance under fake_crypto).

- Split viable_for_head_roots_and_weights into exact root-set equality
  plus a 1.2 ETH weight tolerance: the root set is epoch-determined and
  must match exactly (this strictness caught the getViableHeads
  justified-subtree bug; Teku's containsAll would not), while weights are
  stored in EFFECTIVE_BALANCE_INCREMENT units so the proposer-boost score
  quantizes to whole ETH; the divergence is bounded by
  (100 - gcd(P,100) + P)/100 = 1.2 ETH independent of preset.

Compliance (run 28413328593, minimal): fulu 1459/1472 (99.1%), remaining
11 proposer-boost-root divergences + 1-2 timeouts; gloas 200/1472, blocked
by processPayloadAttestation verifying signatures unconditionally (ignores
verifySignatures; not batched in getBlockSignatureSets) and a payload-status
vote-attribution divergence (weight diffs are exact multiples of 32 ETH
between EMPTY/FULL variants of the same root) — both documented follow-ups,
out of scope here. Known accommodation limit: ALREADY_KNOWN treated as
no-op success cannot re-apply proposer boost for a timely duplicate the
way spec on_block re-processing would. Standard minimal fork_choice+sync:
397 passed, unchanged.
Use the single getDefaultNodeIndex + getNodeByIndex idiom already used
elsewhere in protoArray instead of the two-hop getDefaultVariant + getNode
lookup. Semantically identical for all variant cases (pre-gloas FULL,
gloas PENDING, absent root); drops one redundant indices map lookup and
removes an unreachable throw path.
- getViableHeads(): emit one entry per gloas payload-status variant
  (root, payload_status, weight) per consensus-specs #5393; drop the
  dedupe-by-root heuristic; return increment-unit weights
- runner: read nested checks.head.payload_status (alpha.12 shape),
  replacing the dead flat head_payload_status key
- runner: exact viable-head weight comparison via proposer-boost
  emulation (bigint) instead of the 1.2 ETH tolerance; normalizes the
  documented boost-quantization divergence using the vector's expected
  boost root and the production getCommitteeFraction
- runner: payload-attestation steps now reject slot mismatch and
  non-PTC validators, and fail on unexpectedly-successful negative tests
- specTestIterator: compose SkipOpts.skippedTests with runner-local
  shouldSkip (was silently ignored for fork_choice); gate
  fork_choice_compliance behind RUN_FORK_CHOICE_COMPLIANCE=1; defer
  gloas compliance suite

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `pnpm download-comptests` and `pnpm test:comptest` (root + beacon-node),
fully outside the regular download-spec-tests/test:spec flow.

The comptests.tar.gz release asset exists since consensus-specs #5334;
vectors are fetched pinned to v1.7.0-alpha.12 (valid against the alpha.11
pin: the pre-gloas fork-choice spec delta is rename-only).

The standard downloader deletes its entire output directory on a cache
miss, so it cannot be reused for a second asset sharing spec-tests/.
downloadComptests() is asset-scoped instead: extracts to a temp dir,
replaces only tests/<preset>/<fork>/fork_choice_compliance/ subtrees,
and writes its own comptests-version.json marker only after a successful
merge — a failed download leaves existing fixtures and marker untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers: additive install alongside standard fixtures, refresh replacing
comptest paths + removing stale forks, cache hit, failed extraction
leaving fixtures and marker untouched, legacy marker treated as stale.

Also fixes the ordering bug the tests caught: validate the temp
extraction is non-empty BEFORE removing existing comptest paths — tar
can exit 0 on a truncated archive, which would have wiped the existing
vectors against an empty extraction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers justified-subtree leaf selection with increment-unit weights, and
gloas payload-status variants of one root reported as separate entries
(EMPTY-only before the envelope, EMPTY+FULL after onExecutionPayload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Single source of truth: spec-tests-version.json. The asset exists on
every release since v1.7.0-alpha.11 (consensus-specs #5334), so no
separate pin is needed; the comptests follow the pin bump in #9390
automatically.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… gating

Compliance registration moves out of fork_choice.test.ts into its own
test/spec/comptest/ file backed by a dedicated `comptest` vitest
project; the shared runner is extracted to utils/forkChoiceTestRunner.ts.

The regular spec projects exclude test/spec/comptest/** so
test:spec/test:spec:minimal can never pick the suite up, which removes
the need for RUN_FORK_CHOICE_COMPLIANCE: `pnpm test:comptest` simply
runs the comptest project. Zero-test guard (workspace config has
passWithNoTests: true) moves into the comptest entry file, now
unconditional.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
block_tree_test_16_201284350_1 fails identically on every pre-gloas fork:
the dependent-root gate compares against the cached head, which is stale
when the preceding tick crosses an epoch boundary and pulls up the
justified checkpoint. Tracked in #9666.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spec on_payload_attestation_message returns early when the message slot
does not match the attested block's slot ('PTC votes can only change the
vote for their assigned beacon block, return early otherwise') — it is
not a rejection. Restore conditional processing; the PTC-membership
assert and the negative-test assertion remain.

https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.12/specs/gloas/fork-choice.md#on_payload_attestation_message

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
comptests-version.txt, matching the standard downloader's version.txt
convention; a single version string needs no JSON.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compliance vectors now live in spec-tests-comptests/ with their own
version.txt, downloaded via the plain generic downloader — a flow fully
parallel to the standard spec tests, sharing only the fork-choice test
runner. download-spec-tests and download-comptests are order-independent
(previously, a standard-tests version change wiped the shared directory
including the merged compliance vectors).

Deletes the asset-scoped merge downloader and its tests — no longer
needed without a shared directory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scheduled (03:00 UTC) rather than per-PR: most PRs don't touch fork
choice, and the vectors are pinned — nightly on unstable is the right
cadence to catch regressions. Same pattern as Kurtosis sim tests.
Manual runs via workflow_dispatch.

Also documents download-comptests/test:comptest in AGENTS.md/CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Own outputDirBase and testsToDownload like the other entries; version
and repo URL shared with the standard spec tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ensi321
ensi321 requested a review from a team as a code owner July 16, 2026 23:13
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.


const logger = testLogger("spec-test");

export const forkChoiceTestRunner =

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.

Note for reviewers: a lot of the code here is migrated from fork_choice.test.ts so both spec test and compliance test can share a single runner.

Would be easier to view the diff by:
git diff unstable:packages/beacon-node/test/spec/presets/fork_choice.test.ts nc/fork-choice-compliance:packages/beacon-node/test/spec/utils/forkChoiceTestRunner.ts

@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: 48f1f5f479

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

Comment thread packages/beacon-node/test/spec/utils/forkChoiceTestRunner.ts Outdated
tickTime starts at 0, so an attestation step before the first tick
computed slot 0 regardless of the anchor state slot. clock.currentSlot
is initialized from the anchor slot and advanced by tick steps, matching
get_current_slot(store). Also document the ALREADY_KNOWN duplicate-block
accommodation honestly (spec re-processes duplicates; it is not a no-op).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ensi321

ensi321 commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@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 a standalone fork-choice compliance test suite (pnpm test:comptest) parallel to the standard spec tests, extracting the fork-choice test runner into a reusable utility. It also implements helper methods in ProtoArray and ForkChoice to retrieve viable heads and justified balances for compliance assertions. Feedback from the review highlights opportunities to improve type safety in the test runner by adding type guards before casting blockState to IBeaconStateViewGloas, and to optimize performance in protoArray.ts by returning early when justifiedSlot is undefined to avoid unnecessary tree traversals.

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/test/spec/utils/forkChoiceTestRunner.ts
Comment thread packages/beacon-node/test/spec/utils/forkChoiceTestRunner.ts
Comment thread packages/fork-choice/src/protoArray/protoArray.ts Outdated
@github-actions

github-actions Bot commented Jul 17, 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: af8503e Previous: d16fa2b Ratio
send data - 1000 2048B messages 67.344 ms/op 12.055 ms/op 5.59
Full columns - reconstruct all 6 blobs 376.85 us/op 104.39 us/op 3.61
Full benchmark results
Benchmark suite Current: af8503e Previous: d16fa2b Ratio
getPubkeys - index2pubkey - req 1000 vs - 250000 vc 934.02 us/op 879.50 us/op 1.06
getPubkeys - validatorsArr - req 1000 vs - 250000 vc 39.181 us/op 37.426 us/op 1.05
BLS verify - blst 641.14 us/op 760.80 us/op 0.84
BLS verifyMultipleSignatures 3 - blst 1.3465 ms/op 1.3673 ms/op 0.98
BLS verifyMultipleSignatures 8 - blst 2.1544 ms/op 2.1594 ms/op 1.00
BLS verifyMultipleSignatures 32 - blst 6.8022 ms/op 6.8778 ms/op 0.99
BLS verifyMultipleSignatures 64 - blst 13.219 ms/op 13.103 ms/op 1.01
BLS verifyMultipleSignatures 128 - blst 25.575 ms/op 25.786 ms/op 0.99
BLS deserializing 10000 signatures 608.05 ms/op 623.27 ms/op 0.98
BLS deserializing 100000 signatures 6.1246 s/op 6.4625 s/op 0.95
BLS verifyMultipleSignatures - same message - 3 - blst 797.00 us/op 813.12 us/op 0.98
BLS verifyMultipleSignatures - same message - 8 - blst 880.98 us/op 980.90 us/op 0.90
BLS verifyMultipleSignatures - same message - 32 - blst 1.4704 ms/op 1.6260 ms/op 0.90
BLS verifyMultipleSignatures - same message - 64 - blst 2.2789 ms/op 2.4886 ms/op 0.92
BLS verifyMultipleSignatures - same message - 128 - blst 3.8999 ms/op 4.2456 ms/op 0.92
BLS aggregatePubkeys 32 - blst 17.553 us/op 18.305 us/op 0.96
BLS aggregatePubkeys 128 - blst 62.408 us/op 65.206 us/op 0.96
getSlashingsAndExits - default max 47.355 us/op 50.784 us/op 0.93
getSlashingsAndExits - 2k 348.70 us/op 362.11 us/op 0.96
proposeBlockBody type=full, size=empty 599.88 us/op 608.87 us/op 0.99
isKnown best case - 1 super set check 171.00 ns/op 165.00 ns/op 1.04
isKnown normal case - 2 super set checks 158.00 ns/op 167.00 ns/op 0.95
isKnown worse case - 16 super set checks 164.00 ns/op 169.00 ns/op 0.97
validate api signedAggregateAndProof - struct 1.5229 ms/op 1.5763 ms/op 0.97
validate gossip signedAggregateAndProof - struct 1.5174 ms/op 1.5710 ms/op 0.97
batch validate gossip attestation - vc 640000 - chunk 32 104.19 us/op 112.78 us/op 0.92
batch validate gossip attestation - vc 640000 - chunk 64 90.878 us/op 99.585 us/op 0.91
batch validate gossip attestation - vc 640000 - chunk 128 84.486 us/op 93.002 us/op 0.91
batch validate gossip attestation - vc 640000 - chunk 256 80.843 us/op 89.437 us/op 0.90
bytes32 toHexString 296.00 ns/op 294.00 ns/op 1.01
bytes32 Buffer.toString(hex) 170.00 ns/op 163.00 ns/op 1.04
bytes32 Buffer.toString(hex) from Uint8Array 242.00 ns/op 241.00 ns/op 1.00
bytes32 Buffer.toString(hex) + 0x 171.00 ns/op 166.00 ns/op 1.03
Return object 10000 times 0.20430 ns/op 0.21950 ns/op 0.93
Throw Error 10000 times 3.1793 us/op 3.4292 us/op 0.93
toHex 98.301 ns/op 98.201 ns/op 1.00
Buffer.from 92.644 ns/op 91.479 ns/op 1.01
shared Buffer 63.376 ns/op 61.829 ns/op 1.03
fastMsgIdFn sha256 / 200 bytes 1.5440 us/op 1.5100 us/op 1.02
fastMsgIdFn h32 xxhash / 200 bytes 158.00 ns/op 155.00 ns/op 1.02
fastMsgIdFn h64 xxhash / 200 bytes 204.00 ns/op 200.00 ns/op 1.02
fastMsgIdFn sha256 / 1000 bytes 4.5510 us/op 4.8900 us/op 0.93
fastMsgIdFn h32 xxhash / 1000 bytes 246.00 ns/op 248.00 ns/op 0.99
fastMsgIdFn h64 xxhash / 1000 bytes 248.00 ns/op 254.00 ns/op 0.98
fastMsgIdFn sha256 / 10000 bytes 39.482 us/op 43.277 us/op 0.91
fastMsgIdFn h32 xxhash / 10000 bytes 1.2140 us/op 1.3170 us/op 0.92
fastMsgIdFn h64 xxhash / 10000 bytes 806.00 ns/op 853.00 ns/op 0.94
send data - 1000 256B messages 4.2640 ms/op 4.4865 ms/op 0.95
send data - 1000 512B messages 5.2454 ms/op 5.0310 ms/op 1.04
send data - 1000 1024B messages 5.4967 ms/op 6.0003 ms/op 0.92
send data - 1000 1200B messages 6.8882 ms/op 6.4023 ms/op 1.08
send data - 1000 2048B messages 67.344 ms/op 12.055 ms/op 5.59
send data - 1000 4096B messages 58.658 ms/op 86.159 ms/op 0.68
send data - 1000 16384B messages 378.83 ms/op 382.08 ms/op 0.99
send data - 1000 65536B messages 1.5639 s/op 1.4968 s/op 1.04
enrSubnets - fastDeserialize 64 bits 755.00 ns/op 774.00 ns/op 0.98
enrSubnets - ssz BitVector 64 bits 275.00 ns/op 257.00 ns/op 1.07
enrSubnets - fastDeserialize 4 bits 112.00 ns/op 97.000 ns/op 1.15
enrSubnets - ssz BitVector 4 bits 266.00 ns/op 254.00 ns/op 1.05
prioritizePeers score -10:0 att 32-0.1 sync 2-0 208.03 us/op 197.80 us/op 1.05
prioritizePeers score 0:0 att 32-0.25 sync 2-0.25 229.83 us/op 218.52 us/op 1.05
prioritizePeers score 0:0 att 32-0.5 sync 2-0.5 320.41 us/op 331.14 us/op 0.97
prioritizePeers score 0:0 att 64-0.75 sync 4-0.75 572.95 us/op 582.10 us/op 0.98
prioritizePeers score 0:0 att 64-1 sync 4-1 694.66 us/op 678.87 us/op 1.02
array of 16000 items push then shift 1.3055 us/op 1.2910 us/op 1.01
LinkedList of 16000 items push then shift 6.9470 ns/op 6.9440 ns/op 1.00
array of 16000 items push then pop 64.669 ns/op 64.880 ns/op 1.00
LinkedList of 16000 items push then pop 6.0310 ns/op 5.9410 ns/op 1.02
array of 24000 items push then shift 1.9305 us/op 1.9006 us/op 1.02
LinkedList of 24000 items push then shift 6.4270 ns/op 6.4990 ns/op 0.99
array of 24000 items push then pop 90.477 ns/op 90.776 ns/op 1.00
LinkedList of 24000 items push then pop 5.9750 ns/op 5.9470 ns/op 1.00
intersect bitArray bitLen 8 4.7780 ns/op 4.7840 ns/op 1.00
intersect array and set length 8 29.748 ns/op 29.557 ns/op 1.01
intersect bitArray bitLen 128 24.043 ns/op 24.123 ns/op 1.00
intersect array and set length 128 503.20 ns/op 512.23 ns/op 0.98
bitArray.getTrueBitIndexes() bitLen 128 914.00 ns/op 907.00 ns/op 1.01
bitArray.getTrueBitIndexes() bitLen 248 1.6480 us/op 1.6380 us/op 1.01
bitArray.getTrueBitIndexes() bitLen 512 3.4330 us/op 3.4060 us/op 1.01
Full columns - reconstruct all 6 blobs 376.85 us/op 104.39 us/op 3.61
Full columns - reconstruct half of the blobs out of 6 61.765 us/op 64.703 us/op 0.95
Full columns - reconstruct single blob out of 6 31.783 us/op 32.127 us/op 0.99
Half columns - reconstruct all 6 blobs 389.13 ms/op 384.41 ms/op 1.01
Half columns - reconstruct half of the blobs out of 6 192.78 ms/op 191.46 ms/op 1.01
Half columns - reconstruct single blob out of 6 69.395 ms/op 68.268 ms/op 1.02
Set add up to 64 items then delete first 1.5722 us/op 1.5270 us/op 1.03
OrderedSet add up to 64 items then delete first 2.4321 us/op 2.3804 us/op 1.02
Set add up to 64 items then delete last 1.7916 us/op 1.7615 us/op 1.02
OrderedSet add up to 64 items then delete last 2.8293 us/op 2.7996 us/op 1.01
Set add up to 64 items then delete middle 1.9058 us/op 1.8921 us/op 1.01
OrderedSet add up to 64 items then delete middle 4.3164 us/op 4.2673 us/op 1.01
Set add up to 128 items then delete first 3.8472 us/op 3.7696 us/op 1.02
OrderedSet add up to 128 items then delete first 5.8580 us/op 5.8078 us/op 1.01
Set add up to 128 items then delete last 3.7410 us/op 3.6738 us/op 1.02
OrderedSet add up to 128 items then delete last 5.4806 us/op 5.4024 us/op 1.01
Set add up to 128 items then delete middle 3.7277 us/op 3.6450 us/op 1.02
OrderedSet add up to 128 items then delete middle 11.566 us/op 10.753 us/op 1.08
Set add up to 256 items then delete first 7.8027 us/op 7.1089 us/op 1.10
OrderedSet add up to 256 items then delete first 11.913 us/op 11.189 us/op 1.06
Set add up to 256 items then delete last 7.4119 us/op 6.7707 us/op 1.09
OrderedSet add up to 256 items then delete last 11.186 us/op 10.630 us/op 1.05
Set add up to 256 items then delete middle 7.2774 us/op 6.8529 us/op 1.06
OrderedSet add up to 256 items then delete middle 34.498 us/op 32.936 us/op 1.05
runFastConfirmationRules vc:100000 bc:96 eq:0 4.7415 ms/op 4.2283 ms/op 1.12
runFastConfirmationRules vc:600000 bc:96 eq:0 34.046 ms/op 33.389 ms/op 1.02
runFastConfirmationRules vc:1000000 bc:96 eq:0 58.486 ms/op 54.638 ms/op 1.07
runFastConfirmationRules vc:600000 bc:320 eq:0 33.864 ms/op 33.271 ms/op 1.02
runFastConfirmationRules vc:100000 bc:96 eq:1000 1.0982 s/op 1.0479 s/op 1.05
pass gossip attestations to forkchoice per slot 2.5927 ms/op 2.5840 ms/op 1.00
forkChoice updateHead vc 100000 bc 64 eq 0 409.90 us/op 423.55 us/op 0.97
forkChoice updateHead vc 600000 bc 64 eq 0 2.5124 ms/op 2.5761 ms/op 0.98
forkChoice updateHead vc 1000000 bc 64 eq 0 4.0932 ms/op 4.2651 ms/op 0.96
forkChoice updateHead vc 600000 bc 320 eq 0 2.4586 ms/op 2.6098 ms/op 0.94
forkChoice updateHead vc 600000 bc 1200 eq 0 2.5186 ms/op 2.5832 ms/op 0.98
forkChoice updateHead vc 600000 bc 7200 eq 0 2.7674 ms/op 2.9399 ms/op 0.94
forkChoice updateHead vc 600000 bc 64 eq 1000 2.4529 ms/op 2.3400 ms/op 1.05
forkChoice updateHead vc 600000 bc 64 eq 10000 2.5288 ms/op 2.4424 ms/op 1.04
forkChoice updateHead vc 600000 bc 64 eq 300000 6.5263 ms/op 6.9825 ms/op 0.93
computeDeltas 1400000 validators 0% inactive 12.319 ms/op 11.532 ms/op 1.07
computeDeltas 1400000 validators 10% inactive 11.611 ms/op 10.885 ms/op 1.07
computeDeltas 1400000 validators 20% inactive 10.972 ms/op 10.379 ms/op 1.06
computeDeltas 1400000 validators 50% inactive 8.9757 ms/op 8.4444 ms/op 1.06
computeDeltas 2100000 validators 0% inactive 18.411 ms/op 17.283 ms/op 1.07
computeDeltas 2100000 validators 10% inactive 17.466 ms/op 16.481 ms/op 1.06
computeDeltas 2100000 validators 20% inactive 16.483 ms/op 15.355 ms/op 1.07
computeDeltas 2100000 validators 50% inactive 13.406 ms/op 10.158 ms/op 1.32
altair processAttestation - 250000 vs - 7PWei normalcase 1.6379 ms/op 1.6857 ms/op 0.97
altair processAttestation - 250000 vs - 7PWei worstcase 2.3254 ms/op 2.4996 ms/op 0.93
altair processAttestation - setStatus - 1/6 committees join 102.61 us/op 106.28 us/op 0.97
altair processAttestation - setStatus - 1/3 committees join 190.96 us/op 194.76 us/op 0.98
altair processAttestation - setStatus - 1/2 committees join 280.40 us/op 284.75 us/op 0.98
altair processAttestation - setStatus - 2/3 committees join 370.88 us/op 375.34 us/op 0.99
altair processAttestation - setStatus - 4/5 committees join 496.93 us/op 502.62 us/op 0.99
altair processAttestation - setStatus - 100% committees join 588.89 us/op 598.21 us/op 0.98
altair processBlock - 250000 vs - 7PWei normalcase 3.8404 ms/op 3.1501 ms/op 1.22
altair processBlock - 250000 vs - 7PWei normalcase hashState 14.217 ms/op 16.906 ms/op 0.84
altair processBlock - 250000 vs - 7PWei worstcase 19.677 ms/op 20.100 ms/op 0.98
altair processBlock - 250000 vs - 7PWei worstcase hashState 42.497 ms/op 38.699 ms/op 1.10
phase0 processBlock - 250000 vs - 7PWei normalcase 1.4779 ms/op 1.4428 ms/op 1.02
phase0 processBlock - 250000 vs - 7PWei worstcase 17.319 ms/op 16.738 ms/op 1.03
altair processEth1Data - 250000 vs - 7PWei normalcase 291.87 us/op 283.06 us/op 1.03
getExpectedWithdrawals 250000 eb:1,eth1:1,we:0,wn:0,smpl:16 3.6640 us/op 3.2690 us/op 1.12
getExpectedWithdrawals 250000 eb:0.95,eth1:0.1,we:0.05,wn:0,smpl:220 20.762 us/op 21.708 us/op 0.96
getExpectedWithdrawals 250000 eb:0.95,eth1:0.3,we:0.05,wn:0,smpl:43 5.5750 us/op 5.8990 us/op 0.95
getExpectedWithdrawals 250000 eb:0.95,eth1:0.7,we:0.05,wn:0,smpl:19 3.4530 us/op 3.4770 us/op 0.99
getExpectedWithdrawals 250000 eb:0.1,eth1:0.1,we:0,wn:0,smpl:1021 90.521 us/op 96.985 us/op 0.93
getExpectedWithdrawals 250000 eb:0.03,eth1:0.03,we:0,wn:0,smpl:11778 1.3547 ms/op 1.3586 ms/op 1.00
getExpectedWithdrawals 250000 eb:0.01,eth1:0.01,we:0,wn:0,smpl:16384 1.7662 ms/op 1.7933 ms/op 0.98
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,smpl:16384 1.7532 ms/op 1.8122 ms/op 0.97
getExpectedWithdrawals 250000 eb:0,eth1:0,we:0,wn:0,nocache,smpl:16384 3.5525 ms/op 3.6681 ms/op 0.97
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,smpl:16384 2.0071 ms/op 2.0403 ms/op 0.98
getExpectedWithdrawals 250000 eb:0,eth1:1,we:0,wn:0,nocache,smpl:16384 3.8678 ms/op 3.9844 ms/op 0.97
Tree 40 250000 create 356.21 ms/op 355.87 ms/op 1.00
Tree 40 250000 get(125000) 94.509 ns/op 90.689 ns/op 1.04
Tree 40 250000 set(125000) 998.11 ns/op 972.40 ns/op 1.03
Tree 40 250000 toArray() 9.9212 ms/op 15.840 ms/op 0.63
Tree 40 250000 iterate all - toArray() + loop 10.031 ms/op 16.004 ms/op 0.63
Tree 40 250000 iterate all - get(i) 32.821 ms/op 38.234 ms/op 0.86
Array 250000 create 2.0674 ms/op 2.0884 ms/op 0.99
Array 250000 clone - spread 659.79 us/op 642.27 us/op 1.03
Array 250000 get(125000) 0.30700 ns/op 0.28600 ns/op 1.07
Array 250000 set(125000) 0.30600 ns/op 0.29300 ns/op 1.04
Array 250000 iterate all - loop 58.218 us/op 56.119 us/op 1.04
phase0 afterProcessEpoch - 250000 vs - 7PWei 53.039 ms/op 51.001 ms/op 1.04
Array.fill - length 1000000 2.1718 ms/op 2.1067 ms/op 1.03
Array push - length 1000000 7.3921 ms/op 8.7343 ms/op 0.85
Array.get 0.20916 ns/op 0.19886 ns/op 1.05
Uint8Array.get 0.23095 ns/op 0.24208 ns/op 0.95
phase0 beforeProcessEpoch - 250000 vs - 7PWei 13.925 ms/op 18.999 ms/op 0.73
altair processEpoch - mainnet_e81889 325.63 ms/op 334.05 ms/op 0.97
mainnet_e81889 - altair beforeProcessEpoch 33.489 ms/op 19.704 ms/op 1.70
mainnet_e81889 - altair processJustificationAndFinalization 6.0940 us/op 6.4660 us/op 0.94
mainnet_e81889 - altair processInactivityUpdates 3.5377 ms/op 3.4645 ms/op 1.02
mainnet_e81889 - altair processRewardsAndPenalties 16.890 ms/op 19.323 ms/op 0.87
mainnet_e81889 - altair processRegistryUpdates 544.00 ns/op 531.00 ns/op 1.02
mainnet_e81889 - altair processSlashings 148.00 ns/op 136.00 ns/op 1.09
mainnet_e81889 - altair processEth1DataReset 141.00 ns/op 142.00 ns/op 0.99
mainnet_e81889 - altair processEffectiveBalanceUpdates 1.6425 ms/op 3.6018 ms/op 0.46
mainnet_e81889 - altair processSlashingsReset 702.00 ns/op 674.00 ns/op 1.04
mainnet_e81889 - altair processRandaoMixesReset 1.3110 us/op 1.3840 us/op 0.95
mainnet_e81889 - altair processHistoricalRootsUpdate 146.00 ns/op 131.00 ns/op 1.11
mainnet_e81889 - altair processParticipationFlagUpdates 439.00 ns/op 426.00 ns/op 1.03
mainnet_e81889 - altair processSyncCommitteeUpdates 117.00 ns/op 107.00 ns/op 1.09
mainnet_e81889 - altair afterProcessEpoch 40.305 ms/op 41.292 ms/op 0.98
capella processEpoch - mainnet_e217614 942.53 ms/op 988.56 ms/op 0.95
mainnet_e217614 - capella beforeProcessEpoch 56.482 ms/op 56.440 ms/op 1.00
mainnet_e217614 - capella processJustificationAndFinalization 6.5450 us/op 8.0110 us/op 0.82
mainnet_e217614 - capella processInactivityUpdates 16.348 ms/op 10.980 ms/op 1.49
mainnet_e217614 - capella processRewardsAndPenalties 97.283 ms/op 105.01 ms/op 0.93
mainnet_e217614 - capella processRegistryUpdates 4.4480 us/op 4.5490 us/op 0.98
mainnet_e217614 - capella processSlashings 139.00 ns/op 134.00 ns/op 1.04
mainnet_e217614 - capella processEth1DataReset 141.00 ns/op 127.00 ns/op 1.11
mainnet_e217614 - capella processEffectiveBalanceUpdates 5.6111 ms/op 5.5332 ms/op 1.01
mainnet_e217614 - capella processSlashingsReset 668.00 ns/op 679.00 ns/op 0.98
mainnet_e217614 - capella processRandaoMixesReset 1.1110 us/op 1.3270 us/op 0.84
mainnet_e217614 - capella processHistoricalRootsUpdate 140.00 ns/op 130.00 ns/op 1.08
mainnet_e217614 - capella processParticipationFlagUpdates 454.00 ns/op 426.00 ns/op 1.07
mainnet_e217614 - capella afterProcessEpoch 103.92 ms/op 110.00 ms/op 0.94
phase0 processEpoch - mainnet_e58758 296.89 ms/op 310.88 ms/op 0.95
mainnet_e58758 - phase0 beforeProcessEpoch 64.022 ms/op 63.984 ms/op 1.00
mainnet_e58758 - phase0 processJustificationAndFinalization 6.5360 us/op 5.9160 us/op 1.10
mainnet_e58758 - phase0 processRewardsAndPenalties 16.488 ms/op 15.455 ms/op 1.07
mainnet_e58758 - phase0 processRegistryUpdates 2.1360 us/op 2.2400 us/op 0.95
mainnet_e58758 - phase0 processSlashings 136.00 ns/op 134.00 ns/op 1.01
mainnet_e58758 - phase0 processEth1DataReset 136.00 ns/op 131.00 ns/op 1.04
mainnet_e58758 - phase0 processEffectiveBalanceUpdates 776.16 us/op 832.59 us/op 0.93
mainnet_e58758 - phase0 processSlashingsReset 836.00 ns/op 933.00 ns/op 0.90
mainnet_e58758 - phase0 processRandaoMixesReset 1.3520 us/op 1.4890 us/op 0.91
mainnet_e58758 - phase0 processHistoricalRootsUpdate 250.00 ns/op 139.00 ns/op 1.80
mainnet_e58758 - phase0 processParticipationRecordUpdates 1.2060 us/op 1.2420 us/op 0.97
mainnet_e58758 - phase0 afterProcessEpoch 31.858 ms/op 32.930 ms/op 0.97
phase0 processEffectiveBalanceUpdates - 250000 normalcase 938.77 us/op 1.0719 ms/op 0.88
phase0 processEffectiveBalanceUpdates - 250000 worstcase 0.5 1.5165 ms/op 1.2024 ms/op 1.26
altair processInactivityUpdates - 250000 normalcase 9.7847 ms/op 11.959 ms/op 0.82
altair processInactivityUpdates - 250000 worstcase 10.347 ms/op 13.015 ms/op 0.80
phase0 processRegistryUpdates - 250000 normalcase 2.1800 us/op 2.2280 us/op 0.98
phase0 processRegistryUpdates - 250000 badcase_full_deposits 150.11 us/op 147.20 us/op 1.02
phase0 processRegistryUpdates - 250000 worstcase 0.5 64.364 ms/op 75.991 ms/op 0.85
altair processRewardsAndPenalties - 250000 normalcase 15.941 ms/op 13.267 ms/op 1.20
altair processRewardsAndPenalties - 250000 worstcase 15.516 ms/op 12.924 ms/op 1.20
phase0 getAttestationDeltas - 250000 normalcase 5.1319 ms/op 5.4135 ms/op 0.95
phase0 getAttestationDeltas - 250000 worstcase 5.1159 ms/op 5.5036 ms/op 0.93
phase0 processSlashings - 250000 worstcase 56.490 us/op 59.929 us/op 0.94
altair processSyncCommitteeUpdates - 250000 9.7155 ms/op 10.172 ms/op 0.96
BeaconState.hashTreeRoot - No change 177.00 ns/op 176.00 ns/op 1.01
BeaconState.hashTreeRoot - 1 full validator 81.383 us/op 74.673 us/op 1.09
BeaconState.hashTreeRoot - 32 full validator 863.94 us/op 859.50 us/op 1.01
BeaconState.hashTreeRoot - 512 full validator 7.7641 ms/op 6.2519 ms/op 1.24
BeaconState.hashTreeRoot - 1 validator.effectiveBalance 112.70 us/op 84.407 us/op 1.34
BeaconState.hashTreeRoot - 32 validator.effectiveBalance 1.4778 ms/op 1.1494 ms/op 1.29
BeaconState.hashTreeRoot - 512 validator.effectiveBalance 21.757 ms/op 21.191 ms/op 1.03
BeaconState.hashTreeRoot - 1 balances 84.229 us/op 77.926 us/op 1.08
BeaconState.hashTreeRoot - 32 balances 897.54 us/op 724.71 us/op 1.24
BeaconState.hashTreeRoot - 512 balances 5.4359 ms/op 6.3702 ms/op 0.85
BeaconState.hashTreeRoot - 250000 balances 162.50 ms/op 158.92 ms/op 1.02
aggregationBits - 2048 els - zipIndexesInBitList 19.614 us/op 19.203 us/op 1.02
regular array get 100000 times 22.708 us/op 22.459 us/op 1.01
wrappedArray get 100000 times 22.843 us/op 22.363 us/op 1.02
arrayWithProxy get 100000 times 10.588 ms/op 9.7161 ms/op 1.09
ssz.Root.equals 21.385 ns/op 20.847 ns/op 1.03
byteArrayEquals 21.139 ns/op 20.841 ns/op 1.01
Buffer.compare 8.8780 ns/op 8.5820 ns/op 1.03
processSlot - 1 slots 9.8460 us/op 9.4430 us/op 1.04
processSlot - 32 slots 2.3273 ms/op 2.3350 ms/op 1.00
getEffectiveBalanceIncrementsZeroInactive - 250000 vs - 7PWei 3.7266 ms/op 7.5089 ms/op 0.50
getCommitteeAssignments - req 1 vs - 250000 vc 1.6475 ms/op 1.6978 ms/op 0.97
getCommitteeAssignments - req 100 vs - 250000 vc 3.3985 ms/op 3.4683 ms/op 0.98
getCommitteeAssignments - req 1000 vs - 250000 vc 3.6317 ms/op 3.7234 ms/op 0.98
findModifiedValidators - 10000 modified validators 821.33 ms/op 749.51 ms/op 1.10
findModifiedValidators - 1000 modified validators 444.16 ms/op 450.34 ms/op 0.99
findModifiedValidators - 100 modified validators 281.70 ms/op 296.16 ms/op 0.95
findModifiedValidators - 10 modified validators 214.98 ms/op 190.69 ms/op 1.13
findModifiedValidators - 1 modified validators 190.38 ms/op 152.16 ms/op 1.25
findModifiedValidators - no difference 153.72 ms/op 148.42 ms/op 1.04
migrate state 1500000 validators, 3400 modified, 2000 new 3.7595 s/op 3.4185 s/op 1.10
RootCache.getBlockRootAtSlot - 250000 vs - 7PWei 3.8000 ns/op 3.6500 ns/op 1.04
state getBlockRootAtSlot - 250000 vs - 7PWei 421.83 ns/op 451.67 ns/op 0.93
computeProposerIndex 100000 validators 1.3046 ms/op 1.3191 ms/op 0.99
getNextSyncCommitteeIndices 1000 validators 2.7600 ms/op 2.8066 ms/op 0.98
getNextSyncCommitteeIndices 10000 validators 24.298 ms/op 24.680 ms/op 0.98
getNextSyncCommitteeIndices 100000 validators 85.088 ms/op 84.662 ms/op 1.01
computeProposers - vc 250000 525.80 us/op 535.71 us/op 0.98
computeEpochShuffling - vc 250000 37.293 ms/op 38.133 ms/op 0.98
getNextSyncCommittee - vc 250000 8.9888 ms/op 9.3689 ms/op 0.96
nodejs block root to RootHex using toHex 95.719 ns/op 90.842 ns/op 1.05
nodejs block root to RootHex using toRootHex 60.055 ns/op 59.099 ns/op 1.02
nodejs fromHex(blob) 821.59 us/op 815.74 us/op 1.01
nodejs fromHexInto(blob) 649.65 us/op 601.65 us/op 1.08
nodejs block root to RootHex using the deprecated toHexString 489.68 ns/op 449.88 ns/op 1.09
nodejs byteArrayEquals 32 bytes (block root) 25.938 ns/op 25.053 ns/op 1.04
nodejs byteArrayEquals 48 bytes (pubkey) 37.574 ns/op 36.044 ns/op 1.04
nodejs byteArrayEquals 96 bytes (signature) 38.913 ns/op 33.627 ns/op 1.16
nodejs byteArrayEquals 1024 bytes 45.028 ns/op 39.331 ns/op 1.14
nodejs byteArrayEquals 131072 bytes (blob) 1.7431 us/op 1.7147 us/op 1.02
browser block root to RootHex using toHex 146.12 ns/op 139.04 ns/op 1.05
browser block root to RootHex using toRootHex 130.78 ns/op 126.34 ns/op 1.04
browser fromHex(blob) 1.6754 ms/op 1.6720 ms/op 1.00
browser fromHexInto(blob) 601.58 us/op 604.24 us/op 1.00
browser block root to RootHex using the deprecated toHexString 310.70 ns/op 318.00 ns/op 0.98
browser byteArrayEquals 32 bytes (block root) 27.234 ns/op 27.271 ns/op 1.00
browser byteArrayEquals 48 bytes (pubkey) 37.944 ns/op 38.499 ns/op 0.99
browser byteArrayEquals 96 bytes (signature) 71.257 ns/op 71.490 ns/op 1.00
browser byteArrayEquals 1024 bytes 725.39 ns/op 728.10 ns/op 1.00
browser byteArrayEquals 131072 bytes (blob) 91.119 us/op 92.057 us/op 0.99

by benchmarkbot/action

Comment thread packages/fork-choice/src/protoArray/protoArray.ts Outdated
Comment thread packages/beacon-node/test/spec/utils/forkChoiceTestRunner.ts

@twoeths twoeths left a comment

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.

looks good to me as an infrastructure for compliance test
right now the getCommitteeFranction() doesn't follow forkchoice spec because we store weight by ETH, not by gwei. I suspect we did that even before proposer boost was landed, and we did not revisit.
one way to do that is to let forkchoice store weight in ETH by a scale of SLOTS_PER_EPOCH * 100, then we can keep it as integer without an overflow issue. But this is a separate issue.

ensi321 and others added 2 commits July 22, 2026 22:09
… for getCommitteeFraction divergence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mpliance

# Conflicts:
#	packages/beacon-node/test/spec/utils/specTestIterator.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ensi321
ensi321 merged commit 4606097 into unstable Jul 23, 2026
18 of 19 checks passed
@ensi321
ensi321 deleted the nc/fork-choice-compliance branch July 23, 2026 23:02
@wemeetagain

Copy link
Copy Markdown
Member

🎉 This PR is included in v1.46.0 🎉

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants