From 579589f6351d3753a2784c36904e4acac0ded43b Mon Sep 17 00:00:00 2001 From: Martti Malmi Date: Tue, 16 Jan 2024 13:23:57 +0200 Subject: [PATCH] nip-114: filter.ids_only, HAVE message --- packages/system/src/connection-pool.ts | 16 ++++++++++++++++ packages/system/src/connection.ts | 6 ++++++ packages/system/src/nips.ts | 1 + packages/system/src/nostr.ts | 2 +- packages/system/src/query.ts | 3 +++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/system/src/connection-pool.ts b/packages/system/src/connection-pool.ts index e7a6e9f8..5f551562 100644 --- a/packages/system/src/connection-pool.ts +++ b/packages/system/src/connection-pool.ts @@ -6,6 +6,7 @@ import { Connection, RelaySettings } from "./connection"; import { NostrEvent, OkResponse, TaggedNostrEvent } from "./nostr"; import { pickRelaysForReply } from "./outbox-model"; import { SystemInterface } from "."; +import LRUSet from "@snort/shared/src/LRUSet"; export interface NostrConnectionPoolEvents { connected: (address: string, wasReconnect: boolean) => void; @@ -38,6 +39,7 @@ export class DefaultConnectionPool extends EventEmitter(); + #requestedIds = new LRUSet(1000); constructor(system: SystemInterface) { super(); @@ -69,6 +71,20 @@ export class DefaultConnectionPool extends EventEmitter { + this.#log("%s have: %s %o", c.Address, s, id); + if (this.#requestedIds.has(id)) { + // already requested from this or another relay + return; + } + this.#requestedIds.add(id); + if (await this.#system.eventsCache.get(id)) { + // already have it locally + // TODO better local cache / db + return; + } + c.QueueReq(["REQ", "*", { ids: [id] }], () => {}); + }); c.on("eose", s => this.emit("eose", addr, s)); c.on("disconnect", code => this.emit("disconnect", addr, code)); c.on("connected", r => this.emit("connected", addr, r)); diff --git a/packages/system/src/connection.ts b/packages/system/src/connection.ts index bb6a1b8d..db38cb8e 100644 --- a/packages/system/src/connection.ts +++ b/packages/system/src/connection.ts @@ -28,6 +28,7 @@ interface ConnectionEvents { disconnect: (code: number) => void; auth: (challenge: string, relay: string, cb: (ev: NostrEvent) => void) => void; notice: (msg: string) => void; + have: (sub: string, ids: u256) => void; // NIP-114 unknownMessage: (obj: Array) => void; } @@ -210,6 +211,11 @@ export class Connection extends EventEmitter { // todo: stats events received break; } + // NIP-114: GetMatchingEventIds + case "HAVE": { + this.emit("have", msg[1] as string, msg[2] as u256); + break; + } case "EOSE": { this.emit("eose", msg[1] as string); break; diff --git a/packages/system/src/nips.ts b/packages/system/src/nips.ts index decdfa3c..6544cf3a 100644 --- a/packages/system/src/nips.ts +++ b/packages/system/src/nips.ts @@ -1,3 +1,4 @@ export enum Nips { Search = 50, + GetMatchingEventIds = 114, } diff --git a/packages/system/src/nostr.ts b/packages/system/src/nostr.ts index 66f2f9e2..764eba76 100644 --- a/packages/system/src/nostr.ts +++ b/packages/system/src/nostr.ts @@ -37,7 +37,7 @@ export type MaybeHexKey = HexKey | undefined; */ export type u256 = string; -export type ReqCommand = [cmd: "REQ", id: string, ...filters: Array]; +export type ReqCommand = [cmd: "REQ" | "IDS", id: string, ...filters: Array]; /** * Raw REQ filter object diff --git a/packages/system/src/query.ts b/packages/system/src/query.ts index 9cef059c..951b37e4 100644 --- a/packages/system/src/query.ts +++ b/packages/system/src/query.ts @@ -394,6 +394,9 @@ export class Query extends EventEmitter { #sendQueryInternal(c: Connection, q: BuiltRawReqFilter) { let filters = q.filters; + if (c.SupportsNip(Nips.GetMatchingEventIds)) { + filters = filters.map(f => ({ ...f, ids_only: true })); + } const qt = new QueryTrace(c.Address, filters, c.Id); qt.on("close", x => c.closeReq(x));