Skip to content

feat(forkchoice): implement the forkchoice module - #246

Merged
wemeetagain merged 66 commits into
mainfrom
gr/feature/forkchoice-z
May 7, 2026
Merged

feat(forkchoice): implement the forkchoice module#246
wemeetagain merged 66 commits into
mainfrom
gr/feature/forkchoice-z

Conversation

@GrapeBaBa

@GrapeBaBa GrapeBaBa commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

Motivation

Lodestar-z currently lacks a fork-choice implementation. This implementation targets Lodestar's unstable branch, which includes the upcoming Gloas/ePBS fork with payload-timeliness and builder-boost mechanics.

Description

  • proto_array.zig — ProtoArray implementing LMD-GHOST: findHead, applyScoreChanges, onBlock, onAttestation, node viability/best-child comparison, maybePrune, isDescendant, and ePBS payload status tracking
  • fork_choice.zig — ForkChoice orchestrator: checkpoint management, onBlock/onAttestation with full validation, proposer boost/reorg logic, getHead, updateTime, ancestor queries, and debug/export methods
  • compute_deltas.zig — Vote-weight delta computation from attestation changes
  • vote_tracker.zig — Per-validator vote tracking (current/next root + epoch)
  • store.zig — ForkChoiceStore holding justified/finalized checkpoints, equivocation tracking, proposer boost state

Register fork_choice module in zbuild.zon and implement foundational
types ported from Lodestar's protoArray/interface.ts and errors.ts:
- ExecutionStatus, DataAvailabilityStatus enums
- ProtoBlock, ProtoNode, BlockExtraMeta structs
- LVHExecResponse types for EL validity responses
- ProtoArrayError and ForkChoiceError error sets
- Delete errors.zig; move error sets to proto_node.zig with TODOs for
  future relocation (TigerStyle: declare at point of use)
- Add vote_tracker.zig with SoA-backed Votes (MultiArrayList) and
  NULL_VOTE_INDEX sentinel for cache-efficient computeDeltas
- Refine BlockExtraMeta: 2-variant union(enum) with PostMergeMeta.init()
  assert to reject pre_merge status
- Re-export ZERO_HASH from constants (remove duplication)
- Rename block_hash_hex -> block_hash, slices() -> fields()
- Clean up comments: remove emoji and TS-equivalent references
…s spec

- ProtoNode: flat layout (all ProtoBlock fields inline) with
  fromBlock()/toBlock() comptime conversion
- VoteTracker: next_epoch -> next_slot, add payload_present
  (Gloas LatestMessage spec)
- Use field defaults instead of DEFAULT constants (.{} construction)
- Remove Votes.init(), use field default for multi_list
- Add doc comments to all ProtoBlock/ProtoNode fields
- Remove emoji and TS-equivalent references from comments
- Update task-04, task-05 design docs
- Add lodestar-ts-reading-guide.md
Port computeDeltas from Lodestar TS with Lighthouse-style checked
arithmetic. Uses pointer-equality optimization for balance comparison,
sorted equivocating index advancement, and heap-allocated sort buffer.
Includes 9 tests ported from TS and Lighthouse test suites.
…row sequence

Consolidate 7 tests into 4 by merging init/defaults/no-op cases into
a single table-driven grow sequence test.
…rison, and ePBS support

- Add proto_array.zig with ProtoArray struct: onBlock (pre-Gloas/Gloas),
  onPayload, maybeUpdateBestChildAndDescendant, getAncestor, nodeIsViableForHead,
  isFinalizedRootOrDescendant, and PTC (notifyPtcMessages, isPayloadTimely,
  shouldExtendPayload, getPayloadStatusTiebreaker)
- Add validateNodeByIndex/propagateValidExecutionStatusByIndex with error on
  Invalid→Valid transition (consensus safety)
- Use TigerStyle infallible pattern: ensureUnusedCapacity + appendAssumeCapacity
- Inline node comparison in maybeUpdateBestChildAndDescendant matching TS structure
- Import computeEpochAtSlot/computeStartSlotAtEpoch from state_transition module
- Refactor indices from u32 to usize throughout, remove wrapper functions
- Add PayloadStatus enum, PTC_SIZE preset constant, VariantIndices type
- Remove duplicate ProtoArrayError from proto_node.zig (now in proto_array.zig)
- Change NULL_VOTE_INDEX to std.math.maxInt(u32), use strict < in len() assert
- Port TS interface.ts comments to proto_node.zig type definitions
…y logic

Implement weight propagation (two-pass backward iteration), head
selection via best_descendant chains, and Gloas-specific node
comparison with payload status tiebreakers.

Key additions to ProtoArray:
- applyScoreChanges: proposer boost undo/redo, checked arithmetic,
  weight back-propagation, best child/descendant recomputation
- findHead: O(1) head via justified -> best_descendant chain
- nodeIsViableForHead: FFG filter with pull-up justification
- isFinalizedRootOrDescendant: 4 fast-path checkpoint checks +
  parent chain walk fallback
- getAncestor: slot-based ancestor lookup via parent_root chain
- shouldExtendPayload / isPayloadTimely: PTC vote counting for
  Gloas payload timeliness
- getPayloadStatusTiebreaker: EMPTY vs FULL comparison for
  same-root Gloas nodes
- propagateValidExecutionStatusByIndex: upward EL status promotion

Also changes ProtoNode index fields from ?usize to ?u32 for
TigerStyle explicit-size compliance.
Signed-off-by: Chen Kai <281165273grape@gmail.com>
- Merge 3 Gloas test helpers into 2: asGloas + asGloasWithParentBlockHash
- Remove unused block_hash_from_bid from test helpers (no production code reads it)
- Add tree/diagram comments to all 50 proto_array tests
- Clean up stale block_hash_from_bid references in comments
- Rename onPayload → onExecutionPayload, add UnknownBlock/PreGloasBlock errors
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request lays the groundwork for the forkchoice module, a critical component for determining the canonical chain in a blockchain network. It introduces the necessary data structures and initial logic required to manage the block tree, track validator votes, and compute block weights, which are fundamental for implementing the LMD-GHOST consensus algorithm.

Highlights

  • New Module Introduction: Introduced the foundational forkchoice module, including core data structures and logic for block processing and validator vote tracking.
  • Build System Integration: Integrated the new forkchoice module into the build system (build.zig and zbuild.zon), enabling its compilation and testing.
  • Core Data Structures and Logic: Defined key constants and types within the forkchoice module, such as ProtoBlock, ProtoNode, ExecutionStatus, and VoteTracker, which are essential for the LMD-GHOST consensus algorithm.
  • Configuration Update: Added PTC_SIZE constant to src/preset/preset.zig for both Mainnet and Minimal configurations.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • build.zig
    • Added the fork_choice module to the build system.
    • Configured test targets for the fork_choice module.
    • Added imports for the fork_choice module.
  • src/fork_choice/compute_deltas.zig
    • Added a new file implementing the computeDeltas function, which calculates per-node weight deltas based on vote changes and balance updates, handling equivocating validators.
  • src/fork_choice/proto_node.zig
    • Added a new file defining ProtoBlock and ProtoNode structures, along with ExecutionStatus, DataAvailabilityStatus, PayloadStatus, and error types relevant to fork choice.
  • src/fork_choice/root.zig
    • Added a new root file for the fork_choice module, exporting its public components.
  • src/fork_choice/vote_tracker.zig
    • Added a new file defining VoteTracker and Votes structures for efficient storage and management of validator votes.
  • src/preset/preset.zig
    • Added PTC_SIZE constant to PresetMainnet and PresetMinimal structs.
  • zbuild.zon
    • Added the fork_choice module definition and its imports.
Activity
  • No activity has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@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 new forkchoice module, which is a substantial and well-implemented feature. The code quality is high, with good use of data structures for performance (like SoA in vote_tracker.zig) and comprehensive tests. My review focuses on the compute_deltas.zig file, where I've identified a critical correctness issue regarding a type mismatch, a violation of the function length limit as per the style guide, and some opportunities to improve clarity by splitting compound conditions. I also noted a minor memory leak in the test setup. The rest of the new modules are well-structured and adhere to the repository's style guide.

Comment thread src/fork_choice/compute_deltas.zig
Comment thread src/fork_choice/compute_deltas.zig Outdated
Comment thread src/fork_choice/compute_deltas.zig Outdated
Comment thread src/fork_choice/compute_deltas.zig Outdated
…ork parameterization

Convert ProtoNode and ProtoArray from plain structs to comptime
functions parameterized by ForkSeq, following the BeaconState(fork)
pattern. This eliminates the VariantIndices tagged union and replaces
runtime fork branching with compile-time monomorphization:

- ProtoNode(fork): Gloas ePBS fields (builder_index, block_hash_from_bid,
  parent_block_hash, payload_status) are void for pre-Gloas forks,
  achieving zero storage cost.

- ProtoArray(fork): IndexEntry is u32 (pre-Gloas) or GloasIndices
  (Gloas+) at compile time. PTC votes map is void for pre-Gloas.
  All methods that previously switched on VariantIndices now use
  comptime if(is_gloas) branches.

- Fork transition support: Gloas ProtoArray correctly handles
  pre-Gloas blocks (parent_block_hash == null) by routing them
  through onBlockPreGloas and storing GloasIndices with all fields
  pointing to the same node index.

- Tests: 3 VariantIndices unit tests removed (type no longer exists).
  Pre-Gloas tests use ProtoArray(.phase0), Gloas tests use
  ProtoArray(.gloas). All 88 fork_choice tests pass.
- Simplify getParent param from degenerate comptime conditional to ?Root
- Clean up redundant dead logic in getParentPayloadStatus
- Add safe switch guard in onExecutionPayload for union access
Add AnyProtoArray = union(ForkSeq) as a runtime dispatch layer for the
comptime-parameterized ProtoArray(ForkSeq). Follows the AnyBeaconState
pattern with inline else dispatch across all fork variants.

Wrapped public methods: init, deinit, initialize, getDefaultVariant,
getDefaultNodeIndex, getNodeIndexByRootAndStatus, hasBlock, onBlock,
onExecutionPayload, applyScoreChanges, findHeadBlock, getBlock, length,
isDescendant, validateLatestHash, maybePrune.

Includes upgradeToFork for fork transitions with node/index migration
(pre-Gloas u32 -> Gloas GloasIndices).
…mptime fork parameterization"

This reverts commit 826e5b5.
…stor queries (tasks 9-11)

Complete ProtoArray with pruning, execution status validation, ancestor
iteration, isDescendant, getCommonAncestor, and getAllAncestor/NonAncestor
queries. All methods include comprehensive tests covering edge cases
including Gloas ePBS variant handling.
Add ForkChoice wrapping ProtoArray, Votes, and checkpoint state with
full public API: onBlock, onAttestation, getHead, setProposerBoost,
onAttesterSlashing, prune, validateLatestHash, and Gloas ePBS methods
(onExecutionPayload, notifyPtcMessages). Pre-allocated DeltasCache
eliminates per-slot allocation in the getHead hot path.
Signed-off-by: Chen Kai <281165273grape@gmail.com>
@GrapeBaBa
GrapeBaBa force-pushed the gr/feature/forkchoice-z branch 2 times, most recently from 428f6db to 427dd23 Compare March 22, 2026 14:37
Gloas fork is not yet defined in upstream config. Revert premature addition.
…ockByRoot

- Add fork_choice tests to CI workflow
- Update ForkChoice.isDescendant to accept explicit PayloadStatus params
- Add getCanonicalBlockByRoot to walk head ancestor chain
- Add payload_status to HeadResult for Gloas ePBS support
…rray

- Extract ForkChoiceStore to store.zig with Rc-based balance sharing
  (matching state_transition pattern: init/acquire/release)
- Add CheckpointWithPayloadStatus, JustifiedBalancesGetter (context+fn),
  EventCallback, ForkChoiceStoreEvents, computeTotalBalance
- Merge proto_node.zig types and tests into proto_array.zig
- Update compute_deltas to take *const EquivocatingIndices
- Add store unit tests (Rc sharing, separation, events, leak detection)
@lodekeeper-z

Copy link
Copy Markdown
Contributor

Hey @GrapeBaBa — CI is failing with unable to load 'src/fork_choice/proto_node.zig': FileNotFound. Looks like the latest commit removed/renamed proto_node.zig but root.zig still imports it. Quick fix should unblock CI 👍

@lodekeeper-z lodekeeper-z 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.

Thorough review of the forkchoice module. Impressive scope — 6.3k lines covering the core DAG (ProtoArray), LMD-GHOST weight computation, Gloas ePBS multi-node model, PTC voting, and optimistic sync. The test suite is comprehensive with good coverage of Gloas variant linking and weight propagation.

Main blockers are the CI-breaking import and a couple of type mismatches that will prevent compilation. Architecture concerns are lower priority but worth discussing before this moves out of draft.

See inline comments for details.

Comment thread src/fork_choice/fork_choice.zig Outdated
Comment thread src/fork_choice/fork_choice.zig Outdated
Comment thread src/fork_choice/fork_choice.zig Outdated
Comment thread src/fork_choice/store.zig
Comment thread src/fork_choice/store.zig
///
/// This is only an approximation for two reasons:
/// - The actual block DAG in `ProtoArray`.
/// - `time` is represented using `Slot` instead of UNIX epoch `u64`.

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.

🟡 ForkChoiceStore overlaps significantly with ForkChoice

Both structs track:

  • justified/finalized checkpoints
  • equivocating indices
  • current slot
  • justified balances

ForkChoice has its own checkpoint management (updateJustifiedCheckpoint, updateFinalizedCheckpoint, updateUnrealizedCheckpoints) and ForkChoiceStore has setJustified, setFinalizedCheckpoint.

Is the intent that ForkChoiceStore replaces the checkpoint management in ForkChoice, or do they serve different layers? If ForkChoiceStore is the high-level store (matching the spec's Store) and ForkChoice is the lower-level ProtoArray wrapper, the boundary should be clearer — currently both could manage the same state independently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this is intentional

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.

Got it — makes sense as a deliberate two-layer design. ForkChoiceStore = spec Store (high-level checkpoint management), ForkChoice = ProtoArray wrapper (weight/head computation). The overlap is intentional separation of concerns. 👍


// Check if parent exists by getting variants
if (self.indices.get(block.parent_root)) |parent_vi| {
parent_index = switch (parent_vi) {

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.

🟡 onBlockPreGloas allows orphan blocks (unknown parent)

node.parent = self.getNodeIndexByRootAndStatus(block.parent_root, .full);

If the parent root is not in the DAG, node.parent is null and the block is silently inserted as an orphan. This is fine for genesis, but for non-genesis blocks it means:

  1. The block won't participate in weight propagation (no parent to propagate to)
  2. It won't be prunable via finalization ancestry

The Lodestar TS implementation rejects blocks with unknown parents in onBlock. The ForkChoice.onBlock wrapper does validate this, but ProtoArray.onBlock doesn't — so direct callers of ProtoArray could insert orphans.

Consider: should ProtoArray enforce this invariant, or is it intentionally delegated to the ForkChoice layer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is same with TS implementation, @lodekeeper-z can you recheck?

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.

You're right — I rechecked. TS ProtoArray.onBlock does allow orphan insertion (line 455: // else: parent doesn't exist, parentIndex remains undefined). The parent validation happens at the ForkChoice layer, not ProtoArray. Same pattern here. Thanks for the correction.

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.

You're right — I rechecked. TS ProtoArray.onBlock does allow orphan insertion (line 455: // else: parent doesn't exist, parentIndex remains undefined). The parent validation happens at the ForkChoice layer, not ProtoArray. Same pattern here. Thanks for the correction.

Comment thread src/fork_choice/proto_array.zig
Comment thread src/fork_choice/compute_deltas.zig
Comment thread src/fork_choice/compute_deltas.zig
lodekeeper-z added a commit to lodekeeper-z/lodestar-z that referenced this pull request Mar 24, 2026
Copy GrapeBaBa's fork choice implementation (6.3k lines):
- ProtoArray DAG with LMD-GHOST head selection
- ForkChoice with onBlock/onAttestation/getHead/prune
- compute_deltas for vote weight calculation
- ForkChoiceStore for checkpoint tracking
- VoteTracker for per-validator votes

Based on ChainSafe#246.

🤖 Generated with AI assistance
lodekeeper-z added a commit to lodekeeper-z/lodestar-z that referenced this pull request Mar 24, 2026
Replace naive HeadTracker with GrapeBaBa's proto-array fork choice.
Wire onBlock into block import pipeline. Use getHead() for head
selection. Based on ChainSafe#246.

Changes:
- ForkChoice wired into BlockImporter.importBlock():
  builds ProtoBlock from post-state and calls fc.onBlock()
- BeaconNode.initFromGenesis() initializes ForkChoice with genesis anchor
- BeaconNode.getHead() uses fc.head for slot/root/state_root
- BeaconNode.getStatus() uses fc checkpoints for finalized_epoch/root
- BeaconNode.getSyncStatus() reads head_slot from fork choice
- preset: add PTC_SIZE (Gloas ePBS) required by proto_array.zig
- Optional ForkChoice (?*ForkChoice): falls back to HeadTracker
  when initFromGenesis has not been called yet (e.g., in tests)
- HeadTracker slot_roots map preserved for req/resp range queries

🤖 Generated with AI assistance
lodekeeper-z added a commit to lodekeeper-z/lodestar-z that referenced this pull request Mar 24, 2026
- Fork choice: 6.3k lines from GrapeBaBa's PR ChainSafe#246 (proto-array, LMD-GHOST)
- Sync manager: range sync with batching/retry (WIP - 0.16 API compat)
- Discovery service: bridges discv5 → P2P with bootnode seeding
- Bootnodes: mainnet defaults (Teku, Prysm, Lighthouse ENRs)
- Build.zig: discv5 module wired into networking

Some sync tests have 0.16 ArrayList/BoundedArray compat issues (WIP).

🤖 Generated with AI assistance
These methods were dead code — proposer boost is set inline in onBlock
and cleared inline in onTick, matching the TS Lodestar implementation.
@GrapeBaBa
GrapeBaBa marked this pull request as ready for review March 31, 2026 10:10
@GrapeBaBa
GrapeBaBa requested a review from a team as a code owner March 31, 2026 10:10
Copilot AI review requested due to automatic review settings March 31, 2026 10:10
@GrapeBaBa GrapeBaBa changed the title (WIP)feat(forkchoice): implement the forkchoice module feat(forkchoice): implement the forkchoice module Mar 31, 2026

Copilot AI 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.

Pull request overview

This PR introduces a new fork_choice Zig module (plus benches + CI coverage) and extends the codebase to recognize the new gloas fork (ePBS) across config, types, and state-transition helpers.

Changes:

  • Add a full src/fork_choice implementation (store/votes/proto-array integration, attestation + block handling) plus benchmarks and CI test target.
  • Add gloas fork support across consensus_types, fork_types, spec test runner utilities, and config/fork sequencing.
  • Update state transition utilities and block processing to account for ePBS behavior (no blinded blocks, payload decoupling, execution request relocation).

Reviewed changes

Copilot reviewed 44 out of 46 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
zbuild.zon Register fork_choice module + benches
test/spec/test_case.zig Add gloas SSZ test-case loading/deinit
test/spec/runner/sanity.zig Support gloas blocks in runner
src/state_transition/utils/execution.zig ePBS execution-enabled semantics for gloas+
src/state_transition/utils/epoch.zig Add computeSlotsSinceEpochStart helper
src/state_transition/test_utils/generate_state.zig Add config generation for gloas
src/state_transition/state_transition.zig Disallow blinded blocks for gloas+
src/state_transition/root.zig Export new epoch/balance Rc helpers
src/state_transition/block/slash_validator.zig Extend Electra slashing constants to gloas
src/state_transition/block/process_operations.zig Skip execution_requests for gloas+
src/state_transition/block/process_block.zig Skip exec payload processing for gloas+
src/preset/preset.zig Add ePBS-related preset constants
src/fork_types/root.zig Export new Any* wrapper types
src/fork_types/fork_types.zig Map ForkSeq.gloas to consensus types
src/fork_types/beacon_state.zig Enable fulu -> gloas state upgrade
src/fork_types/beacon_block.zig Enforce no blinded / no payload fields in gloas+
src/fork_types/any_indexed_attestation.zig New AnyIndexedAttestation wrapper
src/fork_types/any_execution_payload.zig Treat gloas like deneb-header variant
src/fork_types/any_beacon_state.zig Add gloas state + payload availability accessor
src/fork_types/any_beacon_block.zig Add gloas full block variants
src/fork_types/any_attester_slashing.zig Add AnyAttesterSlashing wrapper helpers
src/fork_choice/vote_tracker.zig New SoA votes storage + tests
src/fork_choice/store.zig New fork-choice store + Rc balance handling
src/fork_choice/root.zig Export fork-choice public API surface
src/fork_choice/fork_choice.zig Core fork-choice implementation + tests
src/fork_choice/compute_deltas.zig New delta computation + tests
src/consensus_types/root.zig Export gloas consensus types
src/consensus_types/gloas.zig New gloas SSZ types (ePBS)
src/config/networks/sepolia.zig Add gloas fork fields (disabled epoch)
src/config/networks/minimal.zig Add gloas fork fields + timing params
src/config/networks/mainnet.zig Add gloas fork fields + timing params
src/config/networks/hoodi.zig Add gloas fork fields (disabled epoch)
src/config/networks/gnosis.zig Add gloas fork fields + timing params
src/config/networks/chiado.zig Add gloas fork fields (disabled epoch)
src/config/fork_seq.zig Add ForkSeq.gloas
src/config/ChainConfig.zig Add Gloas + slot timing config fields
src/config/BeaconConfig.zig Add Gloas fork info + timing helpers
build.zig Add fork_choice module, tests, and benches
bindings/napi/BeaconStateView.zig Disallow blinded blocks for gloas+
bench/state_transition/process_block.zig Skip exec/withdrawals benches for gloas+
bench/fork_choice/util.zig Shared fork-choice bench initialization
bench/fork_choice/update_head.zig New fork-choice update-head benchmark
bench/fork_choice/on_attestation.zig New fork-choice onAttestation benchmark
bench/fork_choice/compute_deltas.zig New computeDeltas benchmark harness
.github/workflows/CI.yml Run fork-choice tests in CI

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1405 to +1410
// Accept vote if it's the first vote (INIT_VOTE_SLOT) or epoch advances.
if (existing_next_slot == INIT_VOTE_SLOT or computeEpochAtSlot(next_slot) > computeEpochAtSlot(existing_next_slot)) {
fields.next_indices[validator_index] = @intCast(next_index);
fields.next_slots[validator_index] = next_slot;
}
// else it's an old vote, don't count it.

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

addLatestMessage rejects/accepts votes based on computeEpochAtSlot(next_slot), but this function now stores next_slot (Gloas LatestMessage {slot, root}). Comparing epochs will incorrectly reject newer votes within the same epoch (common case), preventing votes from updating until the epoch boundary. Use a slot comparison (e.g. accept when next_slot > existing_next_slot, plus INIT_VOTE_SLOT special-case) to properly filter stale votes.

Suggested change
// Accept vote if it's the first vote (INIT_VOTE_SLOT) or epoch advances.
if (existing_next_slot == INIT_VOTE_SLOT or computeEpochAtSlot(next_slot) > computeEpochAtSlot(existing_next_slot)) {
fields.next_indices[validator_index] = @intCast(next_index);
fields.next_slots[validator_index] = next_slot;
}
// else it's an old vote, don't count it.
// Accept vote if it's the first vote (INIT_VOTE_SLOT) or the new vote has a higher slot.
if (existing_next_slot == INIT_VOTE_SLOT or next_slot > existing_next_slot) {
fields.next_indices[validator_index] = @intCast(next_index);
fields.next_slots[validator_index] = next_slot;
}
// else it's an old or equal-slot vote, don't count it.

Copilot uses AI. Check for mistakes.
Comment on lines +1456 to +1491
var slot_iter = self.queued_attestations.iterator();
while (slot_iter.next()) |entry| {
const att_slot = entry.key_ptr.*;
if (att_slot < current_slot) {
// Process all attestations for this slot.
var block_iter = entry.value_ptr.iterator();
while (block_iter.next()) |block_entry| {
const block_root = block_entry.key_ptr.*;
var vote_iter = block_entry.value_ptr.iterator();
while (vote_iter.next()) |vote_entry| {
try self.addLatestMessage(
allocator,
vote_entry.key_ptr.*,
att_slot,
block_root,
vote_entry.value_ptr.*,
);
}

if (att_slot == current_slot - 1) {
self.queued_attestations_previous_slot += @intCast(block_entry.value_ptr.count());
}
block_entry.value_ptr.deinit(allocator);
}
entry.value_ptr.deinit(allocator);
remove_count += 1;
} else {
break;
}
}

// Remove processed slots from front.
for (0..remove_count) |_| {
const key = self.queued_attestations.keys()[0];
_ = self.queued_attestations.orderedRemove(key);
}

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

processAttestationQueue assumes queued_attestations.iterator() yields entries in increasing att_slot order (it breaks on the first att_slot >= current_slot and then removes remove_count entries from the front). std.AutoArrayHashMapUnmanaged iteration order is insertion order, not key-sorted, so out-of-order slot insertions can cause eligible past-slot attestations to be skipped and/or the wrong slots to be removed. Iterate all entries and remove by key (or maintain a separate sorted structure / ensure sorted insertion explicitly) instead of relying on front-ordered removal + early break.

Copilot uses AI. Check for mistakes.
Comment thread src/fork_choice/fork_choice.zig Outdated
Comment on lines +2018 to +2019
const payload_available = state.state.executionPayloadAvailability(
checkpoint_slot % preset.SLOTS_PER_HISTORICAL_ROOT,

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

Type mismatch: executionPayloadAvailability expects index: usize (see AnyBeaconState.executionPayloadAvailability), but checkpoint_slot % preset.SLOTS_PER_HISTORICAL_ROOT is a Slot/u64. Zig requires an explicit cast here; as written this should not compile. Cast the modulo result to usize (with a safety assertion if desired) before calling executionPayloadAvailability.

Suggested change
const payload_available = state.state.executionPayloadAvailability(
checkpoint_slot % preset.SLOTS_PER_HISTORICAL_ROOT,
const payload_index = @intCast(usize, checkpoint_slot % preset.SLOTS_PER_HISTORICAL_ROOT);
const payload_available = state.state.executionPayloadAvailability(
payload_index,

Copilot uses AI. Check for mistakes.
Add bench_fork_choice_update_head, bench_fork_choice_compute_deltas,
and bench_fork_choice_on_attestation to the benchmark build step.
…ests

Remove sub-section headers from test areas in proto_array.zig and
fork_choice.zig since they tend to become stale as new tests are added.
Keep only code/test boundary markers.
wemeetagain
wemeetagain previously approved these changes Apr 1, 2026

@wemeetagain wemeetagain 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 really good. Tracks closely with the typescript version.

- Fix getElement → getFieldRoot for block_roots TreeView API
- Fix spurious try on getGloasExtraMetaTyped (returns plain value)
- Add 15 onAttestation unit tests: error paths (empty bitfield,
  future/past epoch, bad target, unknown target/head, future block,
  invalid target), valid vote application, queuing, zero-hash ignore,
  vote shifting, epoch advancement, proposer boost, and equivocating
  validator exclusion
…bugs

- Use ForkTypes(fork).BeaconBlock.hashTreeRoot() instead of block wrapper's
  hashTreeRoot() which doesn't exist on BeaconBlock wrapper
- Add try and .* to getFieldRoot() which returns !*const [32]u8
- Fix defer ordering in computeUnrealizedCheckpoints: destroy must run
  after deinit (Zig defers execute LIFO, so destroy must be declared first)
wemeetagain added a commit that referenced this pull request Apr 2, 2026
Merge latest PR head a97a220 and adapt it to Zig 0.16 plus current chain/state-transition interfaces.
- Add .gloas => .fulu to getForkPre() for transition test fixtures
- Pass EquivocatingIndices by *const instead of by value in sortEquivocatingKeys
- Remove redundant ensureTotalCapacity before resize in Votes.ensureValidatorCount
…ript implementation

Rename function parameters and local variables in fork_choice.zig and
proto_array.zig to match the naming conventions used in the TypeScript
Lodestar codebase:

fork_choice.zig:
- onBlockInner: unrealized_justified/finalized → unrealized_justified/finalized_checkpoint
- onAttestation/processAttestationQueue: att_slot → slot
- validateAttestationData: current_epoch → epoch_now
- updateCheckpoints: justified/finalized → justified/finalized_checkpoint
- updateUnrealizedCheckpoints: same checkpoint suffix alignment
- updateHead: head_node → head, score → proposer_boost_score
- getDependentRoot: epoch_diff → epoch_difference
- getCommonAncestorDepth: prev → prev_block
- validateLatestHash: response → exec_response
- prune: pruned → pruned_nodes
- isDescendant: ancestor_status → ancestor_payload_status

proto_array.zig:
- validateLatestHash: response → exec_response
- isDescendant: ancestor_status → ancestor_payload_status,
  descendant_status → descendant_payload_status
- Initialize anchor block PTC votes to all-true per spec get_forkchoice_store
- Reject same-slot full attestation votes and require FULL variant for index=1
- Add hasPayload to proto_array/fork_choice, refactor isPayloadTimely to use it
GrapeBaBa and others added 3 commits April 25, 2026 21:25
Port 5 upstream PRs in one alignment commit; revert 1 prior port that was
itself reverted upstream.

Ported:
- #9165 (2740f92909) — proposer boost gated to PENDING variant for Gloas;
  getParentNodeIndex swallows UnknownParentBlock at finalized boundary.
- #9209 (9fa9f08ef6) — shouldExtendPayload requires a FULL variant
  (hasPayload gate); add ForkChoice.shouldExtendPayload wrapper.
- #9259 (ca1fc40294) — drop payloadStatus from Checkpoint; remove
  CheckpointWithPayloadStatus + getCheckpointPayloadStatus; rename
  CheckpointWithPayload{And,AndTotal}Balance → CheckpointWith{,Total}Balance;
  getAllAncestorAndNonAncestorBlocks no longer pops the boundary; add
  default-status helpers (getAllAncestorAndNonAncestorBlocksDefaultStatus,
  forwardIterateDescendantsDefaultStatus); always-push start node in
  proto_array.getAllAncestorAndNonAncestorNodes.
- #9257 (6b7eebbf6d) — drop executionPayloadStateRoot from
  onExecutionPayload; FULL variant inherits state_root from PENDING.
- #9264 (b741495bdc) — revert anchor PTC all-true seed and anchor
  FULL-variant onExecutionPayload seeding (the latter was the #9222
  protoArray half, also reverted upstream by #9257).

Tests:
- Add 4 regression tests beyond TS coverage (#9165 ×2, #9209 ×2).
- Update getAllAncestorAndNonAncestorBlocks test for new semantics
  (boundary included, slice off in caller).
- Update 30 onExecutionPayload call sites to drop state_root arg.
- Delete 2 tests for the reverted #9188/#9222 anchor seeding behavior.

172/172 fork-choice tests pass.
Merge origin/main into gr/feature/forkchoice-z, picking up the zbuild
library migration (#319). Three conflicts surfaced + several Zig 0.14→0.16
API churns in the fork-choice port:

Conflicts resolved:
- build.zig: take main's 6-line wrapper around zbuild.configureBuild.
- zbuild.zon: deleted (folded into build.zig.zon by main).
- bench/state_transition/process_block.zig: keep our gloas-aware fork
  bound (`fork.gte(.bellatrix) and fork.lt(.gloas)` etc.) and main's
  new time API (`time.timestampNow(io)` / `time.since(io, ...)`).

build.zig.zon:
- Register `fork_choice` module (imports: consensus_types, config, preset,
  state_transition, fork_types, hex, constants).
- Register `fork_choice` per-module test step.
- Register 3 fork-choice bench executables (compute_deltas,
  on_attestation, update_head).

Zig 0.14 → 0.16 fixes inside fork_choice:
- `JustifiedBalances.init(allocator)` → `: JustifiedBalances = .empty;`
  + pass allocator to `appendSlice`/`deinit` (managed→unmanaged ArrayList).
- `RefCount.acquire()` / `.release()` → `.ref()` / `.unref()`.
- `std.BoundedArray(u32, 3)` → inline `BoundedIndices` struct
  (BoundedArray was removed in 0.16).
- `std.ArrayList(T).init(allocator)` → `: std.ArrayList(T) = .empty;` +
  pass allocator at use sites in `getHeads`,
  `getBlockSummariesByParentRoot`, `getBlockSummariesAtSlot`.

Bench main() entry points:
- `pub fn main() !void` → `pub fn main(init: std.process.Init) !void`.
- `std.io.getStdOut().writer()` → drop; `bench.run(stdout)` → `bench.run(io, std.Io.File.stdout())`.
- `attesting_indices = .{}` → `.empty` (unmanaged ArrayList field).
- Bench `run(self: T, ...)` → `run(self: *T, ...)` for new zbench.

172/172 fork-choice tests pass on 0.16.0; top-level `zig build` clean.
@wemeetagain
wemeetagain merged commit 7c62a9b into main May 7, 2026
30 checks passed
GrapeBaBa added a commit that referenced this pull request May 11, 2026
Bring in #246 (forkchoice + gloas types), #350 (withdrawals bindings),
#342/#348 (bindings refactors), and the other 7 PRs merged since this
branch diverged.

Updates gloas.zig FixedListType/FixedVectorType call sites for the
new opts argument added by this PR:
* balances / inactivity_scores / previous & current_epoch_participation
  now route through phase0.Balances / altair.{Epoch,Inactivity}Scores
  so they inherit chunked_leaf=true (matches fulu BeaconState shape).
* Other 13 FixedListType / 3 FixedVectorType sites take the default
  .{} opts.
}

// Regression: upstream lodestar #9209 added `hasPayload` gate — if FULL variant is
// missing shouldExtendPayload returns false regardless of the other conditions.

@nflaig nflaig Jul 12, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@GrapeBaBa I see this references my lodestar PR, can you please explain what this regression test covers, maybe we should add it to lodestar-ts side too? if we wanna add a more high level test can you explain in which scenario this was relevant seems like without this hasPayload check we'd pick a different head?

This comment was marked as spam.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

same, this kind of comment should not exist, and lodekeep-z explain it, this looks like a X do Y test you mentioned, need changed later

Comment on lines +3229 to +3234
// Tree (Gloas):
// 0x01.PENDING
// |
// 0x01.EMPTY
// |
// 0x01.FULL

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.

@GrapeBaBa so FULL is a child of EMPTY?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this ascii is wrong, and I should already cleaned up comments like Upstream: lodestar #9209, these were left out

@github-actions github-actions Bot mentioned this pull request Jul 30, 2026
@wemeetagain
wemeetagain deleted the gr/feature/forkchoice-z branch August 17, 2026 19:40
wemeetagain pushed a commit that referenced this pull request Aug 19, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.0.0](v0.1.2...v1.0.0)
(2026-08-19)


### Features

* add `state.getBuildersLength()` binding
([#472](#472))
([be2b5ab](be2b5ab))
* **beacon-node:** add block state cache and checkpoint datastore
([#452](#452))
([2145faa](2145faa))
* bindings to `getExpectedWithdrawals` and native tweaks
([#350](#350))
([f47bc66](f47bc66))
* **bindings:** add pubkey cache syncPubkeys
([#537](#537))
([542779f](542779f))
* **bindings:** aggregate cached public keys by validator index
([#397](#397))
([2f90603](2f90603))
* **bindings:** align `BeaconStateView` with `IBeaconStateView`
([#347](#347))
([b8ec273](b8ec273))
* **bindings:** configurable pubkey cache growth step
([#481](#481))
([133ef24](133ef24))
* **bindings:** expose more APIs for STF
([#444](#444))
([7fe2609](7fe2609))
* **bls:** add small MSM for npoints &lt; 32
([#393](#393))
([b430638](b430638))
* **blst:** use external buffers for blst operations
([#358](#358))
([78e4678](78e4678))
* **ci:** conditionally publish bindings with tag
([#355](#355))
([ea77919](ea77919))
* **clock:** add clock module for slot/epoch timing
([#354](#354))
([385b077](385b077))
* **fork_choice:** add Prometheus metrics module
([#309](#309))
([cbc9d8d](cbc9d8d))
* **forkchoice:** implement the forkchoice module
([#246](#246))
([7c62a9b](7c62a9b))
* getSyncCommitteesWitness
([#367](#367))
([ef77649](ef77649))
* implement `loadState` API and binding
([#165](#165))
([f903519](f903519)),
closes [#159](#159)
* **metrics:** metrics bindings
([#455](#455))
([dd41999](dd41999))
* migrate blst,pubkeys to use zapi js dsl
([#331](#331))
([fcd26ca](fcd26ca))
* **pubkeys:** add getPubkeyBytes binding
([#555](#555))
([4ca51cf](4ca51cf))
* publish ARM64 musl bindings
([#482](#482))
([ac764c9](ac764c9))
* **shuffle:** add swap-or-not shuffling module and binding
([#559](#559))
([c2db37c](c2db37c))
* split nextValue fn
([#464](#464))
([b47faeb](b47faeb))
* support getLatestWeakSubjectivityCheckpointEpoch
([#366](#366))
([dcf3883](dcf3883))
* update fulu deposit processing
([#442](#442))
([064335c](064335c))


### Bug Fixes

* avoid set ([#484](#484))
([2e25d97](2e25d97))
* better generation of rand scalar
([#388](#388))
([74dce77](74dce77))
* **bindings:** accept `dontTransferCache` in processSlots for backward
compatibility
([#460](#460))
([65df5af](65df5af))
* **bindings:** check signature infinity by default
([#509](#509))
([2f5f281](2f5f281))
* **bindings:** clean up failed async BLS work
([#527](#527))
([1111b00](1111b00))
* **bindings:** free metrics writer on scrape failure
([#529](#529))
([4c8d94a](4c8d94a))
* **bindings:** harden random aggregate scalars
([#528](#528))
([8e89a63](8e89a63))
* **bindings:** log level for missing fields
([#435](#435))
([08faf41](08faf41))
* **bindings:** misordering of print for cpu count
([#381](#381))
([752a972](752a972))
* **bindings:** populate epoch participation for test fixtures
([#436](#436))
([8dbdd2e](8dbdd2e))
* **bindings:** refcount Pool to fix teardown panic
([#352](#352))
([23b2f68](23b2f68))
* **bindings:** roll back partial N-API initialization
([#491](#491))
([31c5ebb](31c5ebb))
* **bindings:** size BLS thread pool by cgroup-aware CPU count
([#386](#386))
([3ae9522](3ae9522))
* **bindings:** validate class types before unwrap
([#514](#514))
([2fd2ad5](2fd2ad5))
* **bindings:** validate secret key hex length
([#517](#517))
([136e415](136e415))
* **bls:** align PublicKey.uncompress validation with
Signature.uncompress
([#508](#508))
([5a8dbe9](5a8dbe9))
* **bls:** bound randomized aggregation inputs
([#548](#548))
([779d0bf](779d0bf)),
closes [#542](#542)
* **bls:** clean up partial thread pool initialization
([#490](#490))
([d55e598](d55e598))
* **bls:** convert pippenger scratch bytes to element counts
([#513](#513))
([a12ca92](a12ca92))
* **bls:** enforce 32-byte signing roots
([#545](#545))
([72fd308](72fd308))
* **bls:** make batch cardinality structural
([#547](#547))
([a06d8b2](a06d8b2))
* **bls:** preserve aggregate outputs on failure
([#521](#521))
([e0b6dd1](e0b6dd1))
* **bls:** reject empty keygen salts
([#524](#524))
([d2a9c86](d2a9c86))
* **bls:** reject unknown BLST error codes
([#525](#525))
([9e4a6ad](9e4a6ad))
* **bls:** size pairing buffers for 32-bit targets
([#531](#531))
([dc64a27](dc64a27))
* **blst:** default signature infinity check to true if not provided
([#387](#387))
([021cdcb](021cdcb))
* **build:** remove `zig-out` from `files`
([#360](#360))
([c52af09](c52af09))
* **ci:** fix caching spec test version
([#439](#439))
([96885a1](96885a1))
* dangling state pointer in loadOtherState
([#450](#450))
([81cbd5f](81cbd5f))
* **epoch_cache:** compute missing `next_proposers`
([#447](#447))
([0088a29](0088a29))
* **epoch_cache:** populate decision roots in afterProcessEpoch
([#453](#453))
([4b70a5e](4b70a5e))
* export asyncAggregateWithRandomness through napi binding
([#371](#371))
([1d04c2b](1d04c2b))
* harden memory safety across PMT, SSZ tree views, and state transition
([#377](#377))
([d6f5897](d6f5897))
* improve atomic ordering in ThreadPool and NAPI init
([#310](#310))
([4b0a1cc](4b0a1cc))
* interface compatbility with NativeBeaconStateView
([#445](#445))
([89e13d1](89e13d1))
* missing deinits in loadOtherState
([#459](#459))
([094d278](094d278))
* missing state commits
([#454](#454))
([a432b55](a432b55))
* no-op when syncPubkeys run on a pk cache with shrinking validator set
([#432](#432))
([ed05a99](ed05a99))
* param order in BeaconBlockBody
([#348](#348))
([d8b9c06](d8b9c06))
* pendingConsolidations bindings
([#449](#449))
([b9c497e](b9c497e))
* **pmt,ssz:** harden chunked-leaf and zero-copy tree-view memory safety
([#400](#400))
([de50c53](de50c53))
* populate cache balances during rewards/penalties processing
([#474](#474))
([5bf23dc](5bf23dc))
* re-expose sizes
([#369](#369))
([64b81f3](64b81f3))
* remove `slashValidator` gating on active status
([#448](#448))
([d319a0d](d319a0d))
* **ssz:** drop redundant default-init pass in fixed-list decode
([#468](#468))
([0c757be](0c757be))
* **ssz:** publish child cache entries after lookup
([#565](#565))
([21e78c9](21e78c9))
* state transition binding exports
([#456](#456))
([895982c](895982c))
* **state-transition:** group-check signature sets
([#515](#515))
([42774e9](42774e9)),
closes [#502](#502)
* **state-transition:** isolate epoch step cache mutations
([#535](#535))
([a83741a](a83741a))
* **state-transition:** repair Pool.init call broken by
[#346](https://github.com/ChainSafe/lodestar-z/issues/346)×[#367](https://github.com/ChainSafe/lodestar-z/issues/367)
merge skew ([#394](#394))
([b42944f](b42944f))
* various fixes around config
([#433](#433))
([c4f082c](c4f082c))


### Performance Improvements

* **bindings:** drop TS BLS comparison benches and report benchmarks on
PRs ([#552](#552))
([c909c6f](c909c6f))
* **bls:** add cache-aware signature verifier
([#562](#562))
([063857e](063857e))
* **bls:** bypass worker queue for small batches
([#553](#553))
([3f8a6df](3f8a6df))
* **epoch:** replace AutoHashMap with array lookup in reward/penalty
caches ([#286](#286))
([e4e181b](e4e181b)),
closes [#243](#243)
* **pmt:** chunked-leaf packing for basic lists and container_struct
([#346](#346))
([ba156c4](ba156c4))


### Code Refactoring

* allocate `AsyncAggRandData` in one obj
([#384](#384))
([459750f](459750f))
* **bindings/pubkeys:** simplify allocation strategy for aggregate
([#518](#518))
([b82750f](b82750f))
* **bindings:** rename blst Lifecycle to State
([#516](#516))
([0a9c179](0a9c179))
* **bindings:** use zapi js.io() instead of local io module
([#469](#469))
([2b34cc0](2b34cc0))
* **bindings:** wake only required number of workers
([#383](#383))
([1db57f1](1db57f1))
* **bls:** allocations around VMAS
([#395](#395))
([dfda58c](dfda58c))
* **bls:** clean up bls
([#398](#398))
([e0f3b9b](e0f3b9b))
* **bls:** remove need for tracking results for
verifyMultipleAggregateSignatures
([#389](#389))
([6fe5c3f](6fe5c3f))
* **bls:** remove single-threaded fallback
([#390](#390))
([e057713](e057713))
* **clock:** single public Clock; internalize SlotClock
([#463](#463))
([fbab1fa](fbab1fa))
* make XXXDecisionRoot fns return `js.String`
([#342](#342))
([aef4420](aef4420))
* move shuffle into swap_or_not_shuffle module
([#558](#558))
([e56efb2](e56efb2))
* **pubkeys:** centralize the process-wide cache
([#522](#522))
([dc9669d](dc9669d))


### Miscellaneous Chores

* avoid slow tests in AGENTS.md
([#546](#546))
([c60f2a9](c60f2a9))
* bump zapi to include musl build
([#485](#485))
([0b488cc](0b488cc))
* **ci:** pin github actions with sha hashes
([#507](#507))
([167b8f5](167b8f5))
* deprecate unused blst APIs
([#575](#575))
([7b547fa](7b547fa))
* **deps:** bump zapi v2.1.0 -&gt; v2.2.0
([#376](#376))
([0c240d8](0c240d8))
* **deps:** bump zbuild
([#403](#403))
([e2545de](e2545de))
* **deps:** compile blst with ReleaseFast
([#391](#391))
([753a896](753a896))
* **deps:** update zapi to 3.1.0
([#483](#483))
([f3e5827](f3e5827))
* **deps:** use zapi v2.1.0
([#372](#372))
([88f403a](88f403a))
* disable gemini auto code review
([#382](#382))
([63e42a4](63e42a4)),
closes [#380](#380)
* **docs:** add comments section in AGENTS.md
([#566](#566))
([0c09750](0c09750))
* move state clones out of benchmark run functions
([#324](#324))
([e4035de](e4035de))
* prepare 1.0.0 release
([#576](#576))
([20b657b](20b657b))
* release v0.1.2-rc.3
([#370](#370))
([e4fc551](e4fc551))
* **release:** 0.1.2-rc.2
([#365](#365))
([7046128](7046128))
* **release:** v0.1.2-rc.10
([#477](#477))
([9a4fad5](9a4fad5))
* **release:** v0.1.2-rc.4
([#373](#373))
([09468f1](09468f1))
* **release:** v0.1.2-rc.5
([#374](#374))
([f344efa](f344efa))
* **release:** v0.1.2-rc.6
([#375](#375))
([bdf5b67](bdf5b67))
* **release:** v0.1.2-rc.8
([#401](#401))
([06f91c2](06f91c2))
* **release:** v0.1.2-rc.9
([#404](#404))
([6024800](6024800))
* remove merge transition code
([#359](#359))
([09b175d](09b175d))
* remove stale epoch cache TODOs
([#534](#534))
([27a547a](27a547a))
* rename era shortHistoricalRoot to shortEraRoot
([#473](#473))
([c75a4d3](c75a4d3))
* **scripts:** build bindings with preset
([#434](#434))
([a1b5ef7](a1b5ef7))
* silence debug log when used in release builds
([#486](#486))
([c5377d7](c5377d7))
* support dev workflow
([#364](#364))
([fcb9a78](fcb9a78))
* update gloas types to align with the latest specs
([#431](#431))
([1f065b5](1f065b5))
* update spec test version to v1.7.0-alpha.11
([#451](#451))
([5875660](5875660))
* update spec-test-version: v1.6.0-beta.2 -&gt; v1.7.0-alpha.10
([#441](#441))
([f932b1c](f932b1c))
* update zapi to 4.0.0
([#571](#571))
([de8e3fd](de8e3fd))


### Documentation

* document security threat model
([#557](#557))
([e678b87](e678b87))
* more comprehensive AGENTS.md
([#520](#520))
([c74b386](c74b386))
* **pkix:** document load provenance requirement
([#556](#556))
([37e0aa2](37e0aa2))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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