Skip to content

wallet_reset_coin_db reads the clock directly, bypassing ClockGovernor's jump discipline #541

Description

@MichaelTaylor3d

Task

wallet_reset_coin_db computes its own now_ms inline from SystemTime::now()
(crates/dig-node-service/src/control.rs:2601) and never routes through WalletBackend, so it
bypasses the ClockGovernor entirely for that one RPC.

#532 (PR #539) disciplines every reservation "now" read through
WalletBackend::reservation_now_ms() so a wall-clock jump cannot make a live hold be misjudged.
Six production call sites were migrated. This one was not, because it lives in a different crate and
reads the clock directly rather than asking the backend.

Consequence: the clock-jump protection #532 exists to provide is absent on this path. A wall
clock stepped forward while a reset is in flight is evaluated against an undisciplined now, which
is precisely the state ClockGovernor was built to prevent — so the guard is real everywhere except
here, and nothing says so.

Why this is not a defect in #539

Pre-existing, blamed to #454, and it predates both #528 and #539. It is in dig-node-service, while
#539's change is in dig-wallet. The #539 lane surfaced it rather than widening its own PR, which
was the right call — an in-scope fix would have crossed a crate boundary and grown the diff past
what its gate covered.

Done condition (finite and checkable)

  • wallet_reset_coin_db obtains its now_ms through the same disciplined path as the other six
    reservation call sites (WalletBackend::reservation_now_ms() or an equivalent that routes
    through ClockGovernor), or it is documented at the call site why an undisciplined read is
    correct for a reset specifically.
  • A test asserts the chosen behaviour at the decision point, built from real
    reserve_spend/prune_reservations-style calls rather than a hand-placed row — a fixture in a
    state production cannot reach would pass under the defect.
  • A grep confirms no other reservation-touching path reads SystemTime::now() directly. If the
    migration missed one site it may have missed others; the sweep is part of the fix, not a
    follow-up.

Constraints carried forward from #532/#528

Evidence

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:maintenancereal work that changes nothing a user can perceive

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions