tinyrelayfile
tinyrelay/scripts/conformance/nip45.test.ts/

scripts/conformance/nip45.test.ts raw
1import { describe, it, expect } from "vitest";
2import { newEvent, newKey, pub, now, randHex, sockets } from "./helpers.ts";
3
4const connect = sockets();
5
6describe("NIP-45 COUNT", () => {
7 it("counts across OR'd filters without double counting, and adds an hll sketch for tag filters", async () => {
8 const sk = newKey();
9 const c = await connect();
10 const target = randHex();
11 for (let i = 0; i < 3; i++) await c.publish(newEvent(sk, 1, "n", [["t", target]], now() - 10 + i));
12 await c.publish(newEvent(sk, 7, "+", [["e", target]], now() - 5));
13
14 c.send("COUNT", "n", { kinds: [1], authors: [pub(sk)] }, { kinds: [7], authors: [pub(sk)] });
15 expect((await c.expect("COUNT"))[2].count).toBe(4);
16 c.send("COUNT", "n", { kinds: [1], authors: [pub(sk)] }, { "#t": [target], authors: [pub(sk)] });
17 expect((await c.expect("COUNT"))[2].count).toBe(3);
18
19 c.send("COUNT", "r", { kinds: [7], "#e": [target] });
20 const res = (await c.expect("COUNT"))[2];
21 expect(res.count).toBe(1);
22 expect(res.hll).toMatch(/^[0-9a-f]{512}$/);
23 // Register: offset = nibble 32 of the target + 8; byte[offset] indexes,
24 // zero run after it plus one is the value.
25 const offset = parseInt(target[32], 16) + 8;
26 const pk = pub(sk);
27 const regIndex = parseInt(pk.substr(offset * 2, 2), 16);
28 const rest = pk.slice((offset + 1) * 2);
29 let zeros = 0;
30 for (const ch of rest) {
31 const n = parseInt(ch, 16);
32 if (n === 0) {
33 zeros += 4;
34 continue;
35 }
36 zeros += Math.clz32(n) - 28;
37 break;
38 }
39 expect(parseInt(res.hll.substr(regIndex * 2, 2), 16)).toBe(zeros + 1);
40 });
41});

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs