diff --git a/package-lock.json b/package-lock.json index 5e1bd7a..b9cc268 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@sveltejs/adapter-static": "^3.0.1", "bitcoin-address-validation": "^2.2.3", "bits-ui": "^0.21.10", + "bloomfilter": "^0.0.18", "clsx": "^2.1.1", "cmdk-sv": "^0.0.17", "embla-carousel-svelte": "^8.1.3", @@ -42,6 +43,7 @@ "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", "@tailwindcss/typography": "^0.5.13", + "@types/bloomfilter": "^0.0.2", "@types/node": "^20.14.2", "autoprefixer": "^10.4.19", "flowbite": "^2.3.0", @@ -1525,6 +1527,12 @@ "tailwindcss": ">=3.0.0 || insiders" } }, + "node_modules/@types/bloomfilter": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@types/bloomfilter/-/bloomfilter-0.0.2.tgz", + "integrity": "sha512-XWY6sYrOqHMPVf2pwITSQ5ZQWjk2QSQibHcXPJtjuYGHkweOkcU8BbgWSYynWVFMjeS/OVhYCyR+V0puTNC/hQ==", + "dev": true + }, "node_modules/@types/chrome": { "version": "0.0.74", "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.74.tgz", @@ -1875,6 +1883,11 @@ "node": "^18 || >=20" } }, + "node_modules/bloomfilter": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/bloomfilter/-/bloomfilter-0.0.18.tgz", + "integrity": "sha512-CbnyHE78gY1tpXS/Ap+B0RJxKdRWCDzjBnX97UJSG8rdLv1PK8GiTWc/CCQyWu6PWVD4lUceeFrqC6Mf3nMgOA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/package.json b/package.json index 74c42f2..48287e2 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@sveltejs/kit": "^2.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0", "@tailwindcss/typography": "^0.5.13", + "@types/bloomfilter": "^0.0.2", "@types/node": "^20.14.2", "autoprefixer": "^10.4.19", "flowbite": "^2.3.0", @@ -48,6 +49,7 @@ "@sveltejs/adapter-static": "^3.0.1", "bitcoin-address-validation": "^2.2.3", "bits-ui": "^0.21.10", + "bloomfilter": "^0.0.18", "clsx": "^2.1.1", "cmdk-sv": "^0.0.17", "embla-carousel-svelte": "^8.1.3", diff --git a/src/lib/event_helpers/rockets.ts b/src/lib/event_helpers/rockets.ts index 9497096..da575f1 100644 --- a/src/lib/event_helpers/rockets.ts +++ b/src/lib/event_helpers/rockets.ts @@ -5,15 +5,36 @@ import validate from 'bitcoin-address-validation'; import { sha256 } from 'js-sha256'; import { MapOfVotes, MeritRequest, Votes } from './merits'; import * as immutable from 'immutable'; +import { BloomFilter } from 'bloomfilter'; export class Rocket { Event: NDKEvent; + private Bloom(): BloomFilter { + let b = new BloomFilter( + 64 * 256, // bits to allocate. + 32 // number of hashes + ); + let existing = this.Event.getMatchingTags('bloom'); + if (existing.length == 1) { + b = new BloomFilter(JSON.parse(existing[0][existing[0].length - 1]), 32); + } + return b; + } + private AppendEventToBloom(id: string) { + let existing = this.Bloom(); + existing.add(id); + this.Event.removeTag('bloom'); + this.Event.tags.push(['bloom', '32', JSON.stringify([].slice.call(existing.buckets))]); + } + Included(id: string): boolean { + return this.Bloom().test(id); + } UpsertBitcoinAssociation(association: BitcoinAssociation): NDKEvent | undefined { let event: NDKEvent | undefined = undefined; - if (association.Validate()) { + if (association.Validate() && association.Event && !this.Included(association.Event.id)) { let existing = this.BitcoinAssociations().get(association.Address!); if ((existing && existing.Pubkey != association.Pubkey) || !existing) { - this.PrepareForUpdate(); + this.PrepareForUpdate(association.Event.id); event = new NDKEvent(this.Event.ndk, this.Event.rawEvent()); event.created_at = Math.floor(new Date().getTime() / 1000); event.tags.push(['address', `${association.Pubkey}:${association.Address}`]); @@ -348,7 +369,7 @@ export class Rocket { return event; } UpsertProduct(id: string, price: number, maxSales?: number): NDKEvent { - this.PrepareForUpdate(); + this.PrepareForUpdate(id); let event = new NDKEvent(this.Event.ndk, this.Event.rawEvent()); event.created_at = Math.floor(new Date().getTime() / 1000); let existingProducts = this.CurrentProducts(); @@ -421,9 +442,12 @@ export class Rocket { } this.Event.tags = newTags; } - PrepareForUpdate() { + PrepareForUpdate(id?: string) { this.RemoveDuplicateTags(); this.RemoveProofs(); + if (id) { + this.AppendEventToBloom(id); + } this.Event.sig = undefined; } constructor(event: NDKEvent) {