Skip to content

Persist mirror-bond coin ids — bond identity is re-derived from chain each read, so a restart or a lagging chain source renders locked collateral as 'no bonds' #574

Description

@MichaelTaylor3d

Persist the mirror-bond COIN IDs — bond identity is currently re-derived from chain on every read

User request, verbatim: "the bonds coinids need to be remembered in the database."

The evidence that prompted it

On a live host, immediately after upgrading 0.254.72 -> 0.254.85 (which restarts the service):

before restart:  epoch 105: 3 bond(s) — 0 bonded, 0 unfunded, 3 unadvertised
after  restart:  epoch 105: 0 bond(s) — 0 bonded, 0 unfunded, 0 other · complete

The capsules did not go anywheredign stores reports 5 hosted stores, dign cache reports 407 MB on disk. Only the bond list emptied.

Why this happens — measured, not assumed

mirror/observe.rs documents itself plainly:

"it turns four already-gathered readings — the capsules on disk, the mirror coins on chain, this node's own open creates, and the $DIG it can spend — into the BondObservation the surface pages."

observe is a pure function over values with no persistence of its own. Bond identity is reconstructed each pass from a chain query, so the answer is only as good as that query at that instant. A restart, a cold replica, a chain source that has not caught up, or a transient RPC failure all render the same as "you have no bonds."

Why that is worse than a stale number

A bond is money that is currently locked. The failure direction is exactly wrong:

  • It fails OPEN into "nothing exists." An empty list is indistinguishable from "this node never bonded anything," so a reader — human or code — concludes there is nothing to protect.
  • The reconcile pass reads the same observation. If a transient chain gap makes existing bonds invisible, the pass sees capsules with no coins and its correct response is to create coins that already exist — spending collateral twice for the same (store, root).
  • Reclaim depends on knowing what to reclaim. Collateral the node cannot enumerate is collateral it cannot return.

I have not confirmed the double-create actually occurs — the in-flight suppression in runner.rs may cover the within-pass case. But that suppression is derived from the audit record, not from persisted coin ids, so it is the same class of dependency. Establish whether a cold start with a lagging chain source can double-create; that answer sets this ticket's severity.

What to persist

The (store, root, epoch) -> coin_id mapping the node created, written when the create is submitted, not when it confirms — an unconfirmed spend is precisely the state most in need of a durable record.

Alongside each: the epoch it covers, the amount locked, and the advertised URL it carries (which the reset work in dig_ecosystem#3203 will need to compare against the current one).

The constraint that decides the design

A local record must never be believed OVER chain — it must be believed IN ADDITION to it.

  • Chain remains authoritative for "is this coin still unspent." bond_verify.rs::chain_bond_verdict already answers that and must keep doing so.
  • The local record answers a different question: "what did this node create, so it knows what to go look for."
  • Where they disagree, that is a finding to surface, not to silently resolve. A locally-recorded coin that chain says is spent may mean someone else reclaimed it; a chain coin with no local record may mean a create landed after a crash. Both are worth telling an operator about.
  • BondVerdict::Unverified must stay reachable. A persisted id makes it possible to verify; it is not itself verification, and a badge or a spend decision must never treat "we wrote it down" as "chain agrees."

Related

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:businessa person can DO something new, or money moves, or a shipped surface stops lying to them

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions