Mint epoch mechanics: height-named units, records, manual rotation lever #16

Open
opened 2026-08-12 18:07:55 +01:00 by vnprc-agent · 0 comments
Collaborator

Give the mint epoch mechanics: open and close mining epochs with height-named currency units, persist epoch records, and hold provisional-epoch quotes unpaid until their boundary confirms — all exercisable by hand before any trigger exists. Design: docs/EPOCH_DESIGN.md.

Primary goals:

  • open_epoch(height, block_hash, source) — register the new unit's payment processor entry (via #15), create its keyset, write the epoch record (height, block hash, reward amount, state), and switch quote stamping to the new unit. Unit is hash_<pool>_<height> — pool = compressed pubkey from mint config, lowercase hex — with a deterministic suffix on derivation-index collision.
  • Genesis — first boot records the current chain height and opens the first epoch, final immediately, no backing reward; restarts reuse the persisted current epoch. Clean slate: existing dev/test mint state is blown away, no migration.
  • Quote lifecycle branch — quotes created while the current epoch is final are paid at creation (today's behavior); quotes in a provisional epoch are created unpaid, invisible to sweeping and unmintable through existing CDK state machinery. Finality bulk-pays them (idempotent — payment id is the share's header hash) and retires the previous epoch's registration.
  • Manual leverjust rotate-epoch hitting a localhost admin endpoint that calls open_epoch with source=manual; manual epochs have no chain boundary and are final immediately. This is the demo and the test harness for everything above.

Current state and specifics

The mint has exactly one hardcoded unit (CurrencyUnit::Custom("hash") in roles/mint/src/lib/mint_manager/setup.rs), created by builder bootstrap; no rotation code exists anywhere. The SV2 quote path hardcodes the unit at creation and immediately marks quotes paid (roles/mint/src/lib/sv2_connection/quote_processing.rs) — the stamping and the pay-now-or-defer branch both live there. Mint::rotate_keyset handles a brand-new unit at the pinned revision (non-empty amounts vector required). Epoch records need a small mint-side store; keep it separate from CDK's own schema. Bump the ehash quote TTL well past the confirmation window (expiry is advisory at the pin; do not rely on that).

Witness

On the dev stack: just rotate-epoch/v1/keysets shows the new unit's keyset active, the epoch record exists, and new quotes stamp the new unit while old-epoch quotes still mint. A second rotation repeats it. Restart reuses the current epoch (no re-genesis).

Scope

In: mint-side epoch orchestration, records, the quote-path branch, the admin lever. Out: reward detection and finality/dissolve transitions driven by the chain (#18 — this issue provides the functions it calls), sweeper multi-unit handling (#17), settlement.

Part of #13. Gated on #15.

Give the mint epoch mechanics: open and close mining epochs with height-named currency units, persist epoch records, and hold provisional-epoch quotes unpaid until their boundary confirms — all exercisable by hand before any trigger exists. Design: `docs/EPOCH_DESIGN.md`. Primary goals: - **`open_epoch(height, block_hash, source)`** — register the new unit's payment processor entry (via #15), create its keyset, write the epoch record (height, block hash, reward amount, state), and switch quote stamping to the new unit. Unit is `hash_<pool>_<height>` — pool = compressed pubkey from mint config, lowercase hex — with a deterministic suffix on derivation-index collision. - **Genesis** — first boot records the current chain height and opens the first epoch, final immediately, no backing reward; restarts reuse the persisted current epoch. Clean slate: existing dev/test mint state is blown away, no migration. - **Quote lifecycle branch** — quotes created while the current epoch is final are paid at creation (today's behavior); quotes in a provisional epoch are created unpaid, invisible to sweeping and unmintable through existing CDK state machinery. Finality bulk-pays them (idempotent — payment id is the share's header hash) and retires the previous epoch's registration. - **Manual lever** — `just rotate-epoch` hitting a localhost admin endpoint that calls `open_epoch` with source=manual; manual epochs have no chain boundary and are final immediately. This is the demo and the test harness for everything above. ### Current state and specifics The mint has exactly one hardcoded unit (`CurrencyUnit::Custom("hash")` in `roles/mint/src/lib/mint_manager/setup.rs`), created by builder bootstrap; no rotation code exists anywhere. The SV2 quote path hardcodes the unit at creation and immediately marks quotes paid (`roles/mint/src/lib/sv2_connection/quote_processing.rs`) — the stamping and the pay-now-or-defer branch both live there. `Mint::rotate_keyset` handles a brand-new unit at the pinned revision (non-empty amounts vector required). Epoch records need a small mint-side store; keep it separate from CDK's own schema. Bump the ehash quote TTL well past the confirmation window (expiry is advisory at the pin; do not rely on that). ### Witness On the dev stack: `just rotate-epoch` → `/v1/keysets` shows the new unit's keyset active, the epoch record exists, and new quotes stamp the new unit while old-epoch quotes still mint. A second rotation repeats it. Restart reuses the current epoch (no re-genesis). ### Scope In: mint-side epoch orchestration, records, the quote-path branch, the admin lever. Out: reward detection and finality/dissolve transitions driven by the chain (#18 — this issue provides the functions it calls), sweeper multi-unit handling (#17), settlement. Part of #13. Gated on #15.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
vnprc/hashpool#16
No description provided.