Zum Hauptinhalt springen

Übersicht

LaserStream unterstützt die komprimierte Account-Filterung über Cuckoo-Filter. Anstatt in deinem subscribe request eine explizite Liste von pubkeys zu senden (32 Byte pro Account), sendest du einen kompakten probabilistischen Filter, der bei der Übertragung nur etwa 3–4 Byte pro Account benötigt. Damit kannst du Hunderttausende Accounts in einem einzigen stream abonnieren – ohne Sharding über mehrere Verbindungen und ohne übergroße subscribe requests. Ein Filter, der 500.000 Accounts verfolgt, wird beispielsweise auf etwa 2,1 MB serialisiert. Eine unkomprimierte Liste von pubkeys benötigt dagegen 16 MB – der Filter ist also ungefähr 7,6-mal kleiner. Die genaue Einsparung hängt vom Füllstand des Filters ab: Je näher er an seiner Kapazitätsgrenze liegt, desto weniger Byte werden pro Account benötigt.

Verfügbarkeit

Wann du Cuckoo-Filter verwenden solltest

Typische Anwendungsfälle sind die Überwachung aller Inhaber eines token, die Verfolgung aller Positionen in einem Kreditprotokoll oder die Überwachung großer Wallet-Gruppen für ein Handels- oder Analysesystem.

Funktionsweise

  1. Erstelle den Filter im Client. Füge jeden verfolgten pubkey in ein CompressedAccountFilterSet ein. Der Hash-Seed wird für jeden Filter zufällig generiert und zusammen mit ihm serialisiert. Dadurch hasht der Server eingehende Accounts mit demselben Seed, den dein Client verwendet hat.
  2. Hänge ihn an deinen subscribe request an. insert_into_subscribe_request() fügt den serialisierten Filter in den stream für Accounts eines standardmäßigen SubscribeRequest ein.
  3. Der Server sucht probabilistisch nach Übereinstimmungen. Da der Filter probabilistisch arbeitet, kann der Server Updates für Accounts liefern, die du nicht verfolgst. Diese False Positives liegen bei voller Auslastung garantiert unter 1 %. Es gibt keine False Negatives: Jedes Update für einen verfolgten Account wird zugestellt.
  4. Prüfe jedes Update lokal erneut – dieser Schritt ist erforderlich. Rufe set.contains(pubkey) für jeden eingehenden Account auf, bevor du ihn verarbeitest. Diese Prüfung ist exakt und basiert auf einem internen Hash-Set. Nach der lokalen Filterung gibt es daher keine False Positives.

Schnellstart (Rust)

Füge das SDK deinem Projekt hinzu:
Cargo.toml
Erstelle einen Filter, hänge ihn an ein Abonnement an und entferne False Positives lokal:
main.rs
Eine vollständige ausführbare Version ist im SDK enthalten: rust/examples/cuckoo_account_filter.rs.

Schnellstart (JavaScript/TypeScript)

Installiere das SDK (die Cuckoo-Unterstützung erfordert helius-laserstream ab Version 0.4.0):
Erstelle den Filter, hänge ihn an und prüfe jedes Update lokal erneut:
Eine vollständige ausführbare Version ist im SDK enthalten: javascript/examples/cuckoo-account-sub.ts.

API-Referenz

CompressedAccountFilterSet umschließt den Cuckoo-Rohfilter zusammen mit einem exakten Hash-Set. Dadurch sind Änderungen und Zugehörigkeitsprüfungen immer sicher und exakt: Die Methodennamen oben folgen den Rust-Konventionen. Das JavaScript/TypeScript SDK stellt dieselbe Oberfläche in camelCase bereit – new CompressedAccountFilterSet(capacity) statt with_capacity, insertIntoSubscribeRequest, isDirty, takeDirty, toProto und so weiter. In JavaScript gibt insert einen booleschen Wert zurück (true, wenn der Eintrag neu hinzugefügt wurde) und löst TableFullError aus, wenn der Filter voll ist. Du kannst einen pubkey als base58-String, als 32 Rohbytes oder als beliebiges Objekt mit einer toBytes()-Methode übergeben. Verwende immer CompressedAccountFilterSet statt des umschlossenen CuckooFilter-Rohfilters. remove() des Rohfilters kann unbemerkt das falsche Element entfernen – eine dokumentierte Fehlerquelle bei Cuckoo-Filtern. Der Wrapper kombiniert den Filter mit einem exakten Hash-Set. Dadurch sind Einfügen, Entfernen und Zugehörigkeitsprüfungen immer korrekt.

Kapazität festlegen

  • Lege die Filtergröße über with_capacity(n) anhand der maximalen Anzahl von Accounts fest, die du voraussichtlich verfolgen wirst.
  • Einfügen über die Kapazitätsgrenze hinaus schlägt kontrolliert mit TableFullError fehl – der Filter wird nie beschädigt. In der Praxis toleriert die Tabelle eine leichte Überfüllung, bevor sie Einfügungen ablehnt. Verlasse dich aber nicht auf diesen Spielraum.
  • Die serialisierte Größe hängt von der Kapazität ab, nicht von der Anzahl der bereits eingefügten Accounts. Ein überdimensionierter Filter verschwendet daher Byte bei der Übertragung. Wähle eine Kapazität, die nahe an deinem tatsächlichen Maximum liegt.

Verfolgte Menge aktualisieren

Wenn sich die verfolgte Menge ändert, weil du neuen Accounts folgen oder alte entfernen möchtest:
  1. Rufe insert() / remove() für CompressedAccountFilterSet auf.
  2. Prüfe mit is_dirty(), ob sich der Filter seit dem letzten Senden geändert hat. Alternativ kannst du das Flag mit take_dirty() abrufen und zurücksetzen.
  3. Wenn der Filter geändert wurde, erstelle den request mit insert_into_subscribe_request() neu. In JavaScript kannst du ihn mit stream.write(request) erneut über denselben stream senden. In Rust abonnierst du mit dem neu erstellten request erneut.

FAQ

Nein. Cuckoo-Filter erzeugen False Positives, also zusätzliche Updates für nicht verfolgte Accounts, aber keine False Negatives. Jedes Update für einen verfolgten Account wird zugestellt.
Bei voller Auslastung sind es weniger als 1 % und normalerweise noch weniger, wenn der Filter unter seiner Kapazitätsgrenze liegt. Ein lokaler Aufruf von contains() pro Update filtert sie exakt heraus.
Das Rust SDK (helius-laserstream ab Version 0.2.0), das JavaScript/TypeScript SDK (helius-laserstream ab Version 0.4.0) und der Yellowstone Rust-Client (yellowstone-grpc-client ab Version 13.1.0). Das Go SDK unterstützt Cuckoo-Filter noch nicht. Weitere Informationen findest du oben in der Verfügbarkeitstabelle.
Ja. Standardmäßige account: [...]-Filter funktionieren unverändert und sind für kleine Account-Mengen mit bis zu etwa 10.000 Accounts weiterhin die richtige Wahl. Weitere Informationen findest du im Leitfaden zu Account-Abonnements.
Ja. Wenn du einen komprimierten Filter an eine Transaktions-Subscription anhängst und matchMints: true festgelegt ist, prüft der Server neben den Account-Keys auch die Mints der Token-Balances vor und nach der Transaktion anhand des Filters. Siehe Token-Mint-Filterung.

Verwandte Themen

Account-Subscriptions

Standardmäßige Account-Filterung mit Filtern für Owner, Datengröße und memcmp.

Clients und SDKs

TypeScript-, Rust- und Go-SDKs mit automatischer Wiederholung und automatischem Neuverbinden.

Token-Mint-Filterung

Gleiche Transaktionen anhand des Token-Mints mit matchMints ab, auch innerhalb komprimierter Filter.