Skip to content

governance: use ledgers instead of timestamps#569

Open
brozorec wants to merge 1 commit intomainfrom
gov-use-ledgers
Open

governance: use ledgers instead of timestamps#569
brozorec wants to merge 1 commit intomainfrom
gov-use-ledgers

Conversation

@brozorec
Copy link
Collaborator

@brozorec brozorec commented Feb 18, 2026

Fixes #567

PR Checklist

  • Tests
  • Documentation

Summary by CodeRabbit

  • Refactor

    • Replaced timestamp-based time references with ledger sequence numbers for timelock and governance operations. Public APIs now accept and return ledger sequence numbers (u32) instead of Unix timestamps (u64).
  • Documentation

    • Updated documentation to reflect ledger-based delays instead of timestamp-based timing.
  • Tests

    • Updated test infrastructure to use ledger sequence numbers instead of timestamps for time progression.

@brozorec brozorec added this to the Release v0.7.0 milestone Feb 18, 2026
@brozorec brozorec self-assigned this Feb 18, 2026
@brozorec brozorec added the Small 2-5 days label Feb 18, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Walkthrough

This PR harmonizes the governance module's clock mechanism by converting from timestamp-based to ledger sequence-based timing. The timelock module's public API is renamed from get_timestamp to get_operation_ledger with return type changed from u64 to u32, and all related storage keys and constants are updated to use ledger references. The Votes module similarly transitions its Checkpoint struct and checkpoint-query functions to use ledger sequence numbers.

Changes

Cohort / File(s) Summary
Timelock Storage & Core
packages/governance/src/timelock/storage.rs, packages/governance/src/timelock/mod.rs
Storage key enum variant Timestamp renamed to OperationLedger; constants UNSET_TIMESTAMP and DONE_TIMESTAMP (u64) replaced with UNSET_LEDGER and DONE_LEDGER (u32); public function get_timestamp renamed to get_operation_ledger returning u32; internal functions updated to use ledger sequence comparisons instead of timestamp comparisons.
Timelock Example & Tests
examples/timelock-controller/src/contract.rs, examples/timelock-controller/src/test.rs
Example contract updated to import and call get_operation_ledger instead of get_timestamp; test setup changed from set_timestamp to set_sequence_number for ledger advancement.
Votes Storage & Trait
packages/governance/src/votes/storage.rs, packages/governance/src/votes/mod.rs
Checkpoint struct field renamed from timestamp: u64 to ledger: u32; trait methods get_votes_at_checkpoint and get_total_supply_at_checkpoint parameter changed from timepoint: u64 to ledger: u32; internal lookup logic updated to use ledger sequence comparisons.
Votes Tests
packages/governance/src/votes/test.rs
Test setup changed from set_timestamp to set_sequence_number; test assertions updated to validate against get_operation_ledger results.
Documentation
packages/governance/README.md
Votes section updated to reference ledger sequence numbers as timepoint reference instead of timestamps for checkpoint queries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Governance: Votes #552: Introduces the Checkpoint struct and get_*_at_checkpoint functions that this PR modifies to use ledger sequence numbers instead of timestamps.

Suggested reviewers

  • ozgunozerk

Poem

🐰 The ledgers now count our days so true,
No more timestamp confusion in this crew!
From seconds past to sequences ahead,
The governance module's clock is gently led.
Harmonized at last, precise and bright! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely and accurately describes the main change: replacing timestamps with ledgers in the governance module.
Description check ✅ Passed The PR description follows the template, includes a linked issue (#567), and marks both Tests and Documentation as complete.
Linked Issues check ✅ Passed The changes fully address issue #567 by replacing timestamp-based clocking with ledger-based clocking across timelock and votes modules for consistency.
Out of Scope Changes check ✅ Passed All changes directly support the objective of harmonizing clock counting by switching from timestamps to ledgers across governance components; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gov-use-ledgers

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

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 migrates the governance module from using timestamps (u64) to ledger sequence numbers (u32) as the clock mode, harmonizing the time counting mechanism across the votes and timelock modules. This addresses issue #567 by making the clock mode more natural and consistent with other parts of the library.

Changes:

  • Changed checkpoint tracking from timestamps to ledger sequence numbers in the votes module
  • Updated timelock operations to use ledger sequence numbers instead of timestamps
  • Renamed functions and storage keys to reflect the new clock mode (e.g., get_timestampget_operation_ledger)

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/governance/src/votes/test.rs Updated all test calls from set_timestamp to set_sequence_number and updated comments
packages/governance/src/votes/storage.rs Changed Checkpoint struct from timestamp: u64 to ledger: u32, updated all related functions and documentation
packages/governance/src/votes/mod.rs Updated API documentation and function signatures to use ledger terminology instead of timestamp
packages/governance/src/timelock/test.rs Updated test calls and function references to use ledger sequence numbers
packages/governance/src/timelock/storage.rs Renamed Timestamp storage key to OperationLedger, updated get_timestamp to get_operation_ledger, changed all u64 types to u32
packages/governance/src/timelock/mod.rs Updated exports and renamed constants from UNSET_TIMESTAMP/DONE_TIMESTAMP to UNSET_LEDGER/DONE_LEDGER
packages/governance/README.md Updated documentation to reflect ledger sequence number usage
examples/timelock-controller/src/test.rs Updated test code to use sequence_number instead of timestamp
examples/timelock-controller/src/contract.rs Updated function names and documentation to use ledger terminology

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

let current_timestamp = e.ledger().timestamp();
let ready_timestamp = current_timestamp + (delay as u64);
let current_ledger = e.ledger().sequence();
let ready_ledger = current_ledger + delay;
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Potential arithmetic overflow: adding current_ledger + delay without overflow checking. If current_ledger and delay sum to a value greater than u32::MAX, this will panic or wrap. Consider using checked_add and returning an appropriate error.

Suggested change
let ready_ledger = current_ledger + delay;
let ready_ledger = current_ledger.saturating_add(delay);

Copilot uses AI. Check for mistakes.
@@ -384,7 +382,7 @@ fn lookup_checkpoint_at(
while low < high {
let mid = (low + high).div_ceil(2);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Potential arithmetic overflow: computing (low + high).div_ceil(2) without overflow checking. If both low and high are large u32 values (e.g., near u32::MAX), their sum could overflow. Consider using low + (high - low) / 2 instead, which avoids overflow.

Suggested change
let mid = (low + high).div_ceil(2);
let mid = low + (high - low + 1) / 2;

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Feb 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.23%. Comparing base (606ec84) to head (b7ca863).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #569      +/-   ##
==========================================
- Coverage   96.24%   96.23%   -0.01%     
==========================================
  Files          57       57              
  Lines        5507     5502       -5     
==========================================
- Hits         5300     5295       -5     
  Misses        207      207              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/governance/src/timelock/mod.rs`:
- Around line 95-100: UNSET_LEDGER (currently 0) and DONE_LEDGER (currently 1)
may collide with valid ledger sequence numbers; change these sentinel values to
numbers outside the valid ledger range (e.g., u32::MAX or a clearly reserved
constant) or enforce a minimum delay >= 2 so real ledgers cannot equal the
sentinels; update all references/tests/docs that assert 0/1 and adjust any logic
in functions that compare against UNSET_LEDGER or DONE_LEDGER (e.g.,
scheduling/checking code) to use the new sentinel constants and ensure behavior
remains correct when min_delay is validated.

Comment on lines 95 to +100
/// Sentinel value for an operation that has not been scheduled.
pub const UNSET_TIMESTAMP: u64 = 0;
pub const UNSET_LEDGER: u32 = 0;

/// Sentinel value used to mark an operation as done.
/// Using 1 instead of 0 to distinguish from unset operations.
pub const DONE_TIMESTAMP: u64 = 1;
pub const DONE_LEDGER: u32 = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid sentinel collisions with real ledger sequence numbers.

UNSET_LEDGER = 0 and DONE_LEDGER = 1 are valid ledger sequences. If min_delay can be 0 and the current ledger is 1, a newly scheduled operation could be classified as Done and become non-executable. Consider sentinel values outside the valid range or enforce a minimum delay ≥ 1. If you change the sentinel values, update docs/tests that assert 0/1.

🔧 Possible sentinel adjustment
-/// Sentinel value for an operation that has not been scheduled.
-pub const UNSET_LEDGER: u32 = 0;
-
-/// Sentinel value used to mark an operation as done.
-/// Using 1 instead of 0 to distinguish from unset operations.
-pub const DONE_LEDGER: u32 = 1;
+/// Sentinel value for an operation that has not been scheduled.
+/// Use high values to avoid collisions with real ledger sequences.
+pub const UNSET_LEDGER: u32 = u32::MAX;
+
+/// Sentinel value used to mark an operation as done.
+pub const DONE_LEDGER: u32 = u32::MAX - 1;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// Sentinel value for an operation that has not been scheduled.
pub const UNSET_TIMESTAMP: u64 = 0;
pub const UNSET_LEDGER: u32 = 0;
/// Sentinel value used to mark an operation as done.
/// Using 1 instead of 0 to distinguish from unset operations.
pub const DONE_TIMESTAMP: u64 = 1;
pub const DONE_LEDGER: u32 = 1;
/// Sentinel value for an operation that has not been scheduled.
/// Use high values to avoid collisions with real ledger sequences.
pub const UNSET_LEDGER: u32 = u32::MAX;
/// Sentinel value used to mark an operation as done.
pub const DONE_LEDGER: u32 = u32::MAX - 1;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/governance/src/timelock/mod.rs` around lines 95 - 100, UNSET_LEDGER
(currently 0) and DONE_LEDGER (currently 1) may collide with valid ledger
sequence numbers; change these sentinel values to numbers outside the valid
ledger range (e.g., u32::MAX or a clearly reserved constant) or enforce a
minimum delay >= 2 so real ledgers cannot equal the sentinels; update all
references/tests/docs that assert 0/1 and adjust any logic in functions that
compare against UNSET_LEDGER or DONE_LEDGER (e.g., scheduling/checking code) to
use the new sentinel constants and ensure behavior remains correct when
min_delay is validated.

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

Labels

Small 2-5 days

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🏗️ [Core Feature]: Harmonize clock counting in the gov module

1 participant

Comments