Keyset final_expiry silently kills held balances — wallets must rotate off inactive keysets (NUT-02)
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 28/100
Línea de trabajo
Start with tests/cloud-lab/run-keyset-rotation.sh and the related issues #409, #413, and #416 to understand the existing rotation and error-classification work. The issue proposes several separable directions, so confirm which one is in scope before starting; for the lifecycle monitor, inspect the keyset refresh and held-proof handling entry points. Done means the selected behavior is covered by tests, including the expired-keyset case.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Wallet hygiene: keyset final_expiry silently kills held balances — wallets must rotate off inactive keysets (NUT-02 SHOULD). Proven in the cloud lab.
What happened (lab evidence, #416): paying with proofs whose keyset was expired fails with "could not swap proofs: Keyset has expired" — the proofs are permanently unspendable at that mint. This is spec-correct mint behavior, not a bug: NUT-02 Keyset Final Expiry says that after final_expiry the mint "is no longer obliged to fulfill promises signed with the keys from that keyset" and may irrevocably delete the keyset's nullifiers. The spec even standardized the refusal: error code 12003 "Keyset has expired" (nuts PR #367). Implementations differ — cdk enforces expiry, nutshell never expires (nutshell #7, tracked in the cashu-audit divergence database) — and the spec's active flag conflates mintable vs redeemable, but none of that is ours to fix upstream.
Why it matters to TollGate: any wallet balance held across a keyset rotation+expiry window can be wiped:
- Reseller mode: the reseller holds balances at upstream mints (
min_balanceinaccepted_mints) between purchases — an upstream that rotates with expiry (cdk mints do) silently destroys that float. - Operator payouts: the merchant wallet holds received funds between payout cycles (
min_payout_amount,payout_interval_seconds); a fee-charging cdk-style mint rotating keysets mid-cycle destroys receivables. - Customers: a customer holding a token from an expired keyset gets a refusal — currently misclassified as
payment-error-mint-unreachable(see the note on #409), telling them to retry a permanently dead token.
Suggested work items (split-able):
- Keyset lifecycle monitor: on keyset refresh, detect
active=falsefor keysets with held proofs and proactively swap them to the active keyset (NUT-02: wallets SHOULD prioritize this; NUT-03 swap). React tofinal_expiryin the keyset response with an operator warning when held value is affected. - Classifier fix (already noted on #409): match "Keyset has expired" / code 12003 to a dedicated
payment-error-keyset-expirednotice instead of mint-unreachable, keeping the cause in the message. The pin intest_keyset_rotation.pyupdates consciously with it. - Advertisement/trust surface (product question): consider surfacing keyset-expiry policy (e.g. keysets with
final_expiryset) in mint metadata evaluation, so routers can prefer mints without expiry time bombs for float.
Repro: tests/cloud-lab/run-keyset-rotation.sh (phase A mints on a 100-ppk keyset; phase B expires it; the stashed token dies with 12003-class refusal).
Refs: #416 (rotation lane + pins), #409 (classifier), #413 (fee mint), cashu-audit issues/keyset-active-flag-semantics.md + divergences/CDK-VS-NUTSHELL-ALIGNMENT-2026-07-29.md ("#7 old keysets never expire"), nuts #367 (error 12003), NUT-02 §Keyset Final Expiry.
- Lenguaje dominante
- Go
- Estrellas
- 12
- Forks
- 14
- Merge medio
- 3 d 20 h
- PR fusionados (30 d)
- 261
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de OpenTollGate/tollgate-module-basic-go
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
OpenTollGate/tollgate-module-basic-go#1159 ·
Los mantenedores suelen responder en 1 día
-
Degraded-mode hygiene follow-ups: dead walletNotInitializedError() + main.go's startup log still over-promises mint recoveryPosiblemente ocupada @Amperstrand la tomó hace 1 día. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
OpenTollGate/tollgate-module-basic-go#1135 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
setup_uhttpd_portal hardcodes the GUEST portal docroot to the TollGate path — the brand token cannot select a re-brand guest portalPosiblemente ocupada @Amperstrand la tomó hace 2 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
OpenTollGate/tollgate-module-basic-go#1122 ·
Los mantenedores suelen responder en 1 día
-
changelog: dependency-security sweep missing from [Unreleased] [Amperstrand fork #105 review debt]Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
OpenTollGate/tollgate-module-basic-go#1055 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
OpenTollGate/tollgate-module-basic-go#1027 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de OpenTollGate/tollgate-module-basic-go
Issues similares
-
CLI: `describe <ns>.<table>` reports "namespace does not exist" when only the table is missingPosiblemente ocupada @Shruthirdy la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
apache/iceberg-go#2423 ·
Los mantenedores suelen responder en 2 días
-
post-v4
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 80/100
rishikanthc/Scriberr#506 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
microsoft/TypeScript#65290 ·
Los mantenedores suelen responder en 1 día
-
[Bug] rollingUpdatePartition panics when live StatefulSet replicas sit far below the desired countAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
sgl-project/rbg#547 ·
Los mantenedores suelen responder en 1 día