> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Groß angelegte Kontofilterung mit komprimierten Filtern

> Abonnieren Sie Hunderttausende von Solana-Konten in einem LaserStream gRPC-Stream mit komprimierten Cuckoo-Filtern — ca. 8x kleinere Abonnementsanfragen.

## Übersicht

LaserStream unterstützt **komprimierte Kontofilterung über Cuckoo-Filter**. Anstatt eine explizite Pubkey-Liste in Ihrer Abonnementanfrage zu senden (32 Bytes pro Konto), senden Sie einen kompakten probabilistischen Filter, der auf der Leitung ungefähr **3–4 Bytes pro Konto** kostet.

Dies macht es praktikabel, **Hunderttausende von Konten in einem Stream** zu abonnieren — kein Sharding über Verbindungen, keine übergroßen Abonnementanfragen.

Ein Beispiel: Ein Filter, der 500.000 Konten verfolgt, serialisiert sich auf etwa 2,1 MB, im Vergleich zu 16 MB als rohe Pubkey-Liste — ungefähr **7,6x kleiner**. Die genauen Einsparungen hängen davon ab, wie voll der Filter ist: Je näher er an der Kapazität ist, desto weniger Bytes pro Konto.

### Verfügbarkeit

| Client                                                         | Mindestversion | Cuckoo-Support |
| -------------------------------------------------------------- | -------------- | -------------- |
| LaserStream SDK — Rust (`helius-laserstream`)                  | 0.2.0          | ✅              |
| LaserStream SDK — JavaScript/TypeScript (`helius-laserstream`) | 0.4.0          | ✅              |
| LaserStream SDK — Go                                           | —              | ❌ Noch nicht   |
| Yellowstone gRPC — Rust (`yellowstone-grpc-client`)            | 13.1.0         | ✅              |

## Wann man Cuckoo-Filter verwendet

| Verfolgt Konten   | Empfohlener Ansatz                                             |
| ----------------- | -------------------------------------------------------------- |
| Bis zu \~10.000   | Explizite Pubkey-Listen (`account: [...]`) — einfach und exakt |
| \~10.000 und mehr | Cuckoo-Filter über `CompressedAccountFilterSet`                |

Typische Anwendungsfälle: Überwachung jedes Besitzers eines Tokens, Verfolgung aller Positionen in einem Kreditprotokoll oder Beobachtung großer Wallet-Sätze für ein Handels- oder Analysesystem.

## So funktioniert es

1. **Erstellen Sie den Filter clientseitig.** Fügen Sie jeden verfolgten Pubkey in einen `CompressedAccountFilterSet` ein. Der Hash-Seed wird pro Filter zufällig erstellt und zusammen mit ihm serialisiert, sodass der Server eingehende Konten mit demselben Seed hasht, den Ihr Client verwendet hat.
2. **Fügen Sie ihn Ihrer Abonnementanfrage hinzu.** `insert_into_subscribe_request()` platziert den serialisierten Filter in den Kontenstream eines Standards `SubscribeRequest`.
3. **Der Server gleicht probabilistisch ab.** Da der Filter probabilistisch ist, kann der Server Updates für Konten liefern, die Sie nicht verfolgt haben — falsch positive Ergebnisse liegen bei **unter 1% bei voller Auslastung**. Es gibt **nie falsch negative**: Jede Aktualisierung für ein verfolgtes Konto wird geliefert.
4. **Jedes Update lokal erneut überprüfen — dieser Schritt ist erforderlich.** Rufen Sie `set.contains(pubkey)` für jedes eingehende Konto auf, bevor Sie es verarbeiten. Diese Überprüfung ist exakt (gestützt auf einen internen Hash-Satz), sodass Sie nach der lokalen Filterung keine falsch positiven Ergebnisse sehen.

## Schnellstart (Rust)

Fügen Sie das SDK Ihrem Projekt hinzu:

```toml Cargo.toml theme={"system"}
[dependencies]
helius-laserstream = "0.2"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
```

Erstellen Sie einen Filter, fügen Sie ihn einem Abonnement hinzu und reinigen Sie falsch positive lokal:

```rust main.rs [expandable] theme={"system"}
use {
    futures::StreamExt,
    helius_laserstream::{
        cuckoo::{CompressedAccountFilterSet, Pubkey},
        grpc::{subscribe_update::UpdateOneof, SubscribeRequest},
        subscribe, LaserstreamConfig,
    },
    std::str::FromStr,
};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // The exact set of accounts you care about. In production this is
    // typically loaded from your database — hundreds of thousands of keys.
    let tracked: Vec<Pubkey> = [
        "So11111111111111111111111111111111111111112", // Wrapped SOL
        "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
        "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // USDT
    ]
    .iter()
    .map(|s| Pubkey::from_str(s).unwrap())
    .collect();

    // Build the cuckoo filter. Size it for your peak tracked-set size.
    let mut set = CompressedAccountFilterSet::with_capacity(500_000)?;
    for pk in &tracked {
        set.insert(*pk)?;
    }
    println!(
        "Tracking {} accounts via cuckoo filter ({} bytes on the wire)",
        set.len(),
        set.to_proto().data.len()
    );

    // Attach the compressed filter to the accounts stream.
    let mut request = SubscribeRequest::default();
    set.insert_into_subscribe_request(&mut request, "tracked_accounts");

    let config = LaserstreamConfig::new(
        "https://laserstream-mainnet-ewr.helius-rpc.com".to_string(), // Choose your closest region
        "YOUR_API_KEY".to_string(), // Replace with your key from https://dashboard.helius.dev/
    );

    let (stream, _handle) = subscribe(config, request);
    tokio::pin!(stream);
    while let Some(message) = stream.next().await {
        match message {
            Ok(update) => {
                if let Some(UpdateOneof::Account(account_update)) = update.update_oneof {
                    if let Some(info) = account_update.account {
                        let pk = Pubkey::try_from(info.pubkey.as_slice()).ok();
                        // Re-check locally: drop server-side false positives.
                        match pk {
                            Some(pk) if set.contains(pk) => {
                                println!(
                                    "tracked account update: {pk} (slot {})",
                                    account_update.slot
                                );
                            }
                            Some(pk) => {
                                println!("(false positive, ignored): {pk}");
                            }
                            None => {}
                        }
                    }
                }
            }
            Err(e) => eprintln!("stream error: {e}"),
        }
    }

    Ok(())
}
```

Eine komplette ausführbare Version wird mit dem SDK geliefert: [`rust/examples/cuckoo_account_filter.rs`](https://github.com/helius-labs/laserstream-sdk/blob/main/rust/examples/cuckoo_account_filter.rs).

## Schnellstart (JavaScript/TypeScript)

Installieren Sie das SDK (Cuckoo-Unterstützung erfordert `helius-laserstream` 0.4.0+):

```bash theme={"system"}
npm install helius-laserstream
```

Erstellen Sie den Filter, fügen Sie ihn hinzu, und überprüfen Sie jedes Update lokal erneut:

```typescript [expandable] theme={"system"}
import {
  subscribe,
  CommitmentLevel,
  CompressedAccountFilterSet,
  SubscribeUpdate,
  LaserstreamConfig,
} from 'helius-laserstream';

async function main() {
  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY', // Replace with your key from https://dashboard.helius.dev/
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // Choose your closest region
  };

  // The accounts you want to track. In production this is typically loaded
  // from your database — hundreds of thousands of keys.
  const addresses = [
    'So11111111111111111111111111111111111111112', // Wrapped SOL
    'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
    'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', // USDT
  ];

  // Build a compact cuckoo filter instead of sending the full pubkey list.
  // Size capacity for your peak tracked-set size.
  const tracked = new CompressedAccountFilterSet(500_000);
  for (const address of addresses) {
    tracked.insert(address);
  }

  // Attach the filter to the request (no explicit account list needed).
  const request: any = { accounts: {}, commitment: CommitmentLevel.CONFIRMED };
  tracked.insertIntoSubscribeRequest(request, 'tracked-accounts');

  const stream = await subscribe(
    config,
    request,
    async (update: SubscribeUpdate) => {
      const pubkey = update.account?.account?.pubkey;
      if (!pubkey) return;
      // Re-check locally: drop server-side false positives. This is exact.
      if (tracked.contains(pubkey)) {
        console.log('tracked account update:', update.account);
      }
    },
    (error: Error) => {
      console.error('Stream error:', error);
    }
  );

  process.on('SIGINT', () => {
    stream.cancel();
    process.exit(0);
  });
}

main().catch(console.error);
```

Eine komplette ausführbare Version wird mit dem SDK geliefert: [`javascript/examples/cuckoo-account-sub.ts`](https://github.com/helius-labs/laserstream-sdk/blob/main/javascript/examples/cuckoo-account-sub.ts).

## API-Referenz

`CompressedAccountFilterSet` umhüllt den rohen Cuckoo-Filter zusammen mit einem exakten Hash-Satz, sodass Mutationen und Mitgliedschaftsprüfungen immer sicher und exakt sind:

| Methode                                                | Verhalten                                                                                                             |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `with_capacity(n)`                                     | Erstellen Sie einen Filter, der auf `n` verfolgte Konten ausgelegt ist. Größe für Ihre **Spitzen**-Verfolgungsgrößen. |
| `insert(pubkey)`                                       | Gibt `Ok(true)` zurück, wenn neu, `Ok(false)` bei Duplikaten, `Err(TableFullError)`, wenn der Filter voll ist.        |
| `remove(pubkey)`                                       | Entfernt das Konto. Sicher und exakt.                                                                                 |
| `contains(pubkey)`                                     | Exakte Mitgliedschaftsprüfung — verwenden Sie dies, um serverseitige falsch positive Ergebnisse zu bereinigen.        |
| `insert_into_subscribe_request(&mut request, "label")` | Fügen Sie den Filter dem Kontenstream eines `SubscribeRequest` hinzu.                                                 |
| `to_account_filter()` / `to_proto()`                   | Niedrigere Konvertierungen für benutzerdefinierte Anforderungszusammenstellungen.                                     |
| `is_dirty()` / `take_dirty()`                          | Berichten Sie, ob sich das Set seit der letzten Anfrage geändert hat — nützlich für Wiederabonnement-Zyklen.          |

Methodennamen verwenden die Rust-Konventionen. Das JavaScript/TypeScript SDK bietet dieselbe Oberfläche in camelCase — `new CompressedAccountFilterSet(capacity)` anstelle von `with_capacity`, `insertIntoSubscribeRequest`, `isDirty`, `takeDirty`, `toProto` usw. In JavaScript gibt `insert` einen boolean zurück (`true` wenn neu hinzugefügt) und wirft `TableFullError`, wenn der Filter gesättigt ist. Ein Pubkey kann als Base58-String, Roh-32-Bytes oder jedes Objekt mit einer `toBytes()`-Methode übergeben werden.

Verwenden Sie immer `CompressedAccountFilterSet` anstelle des rohen `CuckooFilter`, den er umhüllt. Die rohe Filterfunktion `remove()` kann stillschweigend das falsche Element entfernen — eine dokumentierte Fehlerquelle von Cuckoo-Filtern. Der Wrapper kombiniert den Filter mit einem exakten Hash-Satz, sodass Einfügen, Entfernen und Enthalten immer korrekt sind.

## Kapazitätsgrößenbestimmung

* Bemessen Sie den Filter für die **Spitzen**anzahl von Konten, die Sie über `with_capacity(n)` verfolgen möchten.
* Das Einfügen über die Kapazität hinaus schlägt mit einer `TableFullError` fehl — der Filter wird nie beschädigt. In der Praxis toleriert die Tabelle eine leichte Überfüllung, bevor sie Einfügungen ablehnt, aber verlassen Sie sich nicht auf diesen Spielraum.
* Die serialisierte Größe wird durch die Kapazität bestimmt, nicht durch die Anzahl der eingefügten Konten — ein überdimensionaler Filter verschwendet also Bytes auf der Leitung. Wählen Sie eine Kapazität, die nahe an Ihrem tatsächlichen Spitzenwert liegt.

## Aktualisierung des verfolgten Sets

Wenn sich Ihr verfolgtes Set ändert (neue Konten zum Folgen, alte zum Entfernen):

1. Rufen Sie `insert()` / `remove()` auf dem `CompressedAccountFilterSet` auf.
2. Überprüfen Sie `is_dirty()` (oder verbrauchen Sie das Flag mit `take_dirty()`), um zu sehen, ob sich der Filter geändert hat, seit er das letzte Mal gesendet wurde.
3. Wenn das Flag gesetzt ist, bauen Sie die Anfrage mit `insert_into_subscribe_request()` neu. In JavaScript können Sie sie im selben Stream mit `stream.write(request)` erneut senden; in Rust abonnieren Sie mit der neu aufgebauten Anfrage erneut.

## FAQ

<Accordion title="Kann ich Updates für Konten in meinem Filter verpassen?">
  Nein. Cuckoo-Filter erzeugen falsch positive Ergebnisse (zusätzliche Updates für nicht verfolgte Konten), aber **nie falsch negative**. Jedes Update für ein verfolgtes Konto wird geliefert.
</Accordion>

<Accordion title="Wie viele zusätzliche (falsch-positive) Updates werde ich erhalten?">
  Unter 1% bei voller Auslastung und typischerweise weniger, wenn der Filter unterhalb der Kapazität liegt. Ein lokaler `contains()`-Aufruf pro Update filtert sie genau aus.
</Accordion>

<Accordion title="Welche Clients unterstützen Cuckoo-Filter?">
  Das Rust SDK (`helius-laserstream` 0.2.0+), das JavaScript/TypeScript SDK (`helius-laserstream` 0.4.0+) und der Yellowstone Rust-Client (`yellowstone-grpc-client` 13.1.0+). Das Go SDK unterstützt es noch nicht. Siehe die [Verfügbarkeitstabelle](#verfügbarkeit) oben.
</Accordion>

<Accordion title="Kann ich immer noch explizite Pubkey-Listen verwenden?">
  Ja. Standard `account: [...]`-Filter funktionieren unverändert und bleiben die richtige Wahl für kleine Kontosets (bis zu etwa 10.000 Konten). Siehe den [Kontofilterungs-Leitfaden](/docs/de/laserstream/guides/account-subscription).
</Accordion>

## Verwandt

<CardGroup cols={2}>
  <Card title="Kontenabonnements" icon="user" href="/docs/de/laserstream/guides/account-subscription">
    Standardmäßige Kontofilterung mit Besitzer-, Datengrößen- und Memcmp-Filtern.
  </Card>

  <Card title="Clients & SDKs" icon="code" href="/docs/de/laserstream/clients">
    TypeScript-, Rust- und Go-SDKs mit automatischer Wiederholung und Wiederverbindung.
  </Card>
</CardGroup>
