Solana Geyser Plugins: Powering High-Speed Data Streaming Guide
Geyser gRPC, offers a high-performance and flexible way to stream block, transaction, account, and slot updates directly from the Solana blockchain. Whether you’re building analytics dashboards, real-time monitoring services, or dev tools, this guide will walk you through subscribing to various update streams — accounts, slots, and transactions — leveraging the Yellowstone Geyser Interface.
Why Geyser gRPC?
While Geyser gRPC focuses on streaming via a gRPC endpoint, Solana Geyser Plugins are a modular system built into the Solana validator itself. You might consider Geyser Plugins if:
- You want extremely low-level, near-instant data handling.
- You plan to push updates directly into a specific database (PostgreSQL, Kafka, etc.) or message queue.
- You manage your own validators and can configure dynamic libraries (plugins) at runtime.
- High Throughput: Geyser gRPC accommodates Solana’s rapid block production cadence, supporting large numbers of concurrent subscriptions.
• Flexible Filters: Subscribe only to what you need, such as all accounts owned by your on-chain program, or only “vote” transactions. This can greatly reduce your application’s overhead.
• Real-Time + Historical: Combine live streaming (via Dragon’s Mouth) with historical queries through Old Faithful to fully cover the chain’s events (blocks, transactions, and account states).
• gRPC Efficiency: gRPC and protocol buffers generally offer lower overhead and higher throughput than plain JSON RPC over HTTP/WebSockets, especially at scale.
How Geyser Plugins Work
- The validator loads a Rust-based plugin implementing the “GeyserPlugin” trait.
- Each time an account, slot, or transaction updates, Solana invokes a corresponding function like
update_account
ornotify_transaction
. - The plugin can handle or store data however it sees fit—potentially skipping the entire Solana RPC overhead.
This plugin approach was favored over “AccountsDB replicas” because it is simpler for validator clients and far more flexible, letting you define exactly how data should be streamed or stored. The architecture ensures you won’t bog down the validator with giant “getProgramAccounts” queries.
Overview of Geyser gRPC Update Types
- Account Updates
- Emitted whenever an account’s lamports, data, or ownership changes.
- Essential for dApps that need to track real-time user balances, liquidity pool states, or market data.
2. Slot Updates
- Published for each new slot, including the parent slot and commitment level (Processed, Confirmed, or Finalized).
- Helpful for block explorers, chain indexers, or any application that needs granular, slot-by-slot visibility.
3. Transaction Updates
- The transaction signature, involved accounts, status (e.g., success or failure), and metadata are included.
- It is ideal for real-time analytics, protocol metrics, or compliance logging where you need canonical “cause-and-effect” behind account changes.
These update types can be mixed and matched in a single subscription request, allowing you to fetch only what’s relevant to your dApp or service.
Getting Started with the Rust Client
The Rust example in the yellowstone-grpc repo demonstrates how to:
- Parse command-line arguments.
- Connect to a Geyser gRPC endpoint.
- Set up subscription filters for accounts, transactions, slots, blocks, etc.
- Handle streaming updates over an asynchronous gRPC connection.
A simplified command to run Geyser GRPC might look like:
cargo run --bin client \
-- --endpoint <GEYSER_GRPC_ENDPOINT> --x-token <TOKEN> \
subscribe \
--accounts \
--slots \
--transactions \
2>&1 | tee output.log
Where:
--endpoint
points to the Geyser gRPC URL (for example, https://api.rpcpool.com).--x-token
is an API token if your Geyser endpoint requires authentication.--accounts
,--slots
, and--transactions
tell the client to subscribe to those respective updates.
1. Subscribing to Account Updates
“Accounts” within the client.rs are managed through a filter type called SubscribeRequestFilterAccounts
. You can specify conditions such as:
• Owner Pubkey (i.e., your on-chain program’s address).
• Data size (e.g., “datasize = 324 bytes”).
• Memcmp conditions (offset + base58 data checks).
• Lamports-based conditions (“gt:1000000000” to filter high-lamport accounts).
• “Accounts token account state” to specifically get SPL token accounts; updates include token balances and freeze authority changes.
A snippet from the Rust client might look like this:
let filter = SubscribeRequestFilterAccountsFilter {
filter: Some(AccountsFilterOneof::Memcmp(
SubscribeRequestFilterAccountsFilterMemcmp {
offset: 0,
data: Some(AccountsFilterMemcmpOneof::Base58("Qm...".to_string())),
},
)),
};
// ...
let mut accounts = HashMap::new();
accounts.insert(
"client".to_owned(),
SubscribeRequestFilterAccounts {
account: vec!["<SPECIFIC_ACCOUNT_PUBKEY>".to_string()],
owner: vec!["<YOUR_PROGRAM_PUBKEY>".to_string()],
filters: vec![filter],
nonempty_txn_signature: None, // Only stream if there’s a related transaction
},
);
Whenever those accounts change (e.g., ownership transitions, data writes, lamport balance modifications), a corresponding update event will stream to your client. This is especially useful for DeFi protocols monitoring user or pool states in real time.
2. Subscribing to Slot Updates
Slots are effectively the “heartbeat” of the Solana blockchain:
let mut slots = HashMap::new();
slots.insert(
"client".to_owned(),
SubscribeRequestFilterSlots {
filter_by_commitment: Some(true),
});
With such a subscription, your client receives:
- The slot’s number and its parent slot.
- Commitment level (whether it is Processed, Confirmed, or Finalized).
- Error info if the slot is marked “dead.”
Infrastructure providers and explorers often rely on this feed to maintain up-to-date chain indexes, or to trigger follow-up indexing tasks once a slot is finalized.
3. Subscribing to Transaction Updates
Transactions give the “why” behind on-chain changes. By subscribing to transaction updates, you’ll see:
- Signatures for each new transaction.
- Whether it’s a vote transaction.
- A list of participating accounts (including signers).
- Transaction success or failure, with any relevant error messages.
An example filter configuration:
let mut transactions = HashMap::new();
transactions.insert(
"client".to_string(),
SubscribeRequestFilterTransactions {
// Only track successful, non-vote transactions
vote: Some(false),
failed: Some(false),
signature: None,
account_include: vec!["<ACCOUNT_PUBKEY>".to_string()],
account_exclude: vec![],
account_required: vec![],
},
);
Monitoring transaction updates is especially powerful for dashboards or analytics that need real-time insights into user behavior. For instance, a front-end aggregator might highlight every new transaction that interacts with a popular liquidity pool.
Considerations for an End-to-End Setup
- Initial State & Snapshots: Before streaming live changes, gather a “snapshot” of the chain’s current state, for example using Solana’s built-in RPC “getProgramAccounts” or Project Yellowstone’s Old Faithful historical data. That ensures your local state or DB is seeded properly.
- Handling Missed Updates: If your client briefly disconnects or restarts, consider a “from_slot” parameter to re-subscribe from a known slot, mitigating the risk of missing events.
- Performance & Filtering: Geyser gRPC can deliver massive volumes of data. Filter by ownership, lamports, or memcmp to reduce bandwidth and CPU usage on your end.
- Commitment Selection: Decide whether to subscribe to Processed (fastest), Confirmed (medium) or Finalized (highest confirmation) states. The right choice depends on how quickly you need updates vs. how certain they need to be.
Putting it All Together
Here is a consolidated example that subscribes to accounts, slots, and transactions:
cargo run --bin client -- \
--endpoint https://api.rpcpool.com/ \
--x-token <YOUR_TOKEN> \
subscribe \
--accounts \
--accounts-owner <PROGRAM_PUBKEY> \
--slots \
--slots-filter-by-commitment \
--transactions \
--transactions_account_include <ACCOUNT_PUBKEY> \
2>&1 | tee subscription.log
Explanation:
- The Rust client connects to https://api.rpcpool.com.
- Authorizes itself using
--x-token
. - Subscribes to account updates on all accounts owned by
<PROGRAM_PUBKEY>
. - Subscribes to every newly processed slot.
- Subscribes to any transaction that includes
<ACCOUNT_PUBKEY>
. - Pipes output to “subscription.log” for later analysis.
Final Thoughts
By combining Geyser gRPC (for quick subscription-based streaming) with the broader Solana Geyser Plugin ecosystem, you can minimize RPC overhead on validators and gain the high-performance, real-time insights that modern decentralized applications demand.
Whatever route you choose, keep in mind:
- Plan your data flow. Do you need immediate, unconfirmed updates, or do you require only finalized states?
- Ensure reliability. If your service goes down, have a plan to restart from a known slot or reference point.
- Experiment with filters. Fine-tuned filters help avoid unneeded updates, reducing both bandwidth costs and client overhead.
Resources to keep going:
- Peruse the Rust client example to see advanced filtering (e.g., lamports, memcmp, token accounts).
- Check out the rest of Project Yellowstone’s documentation to understand how Geyser gRPC, Steamboat, Old Faithful, and Whirligig interconnect.
- Solana Geyser Plugins: Streaming Data at the Speed of Light by Helius
- Solana Docs
Armed with Geyser gRPC, you can confidently build next-level Solana tooling that meets the demands of high-throughput, real-time DeFi and beyond.