Skip to content

test(utils): add unit tests for epoch utilities and intSqrt#259

Closed
lodekeeper-z wants to merge 1 commit intoChainSafe:mainfrom
lodekeeper-z:test/epoch-utils-unit-tests
Closed

test(utils): add unit tests for epoch utilities and intSqrt#259
lodekeeper-z wants to merge 1 commit intoChainSafe:mainfrom
lodekeeper-z:test/epoch-utils-unit-tests

Conversation

@lodekeeper-z
Copy link
Copy Markdown
Contributor

Add 10 unit tests covering pure utility functions in epoch.zig and math.zig:

epoch.zig (9 tests):

  • computeEpochAtSlot — slot-to-epoch conversion
  • computeStartSlotAtEpoch — epoch start slot
  • computeEndSlotAtEpoch — epoch end slot
  • computeCheckpointEpochAtStateSlot — checkpoint boundary logic
  • computeActivationExitEpoch — activation/exit delay
  • computePreviousEpoch — genesis clamping
  • computeSyncPeriodAtEpoch — sync committee period
  • computeSyncPeriodAtSlot — slot-to-sync-period
  • isStartSlotOfEpoch — epoch boundary check

math.zig (1 test):

  • intSqrt — integer square root via f64, edge cases and large values

All tests verified locally with zig build test:state_transition.

🤖 Generated with AI assistance

Add 10 unit tests covering pure utility functions:
- computeEpochAtSlot
- computeStartSlotAtEpoch
- computeEndSlotAtEpoch
- computeCheckpointEpochAtStateSlot
- computeActivationExitEpoch
- computePreviousEpoch
- computeSyncPeriodAtEpoch
- computeSyncPeriodAtSlot
- isStartSlotOfEpoch
- intSqrt

🤖 Generated with AI assistance
@lodekeeper-z lodekeeper-z requested a review from a team as a code owner March 22, 2026 02:20
@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 significantly enhances the robustness and reliability of core utility functions by introducing a suite of unit tests. These tests ensure the correctness of epoch-related calculations and the integer square root function, which are fundamental to the state transition logic.

Highlights

  • Epoch Utility Tests: Introduced 9 new unit tests for src/state_transition/utils/epoch.zig, covering functions like computeEpochAtSlot, computeStartSlotAtEpoch, computeEndSlotAtEpoch, computeCheckpointEpochAtStateSlot, computeActivationExitEpoch, computePreviousEpoch, computeSyncPeriodAtEpoch, computeSyncPeriodAtSlot, and isStartSlotOfEpoch.
  • Integer Square Root Test: Added a comprehensive unit test for the intSqrt function in src/state_transition/utils/math.zig, validating its behavior with edge cases and large numerical inputs.

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

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 adds a good set of unit tests for utility functions in epoch.zig and math.zig. The tests for epoch utilities improve coverage for these pure functions. My review uncovered a critical issue with the intSqrt function's implementation, which can produce incorrect results for large numbers due to floating-point precision loss. I've recommended a more robust implementation and an additional test case to cover this. I also found minor inconsistencies in type casting within the epoch utility tests and have suggested improvements for better clarity and consistency, in line with the project's style guide.

Comment on lines +9 to +21
test "intSqrt" {
try std.testing.expectEqual(@as(u64, 0), intSqrt(0));
try std.testing.expectEqual(@as(u64, 1), intSqrt(1));
try std.testing.expectEqual(@as(u64, 1), intSqrt(2));
try std.testing.expectEqual(@as(u64, 1), intSqrt(3));
try std.testing.expectEqual(@as(u64, 2), intSqrt(4));
try std.testing.expectEqual(@as(u64, 3), intSqrt(9));
try std.testing.expectEqual(@as(u64, 10), intSqrt(100));
try std.testing.expectEqual(@as(u64, 31), intSqrt(999));
try std.testing.expectEqual(@as(u64, 1000), intSqrt(1_000_000));
// Large value.
try std.testing.expectEqual(@as(u64, 4_294_967_295), intSqrt(18_446_744_065_119_617_025));
}
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.

critical

The intSqrt implementation is incorrect for large u64 values due to precision loss when converting to f64. f64 only has 53 bits of mantissa precision, while u64 has 64 bits. For numbers larger than 2^53, the conversion to f64 is lossy, leading to incorrect square root calculations.

A failing test case that demonstrates this is intSqrt(std.math.max_int(u64)). The expected result is 4294967295 (2^32 - 1), but the current implementation returns 4294967296 (2^32).

While the existing tests are good, they don't cover this critical edge case. Please add a test for u64.max to ensure the function's correctness. This will require fixing intSqrt.

Suggested test case to add:

// u64.max
try std.testing.expectEqual(@as(u64, 4_294_967_295), intSqrt(std.math.max_int(u64)));

A correct implementation should use integer arithmetic. Here is a suggestion using binary search:

pub inline fn intSqrt(n: u64) u64 {
    if (n < 2) {
        return n;
    }
    var low: u64 = 1;
    // The integer square root of a u64 is at most 2^32.
    var high: u64 = 1 << 32;
    var ans: u64 = 1;
    while (low <= high) {
        const mid = low + (high - low) / 2;
        // Using division to avoid overflow with mid*mid
        if (mid > n / mid) {
            high = mid - 1;
        } else {
            ans = mid;
            low = mid + 1;
        }
    }
    return ans;
}

Comment on lines +133 to +137
test "computeStartSlotAtEpoch" {
try std.testing.expectEqual(@as(Slot, 0), computeStartSlotAtEpoch(0));
try std.testing.expectEqual(preset.SLOTS_PER_EPOCH, computeStartSlotAtEpoch(1));
try std.testing.expectEqual(5 * preset.SLOTS_PER_EPOCH, computeStartSlotAtEpoch(5));
}
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

For consistency with other tests and to be more explicit, please cast the expected values to Slot using @as(Slot, ...). The first assertion in this test does this, but the following two do not. This aligns with the style guide's preference for explicitness.

test "computeStartSlotAtEpoch" {
    try std.testing.expectEqual(@as(Slot, 0), computeStartSlotAtEpoch(0));
    try std.testing.expectEqual(@as(Slot, preset.SLOTS_PER_EPOCH), computeStartSlotAtEpoch(1));
    try std.testing.expectEqual(@as(Slot, 5 * preset.SLOTS_PER_EPOCH), computeStartSlotAtEpoch(5));
}
References
  1. The style guide recommends being explicit to minimize dependence on the compiler (Line 200) and using explicitly-sized types (Line 44). (link)

Comment on lines +139 to +142
test "computeEndSlotAtEpoch" {
try std.testing.expectEqual(preset.SLOTS_PER_EPOCH - 1, computeEndSlotAtEpoch(0));
try std.testing.expectEqual(2 * preset.SLOTS_PER_EPOCH - 1, computeEndSlotAtEpoch(1));
}
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

For consistency and explicitness, please cast the expected values to Slot using @as(Slot, ...). Other tests in this file follow this pattern, and it aligns with the style guide's preference for explicitness.

test "computeEndSlotAtEpoch" {
    try std.testing.expectEqual(@as(Slot, preset.SLOTS_PER_EPOCH - 1), computeEndSlotAtEpoch(0));
    try std.testing.expectEqual(@as(Slot, 2 * preset.SLOTS_PER_EPOCH - 1), computeEndSlotAtEpoch(1));
}
References
  1. The style guide recommends being explicit to minimize dependence on the compiler (Line 200) and using explicitly-sized types (Line 44). (link)

@lodekeeper-z
Copy link
Copy Markdown
Contributor Author

Closing — #263 (merged today) replaced intSqrt with std.math.sqrt, so these tests are now obsolete. The epoch utility tests remain valid and are covered by #262.

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.

1 participant