lists: cap login list subscriptions to the §17 read set (≤8)

The cold-login REQ storm came from list subsystems subscribing/fetching across
the user's full NIP-65 relay set (often ~20) instead of the documented §17 read
cap. The fetchListIncrementally paths already route through capReadRelays, but
the live subscriptions and direct pool.list calls bypassed it:

- userBlocks.ensureBlockListSubscription: cap the live block-list subscription
- subscriptions.ensureSubscriptionListSubscription: cap the live follows-list
  subscription
- hashtagPreferencesService: cap the relay set used by pool.list + fetch

capReadRelays keeps the user's own relays first and guarantees the reserved
defaults, bounded to MAX_SUBSCRIBE_RELAYS (8). Trade-off accepted: a list event
living only on a user's 9th+ relay may sync on a later pass rather than at login.

Regression: tests/user-blocks-relay-cap.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-24 07:07:57 -04:00
1 parent 7f6a0f3adf
commit 2c62b959fd
4 files changed
+85 -8

No files matched your search

+9 -3
View File
@@ -27,7 +27,7 @@ import {
assertAnyRelayAccepted,
} from "./nostrPublish.js";
import { profileCache } from "./state/profileCache.js";
import { DEFAULT_RELAY_URLS } from "./nostr/toolkit.js";
import { DEFAULT_RELAY_URLS, capReadRelays } from "./nostr/toolkit.js";
import { relayManager } from "./relayManager.js";
import {
DEFAULT_NIP07_ENCRYPTION_METHODS,
@@ -741,6 +741,12 @@ class UserBlockListManager {
return null;
}
// Bound the live block-list subscription to the §17 read cap (user relays
// first + reserved defaults, ≤8). Without this the subscription fanned out
// across the user's full NIP-65 set, a primary contributor to the cold-login
// REQ storm.
const cappedRelays = capReadRelays(relays);
const key = `block-list:${normalized}`;
this.blockListSubscriptionKey = key;
@@ -758,7 +764,7 @@ class UserBlockListManager {
if (manager) {
this.blockListSubscriptionHandle = manager.subscribe({
key,
relays,
relays: cappedRelays,
filters,
label: "block-list",
onEvent: (event) => this.handleBlockListEvent(event),
@@ -769,7 +775,7 @@ class UserBlockListManager {
return relaySubscriptionService.ensureSubscription({
key,
pool: nostrClient.pool,
relays,
relays: cappedRelays,
filters,
label: "block-list",
onEvent: (event) => this.handleBlockListEvent(event),