Skip to content

chore(deps): bump gonuts-tollgate v0.11.2 → v0.12.0 (melt/swap-retry counter reservation + #480 landing) - #506

Merged
Amperstrand merged 2 commits into
mainfrom
deps/gonuts-v0.12.0
Sep 22, 2026
Merged

Amperstrand merged 2 commits into
mainfrom
deps/gonuts-v0.12.0

Conversation

@Amperstrand

Copy link
Copy Markdown
Collaborator

Pure dependency bump, no source changes (three go.mod replace pins + go.sum), same shape as #266/#392/#394.

Picks up the gonuts v0.12.0 fund-safety train (gonuts-tollgate#28):

Verification: go build/vet clean from src/; race suites green in the two gonuts-consuming modules (tollwallet 35s, merchant 432s) + root module (21s), all -tags testenv -count=1.

Amperstrand added 2 commits September 22, 2026 10:25
… counter reservation + #480 landing

Picks up the fund-safety train (gonuts-tollgate#28, tagged v0.12.0):

- the #480 fix lands: canonical mint-URL bucket keys, one-time
  max-counter alias merge on open, SaveKeyset monotonic-counter guard —
  service restarts no longer replay swap outputs on alias-carrying
  wallets (#480, #496)
- Melt reserves its blank-output derivation range before PostMeltBolt11;
  a lost Paid-with-change response no longer bricks the melt path when
  the caller retries with a fresh quote (#494)
- swapWithRetry reserves its retry range; the counter no longer trails
  the last exposed range after a 10002-retry (#495)
- writer-audit pin: keyset rewrites can never rewind a counter

Verification: go build/vet clean; race suites green in the two modules
that consume gonuts (src/tollwallet 35s, src/merchant 432s) plus the
root module (21s), all -tags testenv.
@Amperstrand

Copy link
Copy Markdown
Collaborator Author

Verification — the #480 fix chain is closed end-to-end at the TollGate level. Live restart-repro green.

Checked at head (320896bd, bumping to v0.12.1 — includes the serialized-ReclaimUnspentProofs fix on top of v0.12.0):

Library lineage (v0.12.0/v0.12.1): contains the #480 fix verbatim (1c24161 — canonical mint-URL bucket keys + alias merge + monotonic-counter guard), unioned with #24's lock-timeout fix, plus the counter-reservation hardening (swap-retry range reserved before re-exposure, melt blank-output range reserved before PostMeltBolt11 — the lost-Paid-response brick classes), and a writer-audit pin test asserting AddMint-path keyset rewrites can never rewind the counter. v0.12.1 adds ReclaimUnspentProofs swap serialization.

Live discriminator (isolated cloud-lab, real cdk-mintd, exactly the rig that reproduced the brick):

payment before the fix at this PR head
1, 2 (pre-restart) 200, 200 200, 200
restart → 3 400 Duplicate outputs 200
4 (absorbing check) 400 200
restart → 5 400 200

Post-run wallet.db forensics: one canonical bucket per mint (no trailing-slash aliases), derivation counter monotonic at 35 across both restarts.

Module spot-battery green at head (tollwallet builds against v0.12.1; merchant expired-keyset tests pass under race).

From our side: this PR is the release gate satisfied — land it before any alpha is driven from DQ05. The restart-brick is dead with it.

@Amperstrand
Amperstrand merged commit 8e7a2e5 into main Sep 22, 2026
Amperstrand added a commit that referenced this pull request Sep 22, 2026
#506 bumped the direct declarations (merchant, tollwallet, root) but
src/cli's indirect pin stayed v0.11.2, failing make go-battery at that
module. Tidied; cli battery green under race.

Co-authored-by: Amperstrand <amperstrand@localhost>
@Amperstrand

Copy link
Copy Markdown
Collaborator Author

Independent verification of the #480 fix on this branch — the restart discriminator, run live on an isolated 20-core runner (cloud lab, real cdk-mintd, real payments).

Note: the branch was retargeted overnight to gonuts v0.12.1 (serialized ReclaimUnspentProofs swap); this verification ran against that head (320896b, go.mod → v0.12.1).

The discriminator (exactly the #480 reproduction: fresh wallet seed → payment → plain docker restart tg-upstream → new token, new amount):

Step main (gonuts v0.11.2) this branch (v0.12.1)
pay 10 sats, fresh wallet VERDICT 10 OK VERDICT 10 OK
restart, pay 11 sats FAIL payment-processing-failed: could not swap proofs: Duplicate outputs VERDICT 11 OK
restart again, pay 12 sats (permanently broken — the #480 state) VERDICT 12 OK

On main, the first post-restart payment fails with the exact #480 error and (per the issue) never recovers; on this branch, payments survive two restarts with a wallet that has prior swap history at the fee mint. The alias-carrying mint condition is covered — the payments went through the fee-charging keysets (multi-keyset mint), which is the shape the canonical-bucket/counter-merge fixes target.

This confirms the release-gate claim: any alpha cut from current main bricks payment acceptance for every previously-used mint on the first service restart; with this bump, it does not. Evidence supports landing before the alpha4 cut.

(Scope note: this verifies the #480 restart class end-to-end. The #494/#495-class melt-reserve and swap-retry-range fixes are pinned by gonuts' own tests, not re-derived here; the PR's race-suite evidence for the two consuming modules stands as posted.)

@Amperstrand

Copy link
Copy Markdown
Collaborator Author

Post-merge live validation — the #480 reproducer lane, RED/GREEN A/B on the exact merged head (320896b vs main @61d65454):

Lane = the issue's own recipe: full topology up → fresh mint-fees token paid to the upstream (swap #1) → docker restart tg-upstream (same fs, same wallet seed) → two more payments with fresh tokens/amounts.

tree payment-1 pre-restart payment-2 post-restart payment-3 absorbing-check verdict
main @ 61d65454 (gonuts v0.11.2) 200 400 Duplicate outputs 400 (absorbing, as reported) #480 reproduced live
#506 @ 320896bd (gonuts v0.12.1) 200 200 200 fixed

Live failure line from the RED run's upstream log: PurchaseSession: Receive completed, amount=0, err=could not swap proofs: Duplicate outputs.

Static side, all on the merged head: go vet + go test -race -count=1 -tags testenv green in tollwallet (36s), merchant (221s), root (15s) — the three consuming modules.

Lane harness (pay_once.py fresh-wallet probe + restart_swap_lane.sh) preserved at ai-legion:/root/clab480{main,fix}/tests/cloud-lab/; full logs alongside (restart-swap-*.log, upstream-*.full.log).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant