fix(backend): pin per-key kind:24133 subscription to explicit relays (#21) #23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-21-pin-backend-sub-to-explicit-relays"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Closes #21. Fix the second half of the bunker-side regression diagnosed in the 2026-06-03 debug session (companion to PR #22 / #20).
Backend.start()callsthis.ndk.subscribe(filter, opts)to listen for NIP-46 events targeted at each unlocked key's pubkey (kind:24133 with#p=[localUser.pubkey]). Pre-fix the subscription opts didn't pin a relay set, so NDK 3.x's outbox routing took over: it looked up thelocalUser.pubkey's NIP-65 relay list (kind:10002) to decide where to send the REQ. Newly-provisioned bunker keys have no kind:10002 published yet, so NDK's subscription manager queued the REQ waiting for a relay list that would never arrive — the subscription never landed on the wire.User-visible symptom: every NIP-46 RPC from lnbits to a freshly-provisioned key (
connect,get_public_key,sign_event, thenip04_*/nip44_*family) was published into the relay, the relay tried to route, found no subscribed peer matching["p", new_key_pubkey], and emittedFilter didn't match. The lnbits-side RPC then timed out at 15s, breaking eager merchant provisioning (aiolabs/lnbits#46) and satmachineadmin's per-cassettenip44_decryptpolling.Diagnosis
Reproduced + confirmed by patching the lnbits
nostrrelayextension's_handle_requestto log every incoming REQ filter. After a signup:AdminInterface.connect()(admin/index.ts:145) appeared on the wire:Backend.start()for the newly-provisioned key did not appear at all.So the AdminInterface's subscription (which has the admin signer's pubkey, and the daemon has explicit relays configured for it) was reaching the wire; the per-key Backend's subscription (using the same
this.ndkinstance, with#ppointing at a key whose outbox is unresolved) was not.Fix
Pass
relayUrls: this.ndk.explicitRelayUrlsin the subscription opts.relayUrlswas added in NDK 2.13.0 as the supported way to bypass outbox routing per subscription. The relay set built from these URLs matches what the rest of the daemon uses (admin RPC channel + every per-key Backend channel alike), so events flow through the same connection the AdminInterface already established.Test plan
Verified on the regtest dev stack with bunker enabled, fresh signup that provisions a new key + immediately publishes a kind:30017 stall via NIP-46
sign_event:POST /api/v1/auth/register→HTTP 200in 1.1 s (pre-fix: hung at 15 s withNsecBunkerTimeoutError: no NIP-46 response for 'sign_event').stalls.event_idpopulated inext_nostrmarket.sqlite3:8a2eb20b929…— proves the bunker signed and returned the event to lnbits.pnpm run buildclean.Notes
#pfilter for a pubkey whose outbox is unresolved — the AdminInterface's NDK has the admin signer set, so outbox resolution doesn't fire the same blocking lookup. But applyingrelayUrlsto the admin sub too would be a small additional belt-and-suspenders if a future NDK version changes that behavior; out of scope here.DEFAULT_POLICY_RULESNIP-15 kind fix landed in aiolabs/lnbits#48. The nostrmarket publish-without-timeout fix landed in aiolabs/nostrmarket#8.🤖 Generated with Claude Code