Skip to content

Reset the cached coin database and re-sync from chain (control method + dign verb) #384

Description

@MichaelTaylor3d

Task

Give the node a way to drop the cached coin database and re-sync it from chain, exposed as a
control method and a dign verb. The DIG App button (dig-app#TBD) drives this; it must not reach into
the database itself.

User directive, 2026-08-27 (verbatim): "we will need to reset the database when this is fixed.
There should be a button in dig-app to reset the coin datbase and resync"

Parent epic: https://github.com/DIG-Network/dig_ecosystem/issues/3170
Related: #382 (the CAT attribution defect that prompted it)

Why this is worth building even though #382's fix backfills

reconstruct_all walks every coin in the DB and attributes any that is unspent, unattributed and
a candidate — so once #382 wires the attributor, existing asset_id = NULL rows are repaired on the
next update tick without a reset. A reset is not the remedy for #382.

The case that genuinely needs it is narrower and permanent:

let Some(parent) = lineage.parent_spend(&c.parent_coin_info, created as u32).await? else {
    continue;
};

A coin whose parent spend could not be fetched — source unreachable, a transient failure, a pruned
response — is skipped, silently, and never retried. Nothing re-queues it. That coin stays
unattributed for the life of the database, so its asset never resolves and its value never appears in
an asset-scoped balance. There is currently no way for a user to recover from that except deleting
the file by hand.

That is the honest justification: not "the DB is stale" but "a one-off fetch failure is permanent
and otherwise unrecoverable."

The hazard this MUST get right — the repo already documents it

Between emptying the table and finishing the re-sync, the database is empty. The routing gate
(WalletDb::is_syncedrouting::route) is what makes the local replica authoritative. So an
emptied-but-still-synced database answers balance 0, synced true on a funded wallet.

sync.rs already states this for the reorg-rollback path, in almost these words:

"The routing gate … is what makes an emptied DB authoritative, so a destructive push must clear it:
the wallet then reads from the fallback tier until a genuine catch-up re-establishes the flag.
Without this, one hostile frame makes a funded wallet answer balance 0, synced true."

The reset must clear is_synced in the same transaction that empties the coins, so a crash
between the two cannot leave an empty authoritative replica. Reads then fall back until a real
catch-up re-establishes the flag. This is the money-lie class (§2.6's narrow stop) and it is the whole
risk of the feature.

Other constraints

  • Never touch key material. Coins are chain-derived and safe to discard; a seed is not. Scope the
    reset to chain-cached tables and say explicitly which ones.
  • Refuse while a spend is in flight. coin_reservations, client_coin_reservations and
    pending_transactions reference coins by id. Wiping the coins beneath a reserved, unconfirmed spend
    loses the record of what is committed and invites a double-spend attempt. Refuse with a clear
    machine-branchable error rather than resetting anyway.
  • Re-entrant. Pressing it twice, or while a resync is running, must not corrupt or start two
    catch-ups.
  • Report progress. A resync from genesis is slow. The caller needs to distinguish "running" from
    "stalled" — dign wallet sync-status already reports phase and replica height; make the reset
    observable through the same read rather than inventing a second status surface.

Deliverables

  • A control method (declare it in dig-node-control-interface, release-first per §4.1)
  • A dign wallet verb, --json supported (§6.2)
  • SPEC.md updated (§4.2); the #426 CLI/RPC parity test kept green

Acceptance

On a real funded wallet: reset, watch the balance become unknown (never a confident zero), watch the
resync complete, and see the same balance and coins as before. §2.6 — evidence is that sequence on a
real machine.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions