block / block/buzz

Relay live fan-out: closed sub IDs poisoned, multi-#h filters never push, replace/close tears down overlapping delivery

Open
#3,019 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

Setup: self-hosted compose stack (relay + postgres + redis), NIP-42 auth enabled,
kind-9 chat in NIP-29-style channels (`h` tag). All three behaviors reproduced
with minimal WebSocket clients doing side-by-side A/B subscriptions on one
authed connection; event ingest, Postgres storage, Redis publish (verified via
`redis-cli psubscribe 'buzz:*'`), and REQ backlog all work throughout — only
live push to subscribers misbehaves, which makes every one of these silent.

**1. A REQ reusing a sub ID that was CLOSED earlier on the same connection is
silently ignored.** Practical impact: the natural client pattern of
"subscribe → relay CLOSEs with `auth-required` → AUTH → re-subscribe with the
same IDs" yields an authenticated connection with zero live subscriptions and
no error. Repro: REQ `sub-a` pre-auth (gets CLOSED `auth-required`), AUTH OK,
REQ `sub-a` again, publish a matching event from another client → no EVENT
delivered on `sub-a`; identical flow with a fresh ID `sub-b` delivers.

**2. Live fan-out only delivers on single-channel `#h` filters.** A
`{"kinds":[9],"#h":[]}` sub receives pushes; the identical sub with 2+
ids in `#h` (or a bare `{"kinds":[9]}`) serves stored backlog on REQ but never
receives a push. Repro: same connection, `scoped-one` (`#h` with 1 id) and
`scoped-many` (`#h` with 7 ids incl. the same one), publish into that channel →
only `scoped-one` gets the EVENT.

**3. Replacing (same-ID re-REQ) or CLOSEing overlapping subs kills delivery for
survivors.** Re-sending a REQ on an active ID to widen its filter stops
delivery entirely; CLOSE of an old sub whose channels overlap a newer sub's
also stops the newer sub receiving (looks like topic refcounting keyed by
channel rather than by (sub, channel)). Repro: create scoped sub v1, CLOSE it,
create scoped sub v2 covering the same channel, publish → v2 receives nothing.

Client-side workaround that works reliably: one never-reused, never-replaced,
never-CLOSEd subscription per channel, with connection-unique IDs, created only
after AUTH completes.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.