NUT-XX pubkey quote discovery: sweeper reconcile + cdk pin cba8469b #21

Open
vnprc-agent wants to merge 20 commits from agent/nutxx-pubkey-lookup into master
Collaborator

The translator's wallet now discovers its mint quotes by locking pubkey — a 15s reconcile loop asking the mint for all still-mintable quotes locked to its key — instead of depending on per-quote notifications that can be dropped. Re-pins cdk from 7011eebc to vnprc/cdk cba8469b (same NUT-XX lineage, plus the pubkey-encoding fix and the only_mintable lookup filter this branch uses). Nothing changes for the pool or mint protocol surface; the mint's existing lookup endpoint gains the only_mintable filter and pubkey-encoding fixes from the cdk bump, and the wallet gains the lookup API. If this is wrong, revert the merge — master stays functional on 7011eebc.

This branch is the base of the epoch milestone stack (#13): merging it unblocks the epoch-mechanics and multi-unit-sweeper PRs.

Refs #7.

Risk

The cdk pin moves in all three in-repo places together (roles/Cargo.toml, protocols/Cargo.toml, devenv.nix); roles/Cargo.lock keeps the MSRV-pinned transitive deps (time 0.3.41 family) — a fresh re-resolve would break the devenv toolchain (issue #10). The old 0xC0 notification path is retained but its wallet-side fetch is disabled; discovery is sweep-only.

Validation

Live-run validated on the dev stack 2026-08-10: 64 quotes / 662 ehash minted via pubkey reconcile, including 12 quotes whose notifications were deliberately dropped; wallet and mint databases reconcile exactly. Branch merged with current master (docs + 0.17 bump) with pins kept at cba8469b; conflict resolution verified: single [patch] block, single cdkCommit, zero stale revs, MSRV lock pins intact.

The translator's wallet now discovers its mint quotes by locking pubkey — a 15s reconcile loop asking the mint for all still-mintable quotes locked to its key — instead of depending on per-quote notifications that can be dropped. Re-pins cdk from `7011eebc` to `vnprc/cdk` `cba8469b` (same NUT-XX lineage, plus the pubkey-encoding fix and the `only_mintable` lookup filter this branch uses). Nothing changes for the pool or mint protocol surface; the mint's existing lookup endpoint gains the only_mintable filter and pubkey-encoding fixes from the cdk bump, and the wallet gains the lookup API. If this is wrong, revert the merge — master stays functional on `7011eebc`. This branch is the base of the epoch milestone stack (#13): merging it unblocks the epoch-mechanics and multi-unit-sweeper PRs. Refs #7. ## Risk The cdk pin moves in all three in-repo places together (`roles/Cargo.toml`, `protocols/Cargo.toml`, `devenv.nix`); `roles/Cargo.lock` keeps the MSRV-pinned transitive deps (`time` 0.3.41 family) — a fresh re-resolve would break the devenv toolchain (issue #10). The old 0xC0 notification path is retained but its wallet-side fetch is disabled; discovery is sweep-only. ## Validation Live-run validated on the dev stack 2026-08-10: 64 quotes / 662 ehash minted via pubkey reconcile, including 12 quotes whose notifications were deliberately dropped; wallet and mint databases reconcile exactly. Branch merged with current master (docs + 0.17 bump) with pins kept at `cba8469b`; conflict resolution verified: single `[patch]` block, single `cdkCommit`, zero stale revs, MSRV lock pins intact.
Move all coordinated CDK pins from cashubtc/cdk 1572941d (0.16.0) to
vnprc/cdk 7011eebc, the tip of branch fix/nutxx-lookup: upstream main at
23fa905d plus the NUT-XX mint quote lookup endpoint. The mint now serves
POST /v1/mint/quote/pubkey (schnorr-signed, replay-protected lookup of
mint quotes by NUT-20 locking key); no hashpool role calls it yet.

- protocols/Cargo.toml, roles/Cargo.toml: [patch.crates-io] -> vnprc/cdk
  rev 7011eebc for all cdk crates
- protocols/ehash, roles/mint, roles/translator Cargo.toml: cdk version
  reqs 0.16.0 -> 0.17.0 to match the patched workspace version
- roles/mint/Cargo.toml: cdk-ehash rev 40fdebe -> 1328180 (branch
  agent/nutxx-cdk-017: the paired cdk-ehash bump to the same CDK rev)
- devenv.nix: cdkRepo/cdkCommit -> vnprc/cdk 7011eebc; build:cdk:cli now
  interpolates those variables instead of hardcoding a second copy of
  the URL and commit, so future bumps touch one place
- scripts/patch-cdk-path.sh: match github.com/(cashubtc|vnprc)/cdk so
  the local-path patcher keeps recognizing the pin lines
- protocols/ehash/src/quote.rs: MintQuoteCustomRequest.amount became
  Option<Amount> upstream; wrap the construction site and test assert
- roles/Cargo.lock: re-resolved; cdk crates to 0.17.0/7011eebc, new
  transitive deps bdk_electrum/electrum-client/bitreq from upstream's
  wallet work, no other pin movement

Upstream drift absorbed: 265 commits (1572941d..7011eebc). Mint DB gets
two additive migrations on first start (updated_at column backfill +
pubkey index); wallet DB gets one (updated_at). No destructive schema
changes.

Validation (rustc 1.97.1, cdk repo nix dev shell; devenv nixpkgs rustc
is 1.95.0, above cdk's 1.85 MSRV): cargo check --all-targets clean and
full test suites green in all three workspaces - protocols 55 tests,
roles 51 suites 0 failures, cdk-ehash 16 tests. Runtime devenv up
mining smoke test remains a human gate.
Move the vnprc/cdk patch pin from 7011eebc to ec97d741 on
agent/nutxx-wallet-client, the combined NUT-XX mint + wallet branch,
across protocols/Cargo.toml, roles/Cargo.toml, and devenv.nix
(cdkCommit). roles/mint/Cargo.toml keeps cdk-ehash at rev 1328180
since the MintPayment trait it consumes is unchanged.

The bump carries CurrencyUnit::Custom from a String payload to
Arc<str>. Update every call site constructing the "hash" custom unit
accordingly:
- protocols/ehash/src/keyset.rs
- protocols/ehash/src/quote.rs (impl + test)
- protocols/ehash/src/sv2.rs (test)
- roles/mint/src/lib/mint_manager/setup.rs
- roles/mint/src/lib/sv2_connection/quote_processing.rs
- roles/translator/src/lib/payment/wallet.rs

Regenerate roles/Cargo.lock against the new rev.
Add a reconcile step at the start of each quote sweeper pass: query
Wallet::mint_quotes_by_pubkey with the translator's locking key, and
for any returned quote not already in the wallet's local store, call
Wallet::fetch_mint_quote to store it through cdk's own accounting
logic (no hand-constructed MintQuote records).

This catches quotes the mint holds against our key that never arrived
through the SV2 notification path (dropped message, translator
restart). The existing get_unissued_mint_quotes -> batch_check ->
batch_mint flow is unchanged and now simply sees the reconciled
quotes alongside anything the notification path already delivered.

A failed pubkey lookup or a single bad quote is logged and skipped
rather than aborting the sweep pass.
The MintQuoteNotification (0xC0) handler's fetch_mint_quote(quote_id,
Custom("ehash")) call is now redundant: the quote sweeper's pubkey
reconcile (Wallet::mint_quotes_by_pubkey) is the discovery source of
record. Comment out the fetch, leaving the payload decode, the
quote_id/amount extraction, and the info! logging in place so the
notification is still observed and logged, just no longer acted on.

The rest of the SV2 plumbing is untouched: the pool poller, the
MintQuoteNotification/MintQuoteFailure message types, and the
mint-side send all remain as-is. Retained but now-unused import and
struct field are marked #[allow(...)] with a note rather than
removed, so re-enabling the fetch later is a one-line uncomment.
Bump the cdk pin to 693f4ec4 (NUT-XX wallet: reject method-less quote
lookup responses instead of mislabeling them Bolt11, and store/validate
pubkey-looked-up quotes in the wallet database).

reconcile_quotes_by_pubkey now makes one call to
Wallet::fetch_mint_quotes_by_pubkey and logs the result; cdk does the
per-quote known-locally check, accounting, and local storage itself, so
the old per-quote check-then-fetch loop is gone. Documents the known
accepted cost of this call (O(full quote history) per lookup until the
NUT grows a state filter - see cashubtc/nuts PR 341) directly above it.

The signing-key stamping loop in process_stored_quotes is unchanged:
quotes reconciled via pubkey lookup now arrive pre-stamped, but the loop
still covers quotes discovered by other means (SV2 notifications,
pre-existing DB rows), so it stays, with a comment noting why.
Bump the cdk pin to 6cf76d12 (NUT-XX: skip malformed quotes in the
pubkey lookup instead of failing the batch, a real regression test for
the fetch_mint_quotes_by_pubkey write-guard, and an opt-in
only_mintable filter on the pubkey lookup request).

reconcile_quotes_by_pubkey now calls fetch_mint_quotes_by_pubkey with
only_mintable: true, so the mint bounds its response to quotes still
mintable for this key. Replace the old O(full quote history) cost note
- which was pending a NUT-level filter - with a short comment that this
filter is implementation-side while the spec discussion at
cashubtc/nuts PR 341 is still open.
Pubkey-lookup reconcile results now log at info when quotes were
discovered (a validation run showed the debug-only line made the
discovery path invisible at the stack's default RUST_LOG=info); quiet
passes stay at debug.

cdk pin moves to 73bbef28: the wallet-side series rebased onto TheMhv's
rebased wallet PR branch (his real commits now underneath), plus a
created_time fix at the shared wallet store path and a mint-side debug
line for lookup observability. Tree-equivalent feature content to the
previous pin.
Tree-identical to the previously pinned local rev; the hash moves to the
commits actually pushed to the fork and under review, so devenv and any
checkout without local redirects fetch the real PR code from GitHub.
Author
Collaborator

Adversarial review findings.

Merge verification (all clean): 49edec22 has an empty combined diff (no evil-merge content); vs the validated branch tip it adds exactly master's three docs files; vs master only branch work + the declared pin supersession, with nothing from master lost (files the 0.17 bump touched that aren't in this diff are byte-identical to master). Single [patch.crates-io] per workspace, single cdkCommit, all 16 lock entries at cba8469b, MSRV pins intact (time 0.3.41 / serde_with 3.17.0 / darling 0.21.3 / simple_asn1 0.6.3), zero stale revs from all 12 superseded hashes, zero conflict markers; the quote.rs resolution (Custom(Arc<str>) form) is the only one that compiles at the kept pin.

should-fix (body text) — "the mint gains the NUT-XX lookup endpoint from the cdk bump" is false: the /mint/quote/pubkey route is identical at master's pin 7011eebc. What the bump actually delivers is the only_mintable filter + pubkey-encoding fixes mint-side and the lookup API wallet-side. Corrected in the body so a future bisect/revert doesn't misjudge master's capabilities.

Verdict: textbook merge, nothing lost; body corrected.

Adversarial review findings. **Merge verification (all clean):** `49edec22` has an empty combined diff (no evil-merge content); vs the validated branch tip it adds exactly master's three docs files; vs master only branch work + the declared pin supersession, with nothing from master lost (files the 0.17 bump touched that aren't in this diff are byte-identical to master). Single `[patch.crates-io]` per workspace, single `cdkCommit`, all 16 lock entries at `cba8469b`, MSRV pins intact (`time` 0.3.41 / `serde_with` 3.17.0 / `darling` 0.21.3 / `simple_asn1` 0.6.3), zero stale revs from all 12 superseded hashes, zero conflict markers; the quote.rs resolution (`Custom(Arc<str>)` form) is the only one that compiles at the kept pin. **should-fix (body text)** — "the mint gains the NUT-XX lookup endpoint from the cdk bump" is false: the `/mint/quote/pubkey` route is identical at master's pin `7011eebc`. What the bump actually delivers is the `only_mintable` filter + pubkey-encoding fixes mint-side and the lookup API wallet-side. Corrected in the body so a future bisect/revert doesn't misjudge master's capabilities. Verdict: textbook merge, nothing lost; body corrected.
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin agent/nutxx-pubkey-lookup:agent/nutxx-pubkey-lookup
git switch agent/nutxx-pubkey-lookup
Sign in to join this conversation.
No reviewers
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!21
No description provided.