Repository navigation
chore(wallet): bump gonuts-tollgate v0.14.0; honest keyset ids in test fakes - #1063
Conversation
… ids in test fakes One logical change, two halves: 1. The pin: scripts/bump-gonuts.sh v0.14.0 rewrote the manifest and all 5 carrier go.mod/go.sum in one run (fence: one pin, everywhere, and v0.14.0 is the fork's newest stable tag). What the fork gained since v0.13.0: the NUT-13 residue-collision guard + advertised-keyset-id verification (#37, tollgate #705), the refuse-swap-consumed-entirely-by-fees guard (#36), pre-persisted swap intents with crash replay (#31), and cached keyset fees (#30). The fork also wires VerifyProofsDLEQWithKeysets at swap/receive internally (tollgate #1057's upstream half). 2. The fixtures: v0.14.0's #705 guard verifies a mint's advertised keyset id against the id its published keys derive to — and our test fakes were forging (arbitrary ids over hand-picked keys: 'ab'x16, 009a1f29, 00ad268c over the generator point). The guard refused them, exactly as designed. All fake mints now advertise ids their keys derive to: tollwallet gains a deriveHonestKeysetID helper (fork's own DeriveKeysetId) used by the shared fixtures; merchant's fakes carry the derived id with provenance comments. Every assertion is untouched — only the advertised ids became honest. Battery: 18/18 modules green under go1.26.10 (gofmt/vet/build/ test -race -count=1 -tags testenv), including the previously-failing tollwallet checkstate/#375-registry suites and the merchant degraded- recovery pair. Fences: gonuts-pin(+--latest), toolchain parity, and changelog-duplicate guard all green.
Local CI gate — PR #1063: chore(wallet): bump gonuts-tollgate v0.14.0; honest keyset ids in test fakesRun of
Verdict: 2 leg(s) RED — 4 green. What this gate does not run (no vacuous green)
failing-leg log tailscontract-fences — tailshell-suites — tail |
Evidence review — 13-criteria pass (independently verified at head)Verified: Fund-safety walk (criterion 10, the one that matters here):
Fixture honesty pass (criterion 4/8): the 15 conversions are assertion-untouched fixture fixes with provenance comments, deriving ids via the fork's own Cross-PR notes (criterion 12): #1058's pin test reads the pinned module source — after this bump it asserts against v0.14.0, where the wiring it checks is even more real (the fork now wires the keyed DLEQ verify at swap/receive, per the body). Either merge order works; landing #1058 first keeps the pin green across both versions' ranges. #1060 is the other red this closes (the nak skew), and per the body the remaining deps-leg reds after this are #1000/#1003 — the release-gate path is fully mapped. Verdict: mechanically ready; the release-blocking character makes it first in the owner queue. Posted for the human gate (Amperstrand-authored). |
The honest fixtures prove derived-id fakes are accepted; this plants the DRIFT — a random key advertised under an unrelated V1-shaped id — and requires New -> registerMint -> AddMint to refuse it naming the forgery. Per the fence doctrine (a guard nobody has seen reject is decoration), this is the rejection proof for the v0.14.0 behavior this bump adopts.
|
Hardening added while in review queue (per the fence doctrine — planted-drift verdicts): |
Local CI gate — PR #1063: chore(wallet): bump gonuts-tollgate v0.14.0; honest keyset ids in test fakesRun of
Verdict: 2 leg(s) RED — 4 green. What this gate does not run (no vacuous green)
failing-leg log tailscontract-fences — tailshell-suites — tail |
…et on Unknown Keyset with a reachable mint Wallet init on a DB caching keysets the mint has rotated out failed with 'error getting keyset from mint: Unknown Keyset', the merchant degraded, and the degraded path's first-reachable trigger never fired (mint reachable all along) — the router bricked until wallet.db was moved aside, discarding proofs (#818). State machine at the New() seam: init fail → classify with the fork's IsUnknownKeysetError → if unknown-keyset class AND the current mint answers the bounded NUT-02 /v1/keysets probe (mintServesKeysets), re-fetch and retry the load ONCE → proceed or degrade. Everything else (storage errors, unreachable mint, real refusals) degrades exactly as before — the storage-degraded family (#583/#1035) is a separate slice. Pin: gonuts-tollgate v0.14.1-0.20261024073441-2c1154c68048 (pseudo-version integration pin, #771 pattern) — fork PR #44 carries the loadWalletMints tolerance; stacks on #1063 (v0.14.0 + honest fixtures); owner tags the fork, then scripts/bump-gonuts.sh finalizes.
…et (NUT-02) on Unknown Keyset with a reachable mint (#1077) * fix(tollwallet): #818 self-heal — wallet init re-fetches the keyset set on Unknown Keyset with a reachable mint Wallet init on a DB caching keysets the mint has rotated out failed with 'error getting keyset from mint: Unknown Keyset', the merchant degraded, and the degraded path's first-reachable trigger never fired (mint reachable all along) — the router bricked until wallet.db was moved aside, discarding proofs (#818). State machine at the New() seam: init fail → classify with the fork's IsUnknownKeysetError → if unknown-keyset class AND the current mint answers the bounded NUT-02 /v1/keysets probe (mintServesKeysets), re-fetch and retry the load ONCE → proceed or degrade. Everything else (storage errors, unreachable mint, real refusals) degrades exactly as before — the storage-degraded family (#583/#1035) is a separate slice. Pin: gonuts-tollgate v0.14.1-0.20261024073441-2c1154c68048 (pseudo-version integration pin, #771 pattern) — fork PR #44 carries the loadWalletMints tolerance; stacks on #1063 (v0.14.0 + honest fixtures); owner tags the fork, then scripts/bump-gonuts.sh finalizes. * test(tollwallet): anchor the hook-retry fixture to the retry boundary — mutation check bites The first version flipped the mint's health inside attempt 1's own /v1/keys fallback, so the load healed itself and the test passed with the hook disabled (decorative). The mint now heals at /v1/keysets call #2 — the hook's probe — so the RETRY is what succeeds; with the hook disabled the test fails with #818's exact signature. * test(merchant): merchant reaches READY at boot under keyset rotation (#818) Full startup path against a hermetic rotating mint with a seeded pre-rotation wallet.db: probe → wallet init (self-heal past the retired keyset) → advertisement → *Merchant, not *MerchantDegraded. GetConfig returns a defensive copy — the accepted mints are persisted via SaveConfig + ReloadConfig (mutating the copy boots against the factory-default mint; the first version of this test passed by reaching coinos.io over the network). The mint's /v1/keysets probe is counted to prove the merchant talked to the fake, and the fixture ids are honest (v0.14.0 #705 guard). Mutation verdicts: fork pin dropped to v0.14.0 → the branch does not compile (wallet.IsUnknownKeysetError undefined — the slice is coupled to gonuts PR #44); the failure mode itself is mutation-verified at the two lower layers (fork suite + tollwallet hook test). * changelog: fragment for #1077 (#818 self-heal) * deps(wallet): gonuts-tollgate v0.14.1 — tag landed, retire the pseudo-pin Owner merged and tagged the fork (a5f5423 + changelog fold, tag v0.14.1). bump-gonuts.sh rewrote manifest + every discovered carrier; fence green including --latest (newest stable tag). go-battery: 18 modules green. --------- Co-authored-by: Amperstrand <Amperstrand@users.noreply.github.com>
#752) (#908) * fix(merchant): classify the wallet's nothing-left-to-swap belt refusal (#752) — same clean below-swap-fee notice isBelowSwapFeeError now maps gonuts-tollgate v0.13.1+'s local refusals ('entirely consumed by the mint's swap fees … nothing to swap', 'produced no outputs: refusing to send an empty swap') to the clean payment-error notice, instead of surfacing a raw mint CU107 to the payer. * fix(tollwallet): #818 self-heal — wallet init re-fetches the keyset set (NUT-02) on Unknown Keyset with a reachable mint (#1077) * fix(tollwallet): #818 self-heal — wallet init re-fetches the keyset set on Unknown Keyset with a reachable mint Wallet init on a DB caching keysets the mint has rotated out failed with 'error getting keyset from mint: Unknown Keyset', the merchant degraded, and the degraded path's first-reachable trigger never fired (mint reachable all along) — the router bricked until wallet.db was moved aside, discarding proofs (#818). State machine at the New() seam: init fail → classify with the fork's IsUnknownKeysetError → if unknown-keyset class AND the current mint answers the bounded NUT-02 /v1/keysets probe (mintServesKeysets), re-fetch and retry the load ONCE → proceed or degrade. Everything else (storage errors, unreachable mint, real refusals) degrades exactly as before — the storage-degraded family (#583/#1035) is a separate slice. Pin: gonuts-tollgate v0.14.1-0.20261024073441-2c1154c68048 (pseudo-version integration pin, #771 pattern) — fork PR #44 carries the loadWalletMints tolerance; stacks on #1063 (v0.14.0 + honest fixtures); owner tags the fork, then scripts/bump-gonuts.sh finalizes. * test(tollwallet): anchor the hook-retry fixture to the retry boundary — mutation check bites The first version flipped the mint's health inside attempt 1's own /v1/keys fallback, so the load healed itself and the test passed with the hook disabled (decorative). The mint now heals at /v1/keysets call #2 — the hook's probe — so the RETRY is what succeeds; with the hook disabled the test fails with #818's exact signature. * test(merchant): merchant reaches READY at boot under keyset rotation (#818) Full startup path against a hermetic rotating mint with a seeded pre-rotation wallet.db: probe → wallet init (self-heal past the retired keyset) → advertisement → *Merchant, not *MerchantDegraded. GetConfig returns a defensive copy — the accepted mints are persisted via SaveConfig + ReloadConfig (mutating the copy boots against the factory-default mint; the first version of this test passed by reaching coinos.io over the network). The mint's /v1/keysets probe is counted to prove the merchant talked to the fake, and the fixture ids are honest (v0.14.0 #705 guard). Mutation verdicts: fork pin dropped to v0.14.0 → the branch does not compile (wallet.IsUnknownKeysetError undefined — the slice is coupled to gonuts PR #44); the failure mode itself is mutation-verified at the two lower layers (fork suite + tollwallet hook test). * changelog: fragment for #1077 (#818 self-heal) * deps(wallet): gonuts-tollgate v0.14.1 — tag landed, retire the pseudo-pin Owner merged and tagged the fork (a5f5423 + changelog fold, tag v0.14.1). bump-gonuts.sh rewrote manifest + every discovered carrier; fence green including --latest (newest stable tag). go-battery: 18 modules green. --------- Co-authored-by: Amperstrand <Amperstrand@users.noreply.github.com> --------- Co-authored-by: Amperstrand <Amperstrand@users.noreply.github.com>
|
Review — verdict: CONCERNS(1, mechanical); disposition: land after retitling — the substance is verified green This is the deliberate fork bump the release fence asks for, and its mechanics check out end-to-end here: the pin fence passes with the tree's actual pin, the modules that the fork's new guard reddened are green under the new version, and the landing vs today's main (including this morning's #1106) is clean. The one concern is accuracy of the PR's own packaging: the tree carries v0.14.1, but the title, body, and changelog fragment all say v0.14.0 — for a PR whose stated posture is "verified decision package", that's worth fixing before the owner merges. The version story (what I found): the branch's first commit did bump v0.14.0 as advertised. The tree's v0.14.1 rewrite arrived inside
Suggested fixes before merge: retitle to What I verified green (worktree at head
evidence— agent evidence pass (review-debt wave R1); not an approval. |
c03rad0r
left a comment
There was a problem hiding this comment.
Technical review — head e1fad124. Approving the dependency move, with a title/body correction and one scope question.
The pin is right and the fence agrees with itself:
python3 tests/contract/check-gonuts-pin.py → ✅ one pin everywhere v0.14.1 (5 carriers)
python3 tests/contract/check-gonuts-pin.py --latest → ✅ v0.14.1 is the fork's newest stable tag
cd src/tollwallet && go test -tags testenv -count=1 -run 'Forged|Honest|Keyset|Split|Swap' ./...
ok
The honest-fixture pass is the right response to #705: 15 fakes were advertising ids their keys did not derive to, and the guard reddening them is the fix working. Deriving ids with the fork's own DeriveKeysetId (rather than hardcoding new constants) keeps the fixtures honest under future key changes.
Title/body correction needed: the branch now pins v0.14.1, not v0.14.0 — the fence checks "newest stable tag", so a later tag moved it. Retitle to v0.14.1 and say what that adds over the body's five v0.14.0 commits.
Scope question (please answer in the PR): the three-dot diff also carries the #1077 wallet self-heal (src/tollwallet/tollwallet.go + init_selfheal_test.go, ~200 lines) and changelog fragments for #908 and #1077. #1077 and #908 are marked merged, but main does not contain IsUnknownKeysetError — so this PR is currently the only path those changes have to main. If that is deliberate, say so in the body ("this also carries #1077/#908 because their merges did not reach main") and keep the fragments; if not, split them so the bump stays reviewable as a bump. The fragments themselves are accurate; the only risk is a future reader assuming the bump also changed wallet init semantics without reading the diff.
No fund-safety objection to the bump itself: #36/#37/#31 are the fixes we want, and the test-only fixture changes do not alter assertions.
Disposition: land (after the title/body correction; scope answer requested).
Rebuilt on #1063 pin (gonuts v0.14.1, which carries #31 pre-persisted swap intents): the wallet-port resume wiring, the once-at-boot call before serving payments, the cdk no-op and the sidecar typed error. The pseudo-version pin from the original branch is dropped; the fragment is relinked to this PR.
Why
release-check's deps leg refuses a cut while the fork has a newer stable tag than the pin (v0.13.0 < v0.14.0), and the audit-trio dig showed the fork's newer tags carry fund-safety-relevant fixes. This is the deliberate bump the fence asks for, prepared as a verified decision package: dry-run first, then the fixture honesty pass the dry-run forced, then the full battery.What the fork gains (v0.13.0 → v0.14.0, five commits)
VerifyProofsDLEQWithKeysetsat swap/receive — the upstream half of DLEQ on the receive path: the proof.Id-keyed verify exists in gonuts v0.13.0 but is unreachable from this module #1057; the repo-side call remains open there.The fixture honesty pass (test-only, assertions untouched)
v0.14.0's #705 guard made 15 tests red across
tollwalletandmerchant— every fake mint advertised an arbitrary id over hand-picked keys (ab×16,009a1f29…,00ad268c…over the generator point). The guard refusing them is the fix working. Fakes now advertise ids their keys actually derive to:tollwallet: newhonest_keyset_test.goderives ids via the fork's owncrypto.DeriveKeysetId(honestV1KeysetIDfor the shared generator-point keyset;honestKeysetIDFromPrivfor per-run random keys); six fixture files converted.merchant: four fake-mint files carry the derived id with provenance comments.Verification
scripts/bump-gonuts.sh v0.14.0: manifest + every discovered carrier rewritten in one run;check-gonuts-pin.pyand--latestgreen ("one pin, everywhere … is the fork's newest stable tag").test -race -count=1 -tags testenv), including the suites the guard initially reddened (tollwallet check-state + tollgate wallet drain cashu #375 registry + receive/sentinel; merchant degraded-recovery pair, 345.8s race).Fragment follows once the PR number exists. This unblocks the deps leg of the release gate for #1033 — the remaining main-side reds are #1000 (doc-facts 16≠18), #1003 (mptcp_bonding go floor), and the nak skew already fixed in #1060.