From 8d4dfedd68b1dcc66ff3af9aa237a7b4e85c17ed Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Jul 2026 13:44:23 +0000 Subject: [PATCH] perf(cli): skip duplicate events before verify in the gated drain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The outbox model — and especially the wide relay-list broadcast — delivers the same event from many relays at once, and the gated drain ran a Schnorr verify (and a store insert) on every copy before the store's UNIQUE constraint dropped it. On a fan-out that asks hundreds of relays for the same kind:10002s, that is hundreds of redundant verifications per event and pegged a core. Add a per-drain SeenIds skip-before-verify to the consumer, mirroring drainAllPages: an id is marked seen only after it verifies, so a forged copy (valid id, bad signature) delivered first can't suppress the genuine one. Cuts the redundant verification across the whole crawl, not just the wide sweep. --- .../com/vitorpamplona/amethyst/cli/Context.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Context.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Context.kt index d5b5326dcd..759b8f37b0 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Context.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/Context.kt @@ -680,11 +680,22 @@ class Context( } val collected = mutableListOf>() coroutineScope { - // Single consumer: verify+store serially, exactly like drain(). + // Single consumer: verify+store serially, exactly like drain(). One + // writer, so SeenIds' single-writer contract holds. The outbox model + // (and especially the wide relay-list broadcast) delivers the SAME event + // from many relays at once; skip a duplicate BEFORE the expensive + // Schnorr verify+store. An id is marked seen only after it verifies, so a + // forged copy (valid id, bad signature) delivered first can't suppress + // the genuine one that follows. val consumer = launch { + val seen = SeenIds(initialSlotsPow2 = 12) for ((relay, event) in eventChannel) { - if (verifyAndStore(event)) collected.add(relay to event) + if (seen.contains(event.id)) continue + if (verifyAndStore(event)) { + seen.add(event.id) + collected.add(relay to event) + } } } // One gated subscription per relay. The permit is held for the whole