3.4 KiB
Mint quote recovery: scope and troubleshooting
routstrd wallet recover explicitly retries mint operations through coco using
their existing stored outputs. It can restore signatures when a quote is
already issued, and reopen failed operations when explicitly requested:
routstrd history --json
routstrd wallet recover --op <operationId> --include-failed
Failed operations require explicit IDs over both HTTP and the CLI. A successful re-run on an already finalized operation is a no-op. Requests that exceed their wait budget are not cancelled; explicit retries skip the operation while the underlying work is outstanding.
What this fixes—and what it does not
Coco already checks pending quotes on startup and the daemon periodically refreshes them. A quote paid while the daemon was offline does not, by itself, require a new issuance implementation.
This change makes normal cleanup confirm UNPAID with the mint before failing an expired quote. PAID, ISSUED and unverified quotes remain pending. It also gives operators a recovery path for operations previously marked failed.
It does not replace rejected outputs with fresh outputs on an active keyset. An inactive-keyset rejection can therefore remain retryable with zero recovery. Recovery reports coco's persisted mint error when available, rather than only a generic “remains pending” error.
Do not infer that the production incidents were caused by keyset retirement. Before claiming those incidents are fixed, collect:
- The affected operation IDs, quote IDs, state and persisted
error. - A fresh remote quote state and, where provided, paid/issued amounts.
- The keyset IDs in the stored outputs and the mint's current keyset metadata.
- A reproduction showing existing recovery fails and the proposed fix succeeds.
Inspect persisted operation data through a read-only database copy; do not edit rows or run recovery scripts concurrently with a daemon against the same wallet. Never share the mnemonic, output secrets, or full wallet database in a PR.
A future fresh-output path must preserve original outputs for uncertain issuance and NUT-09 restore, allocate fresh deterministic counters safely, and coordinate with coco's watcher/processor. It needs its own integration tests before handling real funds.
Cleanup preview and force
wallet cleanup --dry-run is local-only: it reports mintQuoteCandidates, not
confirmed failures. failedMintQuotes and leftForRecovery are zero because no
mint check or cleanup transition was performed. Send/melt counts remain planned
cleanup counts in dry-run mode.
--force deliberately bypasses mint confirmation and can strand paid sats in a
failed operation. Prefer normal cleanup. Forced operations can be retried with
--op <operationId> --include-failed, but recovery still depends on the mint
accepting their stored outputs or restoring their signatures.
Integration and release notes
The reopen helper uses private coco-core 1.0.1 methods. Retain real-Manager and HTTP fake-mint coverage, use frozen dependency installs, and re-run integration tests on coco upgrades. A controlled low-value live-mint smoke test remains recommended before release.
PR #118 removes cocod-client.ts. When integrating that change, move recovery
and cleanup contracts into its replacement wallet-client.ts, rename HTTP error
references accordingly, and make recovery mandatory for the in-process client.
This follow-up does not pull in #118's unrelated removal.