mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
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]>
66 lines
2.1 KiB
JavaScript
66 lines
2.1 KiB
JavaScript
// Regression: the live block-list subscription (ensureBlockListSubscription) used
|
|
// the user's full NIP-65 relay set, a primary contributor to the cold-login REQ
|
|
// storm. It must be bounded to the §17 read cap (capReadRelays, ≤8).
|
|
//
|
|
// Scenario (SCN-blocklist-subscription-relay-cap):
|
|
// Given a user with 20 read relays,
|
|
// When the live block-list subscription is (re)established,
|
|
// Then it subscribes over at most the §17-capped relay set, not all 20.
|
|
|
|
import "./test-helpers/setup-localstorage.mjs";
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { userBlocks } = await import("../js/userBlocks.js");
|
|
const { nostrClient } = await import("../js/nostrClientFacade.js");
|
|
const { capReadRelays, MAX_SUBSCRIBE_RELAYS } = await import(
|
|
"../js/nostr/toolkit.js"
|
|
);
|
|
|
|
if (typeof globalThis.window === "undefined") {
|
|
globalThis.window = {};
|
|
}
|
|
|
|
test("ensureBlockListSubscription caps the live subscription relay set", () => {
|
|
const actor = "f".repeat(64);
|
|
const manyRelays = Array.from(
|
|
{ length: 20 },
|
|
(_, i) => `wss://relay-${i}.example`,
|
|
);
|
|
|
|
const originalPool = nostrClient.pool;
|
|
const originalGetManager = nostrClient.getSubscriptionManager;
|
|
|
|
let captured = null;
|
|
try {
|
|
nostrClient.pool = { close() {} };
|
|
nostrClient.getSubscriptionManager = () => ({
|
|
subscribe: (args) => {
|
|
captured = args;
|
|
return { close() {} };
|
|
},
|
|
});
|
|
|
|
userBlocks.ensureBlockListSubscription(actor, manyRelays);
|
|
|
|
assert.ok(captured, "subscription manager should have been invoked");
|
|
const expected = capReadRelays(manyRelays);
|
|
assert.deepEqual(
|
|
captured.relays,
|
|
expected,
|
|
"live subscription must use the §17-capped relay set",
|
|
);
|
|
assert.ok(
|
|
captured.relays.length <= MAX_SUBSCRIBE_RELAYS,
|
|
`relay set must be capped to ${MAX_SUBSCRIBE_RELAYS}, got ${captured.relays.length}`,
|
|
);
|
|
assert.ok(
|
|
captured.relays.length < manyRelays.length,
|
|
"must not fan out across the full 20-relay NIP-65 set",
|
|
);
|
|
} finally {
|
|
nostrClient.pool = originalPool;
|
|
nostrClient.getSubscriptionManager = originalGetManager;
|
|
}
|
|
});
|