Skip to content

feat(STF): implement Gloas Fork #303

Draft
guha-rahul wants to merge 32 commits intoChainSafe:mainfrom
guha-rahul:G-fork
Draft

feat(STF): implement Gloas Fork #303
guha-rahul wants to merge 32 commits intoChainSafe:mainfrom
guha-rahul:G-fork

Conversation

@guha-rahul
Copy link
Copy Markdown
Contributor

@guha-rahul guha-rahul commented Apr 2, 2026

This pr implements

  • The Gloas fork including EIP-7732
  • upgrades to use test vectors v1.7.0-alpha.4

@guha-rahul guha-rahul requested a review from a team as a code owner April 2, 2026 12:12
@guha-rahul guha-rahul marked this pull request as draft April 2, 2026 12:12
@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 implements the 'Gloas' fork, a significant update to the consensus layer. It introduces new data structures for builder management, payload attestations, and execution payload bids, while refactoring existing state transition logic to support these changes. The update also includes necessary adjustments to the test suite and configuration to align with the latest consensus specifications.

Highlights

  • Implementation of Gloas Fork: Introduced the 'gloas' fork, including new consensus types, configuration parameters, and state transition logic.
  • Builder and Payload Attestation Support: Added support for builder registration, execution payload bids, and payload attestations as part of the Gloas fork.
  • Updated Spec Test Version: Updated the consensus-specs dependency to v1.7.0-alpha.4.
  • State Transition Refactoring: Refactored block processing and withdrawal logic to accommodate the new Gloas fork requirements, including builder payment handling.

🧠 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.

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.

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.

@guha-rahul guha-rahul changed the title featImplement Gloas Fork feat(STF): Implement Gloas Fork Apr 2, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the 'gloas' fork, implementing EIP-7732 changes including builder registry management, payload timeliness committees (PTC), and updated withdrawal processing. The changes involve adding new consensus types, updating state transition logic for blocks and epochs, and integrating new signature verification sets. I have reviewed the code and provided feedback on performance optimizations, style guide compliance, and safety assertions. Specifically, I have flagged issues regarding linear scans in the builder registry, unbounded loops in PTC computation, inefficient memory allocation in attestation processing, and naming/typing inconsistencies.

try builders.setValue(builder_index, &builder);
}

pub fn findBuilderIndexByPubkey(allocator: Allocator, state: *BeaconState(.gloas), pubkey: *const BLSPubkey) !?usize {
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.

high

This function performs an $O(N)$ linear scan over the builder registry. As the registry grows (up to BUILDER_REGISTRY_LIMIT), this will become a significant performance bottleneck. Consider implementing a more efficient lookup mechanism, such as a cache or a hash-based index, to maintain mechanical sympathy and performance.

var random_bytes: [32]u8 = undefined;
var last_block: u64 = std.math.maxInt(u64);

while (result_len < preset.PTC_SIZE) {
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.

high

This loop lacks a fixed upper bound, which poses a risk of excessive execution time or infinite loops if the input data (e.g., effective balances) does not satisfy the sampling criteria. The style guide requires all loops to have a fixed upper bound to prevent tail latency spikes and ensure bounded execution.

References
  1. All loops must have a fixed upper bound to prevent infinite loops or tail latency spikes. (link)

// TODO: metrics — newSeenAttesters, newSeenAttestersEffectiveBalance, attestationsPerBlock
var proposer_reward: u64 = 0;

var builder_weight_map = std.AutoHashMap(u64, u64).init(allocator);
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.

medium

Using AutoHashMap with heap allocation inside a block processing function is inefficient. Since the number of indices is small and fixed (2 * preset.SLOTS_PER_EPOCH), a stack-allocated array or a pre-allocated buffer would be more performant and align better with the 'Safety' design goals regarding memory allocation.

References
  1. Most memory should be statically allocated at startup where possible and optimal to improve performance and safety. (link)

else
data.slot % preset.SLOTS_PER_EPOCH;

var builder_pending_payments = try state.inner.get("builder_pending_payments");
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.

medium

Fetching the builder_pending_payments field from the state inside the attestations loop is inefficient. This should be moved outside the loop to avoid redundant state access operations and potentially shared with the batch write logic after the loop.

signature: BLSSignature,
slot: u64,
) !void {
const builderIndex = try findBuilderIndexByPubkey(allocator, state, pubkey);
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.

medium

Variable name builderIndex violates the repository style guide, which requires snake_case for variable names.

    const builder_index = try findBuilderIndexByPubkey(allocator, state, pubkey);
References
  1. Use snake_case for file names and variable names. (link)

const len = try builders.length();
const current_epoch = computeEpochAtSlot(try state.slot());

var builderIndex: ?usize = null;
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.

medium

Use of architecture-specific usize for a variable that represents a registry index is discouraged. The style guide recommends using explicitly-sized types like u32 or u64 for everything.

    var builder_index: ?u64 = null;
References
  1. Use explicitly-sized types like u32 for everything, avoid architecture-specific usize. (link)

const verify = @import("../utils/bls.zig").verify;
const getExecutionPayloadBidSigningRoot = @import("../signature_sets/execution_payload_bid.zig").getExecutionPayloadBidSigningRoot;

pub fn processExecutionPayloadBid(
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.

medium

This function lacks assertions for its input arguments. The repository style guide mandates that all function arguments, pre/postconditions, and invariants must be asserted to detect programmer errors early and increase the probability of correctness.

References
  1. Assert all function arguments and return values, pre/postconditions and invariants. (link)

}
// TODO: Gloas - Optimization needed
const total_payments = @TypeOf(builderPendingPayments.*).length;
for (0..total_payments) |i| {
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.

medium

Performing getValue and setValue on a TreeView inside a loop is inefficient due to the overhead of Merkle tree operations. Consider reading the entire vector into a local buffer, modifying it, and writing it back in a single operation to improve performance.

Comment thread src/state_transition/block/process_withdrawals.zig
@guha-rahul guha-rahul changed the title feat(STF): Implement Gloas Fork feat(STF): implement Gloas Fork Apr 2, 2026
const pending_deposits_len = try pending_deposits.length();
var pending_it = pending_deposits.iteratorReadonly(0);

for (0..pending_deposits_len) |_| {
Copy link
Copy Markdown
Member

@nflaig nflaig Apr 7, 2026

Choose a reason for hiding this comment

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

@guha-rahul I think we need to more carefully think through the bottlenecks in gloas state transition which even in lodestar itself is not yet optimized since we haven't run it on any network with meaningful load, eg. the code here does 50k signature verifications for each deposit request on mainnet, this is pretty redundant and will not work, ChainSafe/lodestar#9180 has this optimized to only do it once per payload, but even that I think is insufficient, also we need to consider batching here

either way, also what I mentioned in standup, we need to look at the performance issues and come up with improvements / caching etc. I am pretty sure we can port the ts implementation improvements to zig as well

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.

2 participants