Skip to content

Mirror-coin lifecycle: presence tracks the .dig file on disk, created/reclaimed automatically per epoch #377

Description

@MichaelTaylor3d

Task

Implement the mirror-coin lifecycle in dig-node: create one per (store, root) it serves per epoch,
reclaim the previous epoch's, and reclaim when it stops serving
— signing automatically, under a
scoped key.

Per (store, root), not per store. The legacy had one coin per store; roots are now broadcast
individually, so a publisher can fund the latest root and not the legacy one if they choose.

The naming chain, so the legacy source is readable

server coin (legacy code) → collateral coin (interim) → mirror coin (canonical). grep -rniE "mirror" across all three legacy src/ trees returns zero hits — the type is ServerCoin; "mirror" is the puzzle name one layer down in DataLayer-Driver.

§908 carve-out — the node signs this automatically

User directive: "the node MUST sign this on the users behalf, managing these mirror coins behind the scenes, and creating the spends automatically is a hard requirement. Its impossible for the user to approve all the transactions."

Scoped to mirror coins. §908 stands for everything else. The shape to lock first (§1.10): which key signs (a dedicated, separately-derived key with a bounded working balance — not the master seed, or the carve-out is total), what bounds the authority (per-epoch cap, the epoch's required amount per (store, root), destination restricted to the mirror puzzle), what the user accepts and when, and how revocation reclaims what is locked.

The legacy state machine, measured — replicate the shape, not the bugs

ensureServerCoinExists (dig-chia-sdk/src/blockchain/ServerCoin.ts:285-363), driven by a 60-second job (sync_stores.ts:326-333), not a weekly timer — the weekly cadence is emergent from comparing the computed epoch to the cached one:

  • coin exists, synced, root matches → no-op (:306)
  • coin exists, synced, root moved → update the local record only, no chain write (:311)
  • coin exists, not syncedmelt it (:323), stated reason: "helps prevent penalties for not having a valid peer registered"
  • no coin, synced → create (:334)
  • not synced → return without creating (:327) — never advertise a store you cannot serve

It is a re-create per epoch, not a renew. Nothing tops up or extends.

The epoch clock

calculateEpochAndRound (ServerCoin.ts:500-529): 7-day wall-clock windows, hard-coded 7*24*60*60*1000, 1-based, genesis 2024-09-03T00:00Z. Rounds are 10 minutes, 1008 per epoch. No chain input.

dig-epoch is NOT this. It is L2 epoch geometry anchored to L1 block heights with BlockProduction/Checkpoint/Finalization phases — a different notion. Using it here would silently change the cadence. If it is adopted anyway, it leaves the parked L2 island and needs the same release-first treatment as dig-mirror-coin.

Bugs NOT to inherit — this is the highest-value part of the brief

  1. meltOutdatedEpochs had no in-repo callers, but it WORKED — it was an operational step.
    Corrected by the user directly: "no meltOutdatedEpochs worked when that legacy ran. We just had to
    locate the old coins and spend them in that version."
    An earlier version of this ticket called it
    dead code; that was wrong, and the error is worth keeping visible — "no callers" was turned into
    "never happened" without asking what ran outside the repo.

    The requirement survives, and it binds harder here than it did there: dig-node has no operator.
    Nobody will locate and spend the old coins by hand. So reclaiming epoch n-1 when creating epoch
    n is an acceptance criterion, not an optimisation — stranded collateral is real user money that
    never comes back.

  2. Unbounded retry under the sync mutex (:71-78 + sync_stores.ts:253) — recursion on a substring match, no cap, no backoff. One underfunded store stalls synchronisation of every other store, forever.

  3. IP-keyed records (:116) with a 7-day IP refresh (ip_refresh.ts:41-48) — a dynamic IP strands collateral at every address ever held. Key on launcher id + owner puzzle hash.

  4. The local .json was authoritative and unrecoverable if lost. Use query::list (keyed on owner puzzle hash, ownership from the lineage proof) as the source of truth.

  5. waitForConfirmation waited on the wrong coin (:347) — it waits for the funding coin to be spent, which a competing spend satisfies identically. It never confirmed the mirror coin was created.

  6. Reclaim requires XCH for its own fee (:136), and meltUntrackedStoreCoins (:424-438) has no per-coin try/catch — the first failure aborts the whole sweep. A wallet at zero can be unable to advertise and unable to recover what it already locked.

  7. Melt/create churn on sync flap (:321-323) — two fees and two confirmation waits per round trip.

Amount

The amount is derived per epoch, not fixed. equilibrium x multiplier - handicap, computed from
chain data and independently reproducible by every node — specified in
https://github.com/DIG-Network/dig_ecosystem/issues/3173 and implemented in dig-mirror-collateral.
Call that crate; never re-derive the formula — its clamps are structural in the code and absent from
the formula as written, so re-deriving reintroduces holes.

$DIG has 3 decimals, so whole $DIG x 1,000 = CAT mojos. At genesis the schedule starts at 1.000 $DIG
per (store, root) and rises toward 5.000 as the handicap decays. Legacy locked 0.0003 XCH — a
different asset entirely; do not let it drift back.

Hard constraints

  • Never hand-roll a spend bundle (§4.1) — dig-mirror-coin builds them.
  • Every automated spend writes to the audit record (dig-node#376). A spend reaching chain with no entry is invisible money movement.
  • BLOCKED on dig-mirror-coin reaching the ceiling and publishing (dig-mirror-coin#3). Adopting it at chia 0.26/0.30 would re-split dig-node, which just reached 0.36.1.

Evidence (§2.6)

A person watching a (store, root) get collateralised on a real machine: the epoch's required amount
locked, the coin resolvable on chain, and the previous epoch's coin reclaimed at rollover. Not a green
suite.

Parent

https://github.com/DIG-Network/dig_ecosystem/issues/3166

Metadata

Metadata

Assignees

No one assigned

    Labels

    mvpgates the releasable MVP

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions