diff options
| author | Adam Soltys <[email protected]> | 2026-05-17 23:19:25 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-05-17 23:21:39 -0700 |
| commit | 3b7a1efaa1040de29d97640b371f24b41a6562a0 (patch) | |
| tree | 4ebdf9c9b5f17d1c5d23f8d2c48d9b5555721aeb | |
| parent | 609fcebe634b499c1133ea26f162c24e1c76d6d4 (diff) | |
| download | coinos-server-3b7a1efaa1040de29d97640b371f24b41a6562a0.tar.gz coinos-server-3b7a1efaa1040de29d97640b371f24b41a6562a0.zip | |
nwc: handle stale client state cleanly and skip reverted-duplicate records
Three small NWC robustness fixes that surfaced from the Apr 29
double-credit cleanup:
- fail loudly when an NWC request references a pubkey whose user record
no longer exists (migrated/deleted account); previously crashed inside
handle() on `user.id`
- swallow `pubkey not found` and `user not found` in the per-event catch
so deleted-app/migrated-user spam doesn't fill the error log — these
are client-side staleness, not server faults
- use gf() instead of g() when fetching payment records (consistent with
the rest of the codebase: arc fallback for wiped main-db pointers)
- filter `revertedDuplicate` payments out of list_transactions so
clients never see the doubled records that were later reverted
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
| -rw-r--r-- | lib/nwc.ts | 6 |
1 files changed, 5 insertions, 1 deletions
@@ -147,6 +147,7 @@ export default () => { const app = await g(`app:${pubkey}`); if (!app) fail("pubkey not found"); const user = await g(`user:${app.uid}`); + if (!user) fail("user not found"); const result = await handle(method, params, ev, app, user); const payload = JSON.stringify({ result_type: method, ...result }); @@ -166,6 +167,8 @@ export default () => { response = await finalizeEvent(response, hexToBytes(sk)); r.send(["EVENT", response]); } catch (e) { + // Stale client state (deleted app or migrated user) is not a server fault — don't log. + if (e.message === "pubkey not found" || e.message === "user not found") return; err("problem with nwc", pubkey, method, e.message); } } catch (e) { @@ -195,7 +198,7 @@ const handle = (method, params, ev, app, user) => }; const pids = await db.lRange(`${pubkey}:payments`, 0, -1); - let payments = await Promise.all(pids.map((pid) => g(`payment:${pid}`))); + let payments = await Promise.all(pids.map((pid) => gf(`payment:${pid}`))); payments = payments.filter( (p) => p?.created > Date.now() - periods[budget_renewal], ); @@ -455,6 +458,7 @@ const handle = (method, params, ev, app, user) => for (const pid of payments) { const p = await gf(`payment:${pid}`); if (!p) continue; + if (p.revertedDuplicate) continue; const created_at = Math.floor(p.created / 1000); if (created_at < from || created_at > until) continue; if (p.amount < 0 && type === "incoming") continue; |
