satd-events-client 0.6.3

Async Rust client SDK for the satd.events.v1 streaming consumption API
Documentation

satd-events-client

Async Rust client SDK for the satd Streaming Consumption API (satd.events.v1).

It wraps the generated tonic client with a typed event model, per-call auth metadata, cursor capture/persistence, reconnect-with-backoff, Lagged auto-resume, replay-truncation detection, and a privacy-preserving prefix-watch local re-filter — so a consumer writes against StreamClient instead of hand-rolling channels, metadata, and protobuf unwrapping.

  • Typed events & watches — Event is a flat enum over the proto oneof; WatchHandle has a typed helper for every watch kind (scripts with min_value floors, outpoints, txid lifecycle, depth alarms, descriptors, prefixes).
  • Durable firehose — resilient_subscribe reconnects with backoff and persists the resume cursor through a CursorStore, so a process restart resumes from the stored height; Lagged recovers automatically and a server-side replay clamp surfaces as a synthetic Event::ReplayGap.
  • Native TLS / mTLS — tls() / tls_ca_pem() / tls_client_identity() / tls_domain() encrypt the transport (ring rustls provider) so a bearer token is never sent in cleartext.
  • No server-dependency leak — wire types live in the thin satd-events-proto crate, so this SDK pulls none of the node/RocksDB server stack.

Install

Pre-publish: this crate is not yet on crates.io. Depend on it via git until the published release lands:

[dependencies]
satd-events-client = { git = "https://github.com/epochbtc/satd", branch = "master" }

Once published, cargo add satd-events-client.

To read the API docs before publication, generate them locally:

cargo doc -p satd-events-client --no-deps --all-features --open

Quickstart

use satd_events_client::{StreamClient, SubscribeOptions, Categories, Event};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = StreamClient::builder("http://127.0.0.1:50051")
        .keepalive_default()
        .connect()
        .await?;

    let mut events = client
        .subscribe(SubscribeOptions {
            categories: Categories::MEMPOOL | Categories::CHAIN,
            ..Default::default()
        })
        .await?;

    while let Some(event) = events.message().await? {
        if let Event::BlockConnected { height, .. } = event {
            println!("block {height}");
        }
    }
    Ok(())
}

Over a plaintext http:// endpoint a bearer token travels in cleartext — enable TLS (below), restrict bearer auth to loopback, or front the node with a TLS-terminating proxy.

# use satd_events_client::StreamClient;
# async fn run() -> Result<(), Box<dyn std::error::Error>> {
// Pin a satd node's own (self-signed) CA and authenticate with a token.
let client = StreamClient::builder("https://node.example:50051")
    .tls_ca_pem(std::fs::read("node-ca.pem")?)
    .bearer_token("…")
    .connect()
    .await?;
# let _ = client; Ok(())
# }

Feature flags

Feature Default Effect
bitcoin on Typed bitcoin helpers + the PrefixWatcher prefix-watch re-filter (pulls bitcoin/secp256k1).
tls on Native TLS / mTLS via tonic's rustls integration (ring provider; no aws-lc-rs / C toolchain).

For a minimal, plaintext-only build: default-features = false.

Examples

Runnable examples live in examples/ — firehose_tail, resilient_tail, watch_outpoints, descriptor_wallet, lifecycle_alarms, prefix_privacy, tls_tail, mtls_tail:

cargo run -p satd-events-client --example firehose_tail -- http://127.0.0.1:50051

Stability & versioning

The crate version is the satd version it shipped with, and it follows semver. Use an SDK whose minor version is at or below your node's; newer nodes only add fields and event kinds within the same schema.

Each time a stream opens, the SDK compares the node's advertised version (satd-version response header) with its own:

  • same or newer node: silent;
  • one minor version behind: a tracing warning (target satd_events_client::compat) once per node version, which means upgrade the node;
  • two or more minor versions, or a major version, behind: StreamError::NodeTooOld, unless the client was built with allow_old_node(), which turns it into the warning;
  • a different event schema: StreamError::SchemaMismatch, always.

A node older than 0.6.0 sends no header and counts as 0.5. StreamClient::node_version() reports what the node advertised. The rule is written down in STABILITY_POLICY.md. MSRV is 1.93 (an MSRV bump is a minor-version change).

More

License

MIT — see LICENSE.