fix(channels/buzz): accept subscription without EOSE after auth

The Buzz relay authenticates via NIP-42 but does not send EndOfStoredEvents
after the second subscription. Waiting for EOSE caused a 15s timeout and
channel startup failure.

After auth, wait a short grace period (3s) for either EOSE or a rejection.
If neither arrives, the subscription was accepted — the relay simply doesn
not send EOSE, which is valid per NIP-01 (EOSE is optional for live-only
subscriptions).
This commit is contained in:
PeterChrz 2026-08-12 09:43:17 -04:00
parent 5acf91a136
commit 696d767fb4
Signed by untrusted user who does not match committer: pch
GPG key ID: 8F0826ECF7302C63

View file

@ -195,6 +195,12 @@ func (c *BuzzChannel) subscribeAuthed(
"pubkey": c.publicKey, "pubkey": c.publicKey,
}) })
// postAuthGrace is how long we wait after re-subscribing for either
// EOSE (relay sends end-of-stored-events) or a rejection. If neither
// arrives, the relay accepted the subscription but doesn't send EOSE —
// which is fine, we just start consuming events.
const postAuthGrace = 3 * time.Second
authed, err := c.relay.Subscribe(ctx, filters) authed, err := c.relay.Subscribe(ctx, filters)
if err != nil { if err != nil {
return nil, fmt.Errorf("buzz subscribe after auth failed: %w", err) return nil, fmt.Errorf("buzz subscribe after auth failed: %w", err)
@ -208,8 +214,14 @@ func (c *BuzzChannel) subscribeAuthed(
// A second rejection means the identity is not permitted, not that // A second rejection means the identity is not permitted, not that
// the handshake was mistimed — retrying would loop forever. // the handshake was mistimed — retrying would loop forever.
return nil, fmt.Errorf("buzz relay rejected subscription after auth: %s", reason) return nil, fmt.Errorf("buzz relay rejected subscription after auth: %s", reason)
case <-time.After(subscribeTimeout): case <-time.After(postAuthGrace):
return nil, fmt.Errorf("buzz timed out waiting for subscription after auth") // No EOSE and no rejection within the grace period — the relay
// accepted the subscription. Some relays (including Buzz) don't
// send EOSE after auth, so this is the expected success path.
logger.InfoCF("buzz", "Subscription accepted after auth (no EOSE)", map[string]any{
"relay": c.config.RelayURL,
})
return authed, nil
} }
case <-time.After(subscribeTimeout): case <-time.After(subscribeTimeout):