Skip to main content

Overview

LaserStream supports compressed account filtering via cuckoo filters. Instead of sending an explicit pubkey list in your subscribe request (32 bytes per account), you send a compact probabilistic filter that costs roughly 3–4 bytes per account on the wire. This makes it practical to subscribe to hundreds of thousands of accounts in a single stream — no sharding across connections, no oversized subscribe requests. For example, a filter tracking 500,000 accounts serializes to about 2.1 MB, versus 16 MB as a raw pubkey list — roughly 7.6x smaller. The exact savings depend on how full the filter is: the closer it is to capacity, the fewer bytes per account.

Availability

When to use cuckoo filters

Typical use cases: monitoring every holder of a token, tracking all positions in a lending protocol, or watching large wallet sets for a trading or analytics system.

How it works

  1. Build the filter client-side. Insert each tracked pubkey into a CompressedAccountFilterSet. The hash seed is randomized per filter and serialized alongside it, so the server hashes incoming accounts with the same seed your client used.
  2. Attach it to your subscribe request. insert_into_subscribe_request() places the serialized filter into the accounts stream of a standard SubscribeRequest.
  3. The server matches probabilistically. Because the filter is probabilistic, the server may deliver updates for accounts you didn’t track — false positives are bounded at under 1% at full load. There are never false negatives: every update for a tracked account is delivered.
  4. Re-check each update locally — this step is required. Call set.contains(pubkey) on every incoming account before processing it. This check is exact (backed by an internal hash set), so after local filtering you see zero false positives.

Quickstart (Rust)

Add the SDK to your project:
Cargo.toml
Build a filter, attach it to a subscription, and scrub false positives locally:
main.rs
A complete runnable version ships with the SDK: rust/examples/cuckoo_account_filter.rs.

Quickstart (JavaScript/TypeScript)

Install the SDK (cuckoo support requires helius-laserstream 0.4.0+):
Build the filter, attach it, and re-check each update locally:
A complete runnable version ships with the SDK: javascript/examples/cuckoo-account-sub.ts.

API reference

CompressedAccountFilterSet wraps the raw cuckoo filter together with an exact hash set, so mutations and membership checks are always safe and exact: Method names above use Rust conventions. The JavaScript/TypeScript SDK exposes the same surface in camelCase — new CompressedAccountFilterSet(capacity) instead of with_capacity, insertIntoSubscribeRequest, isDirty, takeDirty, toProto, and so on. In JavaScript insert returns a boolean (true if newly added) and throws TableFullError when the filter is saturated. A pubkey can be passed as a base58 string, raw 32 bytes, or any object with a toBytes() method. Always use CompressedAccountFilterSet rather than the raw CuckooFilter it wraps. The raw filter’s remove() can silently remove the wrong item — a documented footgun of cuckoo filters. The wrapper pairs the filter with an exact hash set, so insert, remove, and contains are always correct.

Capacity sizing

  • Size the filter for the peak number of accounts you expect to track via with_capacity(n).
  • Inserting beyond capacity fails gracefully with a TableFullError — the filter is never corrupted. In practice the table tolerates slight overfill before rejecting inserts, but don’t rely on that headroom.
  • The serialized size is determined by capacity, not by how many accounts you’ve inserted — so an oversized filter wastes wire bytes. Pick a capacity close to your real peak.

Updating the tracked set

When your tracked set changes (new accounts to follow, old ones to drop):
  1. Call insert() / remove() on the CompressedAccountFilterSet.
  2. Check is_dirty() (or consume the flag with take_dirty()) to see whether the filter changed since it was last sent.
  3. If dirty, rebuild the request with insert_into_subscribe_request(). In JavaScript you can re-send it on the same stream with stream.write(request); in Rust, resubscribe with the rebuilt request.

FAQ

No. Cuckoo filters produce false positives (extra updates for untracked accounts) but never false negatives. Every update for a tracked account is delivered.
Under 1% at full load, and typically less when the filter is below capacity. One local contains() call per update filters them out exactly.
The Rust SDK (helius-laserstream 0.2.0+), the JavaScript/TypeScript SDK (helius-laserstream 0.4.0+), and the Yellowstone Rust client (yellowstone-grpc-client 13.1.0+). The Go SDK does not support it yet. See the availability table above.
Yes. Standard account: [...] filters work unchanged and remain the right choice for small account sets (up to roughly 10,000 accounts). See the account subscription guide.

Account Subscriptions

Standard account filtering with owner, datasize, and memcmp filters.

Clients & SDKs

TypeScript, Rust, and Go SDKs with automatic replay and reconnects.