import { schnorr } from "@noble/curves/secp256k1.js" import { hexToBytes } from "@noble/hashes/utils.js" import { EventExt } from "../event-ext" import type { NostrEvent, ReqFilter } from "../nostr" import { expandFilter } from "./request-expander" import { flatMerge, mergeSimilar } from "./request-merger" import { diffFilters } from "./request-splitter" export interface FlatReqFilter { keys: number ids?: string authors?: string kinds?: number "#e"?: string "#p"?: string "#t"?: string "#d"?: string "#r"?: string search?: string since?: number until?: number limit?: number relay?: string resultSetId: string } export interface Optimizer { expandFilter(f: ReqFilter): Array getDiff(prev: Array, next: Array): Array flatMerge(all: Array): Array compress(all: Array): Array schnorrVerify(ev: NostrEvent): boolean batchVerify(evs: Array): Array } export const DefaultOptimizer = { expandFilter: (f: ReqFilter) => { return expandFilter(f) }, getDiff: (prev: Array, next: Array) => { const diff = diffFilters( prev.flatMap(a => expandFilter(a)), next.flatMap(a => expandFilter(a)), ) return diff.added }, flatMerge: (all: Array) => { return flatMerge(all) }, compress: (all: Array) => { return mergeSimilar(all) }, schnorrVerify: ev => { // Fast path: already verified (e.g. came through EventExt.verify earlier) if (EventExt.isVerified(ev)) return true const id = EventExt.createId(ev) const ok = schnorr.verify(hexToBytes(ev.sig), hexToBytes(id), hexToBytes(ev.pubkey)) if (ok) EventExt.markVerified(ev) return ok }, batchVerify: evs => { return evs.map(ev => { if (EventExt.isVerified(ev)) return true const id = EventExt.createId(ev) const ok = schnorr.verify(hexToBytes(ev.sig), hexToBytes(id), hexToBytes(ev.pubkey)) if (ok) EventExt.markVerified(ev) return ok }) }, } as Optimizer