If you want to implement your own Geyser plugin gRPC on Rust this is your post.
While there are various pre-made plugins (for databases, queue systems, gRPCgRPC es un framework de código abierto de alto rendimiento … More streaming, etc.), you can also create your own Geyser Plugin to tailor data forwarding to your exact needs.
If you want to know if it worth to have your own geyser plugin you can see our post about it.
This article will walk you through:
The core of any custom Geyser Plugin lies in the GeyserPlugin trait. This trait defines how your plugin should behave at various points in the validator’s workflow and during data updates. Below is a simplified look at the trait:
pub trait GeyserPlugin: Any + Send + Sync + Debug {
// Required method
fn name(&self) -> &'static str;
// Provided methods
fn on_load(&mut self, _config_file: &str) -> Result<()> { ... }
fn on_unload(&mut self) { ... }
fn update_account(
&self,
accountA data structure on Solana that holds tokens and state; acco... More: ReplicaAccountInfoVersions<'_>,
slotThe smallest unit of time in Solana’s consensus mechanism ... More: Slot,
is_startup: bool
) -> Result<()> { ... }
fn notify_end_of_startup(&self) -> Result<()> { ... }
fn update_slot_status(
&self,
slot: Slot,
parent: Option,
status: SlotStatus
) -> Result<()> { ... }
fn notify_transaction(
&self,
transactionA signed data packet that contains instructions to transfer ... More: ReplicaTransactionInfoVersions<'_>,
slot: Slot
) -> Result<()> { ... }
fn notify_entry(
&self,
entry: ReplicaEntryInfoVersions<'_>
) -> Result<()> { ... }
fn notify_block_metadata(
&self,
blockinfo: ReplicaBlockInfoVersions<'_>
) -> Result<()> { ... }
fn account_data_notifications_enabled(&self) -> bool { ... }
fn transaction_notifications_enabled(&self) -> bool { ... }
fn entry_notifications_enabled(&self) -> bool { ... }
}
Although these methods have default implementations, you’ll typically override the ones relevant to your plugin logic:
Solana data often arrives as soon as a slotThe smallest unit of time in Solana’s consensus mechanism … More is processed. While this is great for low-latency ingestion, some processed slots may be skipped later if the network adopts a different branch. Therefore, your plugin (and any downstream systems) must be designed to handle potential rollbacks or re-orgs.
• Processed: The slot is recognized but not necessarily finalized.
• Confirmed: The slot is backed by sufficient votes to be considered secure by most validators.
• Rooted: The slot is fully cemented into the chain, guaranteeing no future re-org at or before that slot.
Key Takeaway: Your plugin should either handle or ignore updates that come from slots which might eventually be skipped. Some plugin developers implement buffering or waiting logic until slots reach a particular status. Others simply accept that “processed” data might be temporary.
These three methods govern how your plugin behaves during the validator’s lifetime:
Read configuration parameters (e.g., which accounts to filter, database connection strings, queue credentials). Then, prepare resources like database clients, file descriptors, or external services.
Ensures a clean shutdown and close open connections, flush logs, commit final data, etc.
Below is a clear roadmap for creating a plugin from scratch.
• Install Rust (with cargo) if you haven’t already.
• Clone or create a new Rust project:
cargo new my-geyser-plugin
cd my-geyser-plugin
Include the Geyser plugin interface crate in your Cargo.toml:
[dependencies]
solana-geyser-plugin-interface = "<version>"
# Potentially others, e.g., for database drivers or message queues
Create or edit a Rust source file (e.g., src/lib.rs) and define a struct that will hold your plugin’s state (configs, connections, etc.):
use solana_geyser_plugin_interface::geyser_plugin_interface::GeyserPlugin;
use solana_geyser_plugin_interface::geyser_plugin_interface::{Result as GeyserResult, /* ...other necessary imports... */};
pub struct MyCustomPlugin {
// fields you need for your logic
// e.g. db connection strings, config details
}
impl MyCustomPlugin {
pub fn new() -> Self {
Self {
// initialize fields
}
}
}
impl GeyserPlugin for MyCustomPlugin {
fn name(&self) -> &'static str {
"MyCustomPlugin"
}
fn on_load(&mut self, config_file: &str) -> GeyserResult<()> {
// parse JSON/JSON5 config
// set up DB clients, logging, etc.
Ok(())
}
fn on_unload(&mut self) {
// cleanup or close connections
}
fn update_account(
&self,
account: ReplicaAccountInfoVersions,
slot: Slot,
is_startup: bool
) -> GeyserResult<()> {
// handle account updates
// perhaps log or forward to a queue
Ok(())
}
// override other methods as needed...
// e.g. notify_transaction, update_slot_status, etc.
}
To let Solana dynamically load your plugin, you must expose a C-compatible function named _create_plugin:
#[no_mangle]
pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin {
let plugin = MyCustomPlugin::new();
Box::into_raw(Box::new(plugin))
}
Note: The #[no_mangle] and extern “C” attributes ensure the function name and calling convention remain intact, letting the validator discover and call it at runtime.
Update your Cargo.toml or run with flags so it compiles to a .so (on Linux):
[lib]
name = "my_geyser_plugin"
crate-type = ["cdylib"]
Then compile:
cargo build --release
Look for the resulting .so file in target/release/libmy_geyser_plugin.so.
Place a JSON or JSON5 config file (e.g., geyser-config.json) that references your shared library:
{
"libpath": "/full/path/to/libmy_geyser_plugin.so",
"my_custom_key": "someValue"
}
Tip: Add any additional configuration keys your plugin needs—like database URIs, table names, or queue endpoints—so you can parse them in on_load.
When launching your Solana validator, specify:
solana-validator \
--geyser-plugin-config /path/to/geyser-config.json \
--other-flags ...
Your plugin will be dynamically loaded at startup, and on_load will be called with /path/to/geyser-config.json.
• Logs: If your plugin writes logs, confirm that you see them when the validator starts, processes transactions, or shuts down.
• Data Flow: Ensure your plugin is sending the data where you want it—database, queue, or any custom logic.
• Lifecycle: Confirm that on_unload is called properly when the validator exits and that you receive notify_end_of_startup after snapshots are restored.
1. Handle Rollbacks or Re-Orgs: Because slots may be skipped, your plugin (and downstream systems) should anticipate the possibility of seeing “processed” data that never becomes part of the chain.
2. Enable/Disable Notifications: If you only care about transactions, set account_data_notifications_enabled() and entry_notifications_enabled() to false to reduce overhead.
3. Resource Management: Close connections and free memory in on_unload() to avoid resource leaks.
4. Scalability: Large or busy validators can push thousands of updates per second. Make sure your plugin’s logic can keep up with the data throughput (e.g., asynchronous writes, batching, or queue buffering).
5. Security: If your plugin uses private credentials (to connect to a DB, for instance), store them securely, parse them carefully in on_load, and never leak them in logs.
Writing your own Geyser Plugin gives you ultimate control over how you collect, transform, and store Solana on-chain data. By understanding the GeyserPlugin trait methods—especially lifecycle hooks like on_load and on_unload, commitment levels, and potential skipped slots—you can build a powerful, customized data pipeline.
Whether you’re archiving every transactionA signed data packet that contains instructions to transfer … More in a specialized database or triggering automated workflows based on real-time accountA data structure on Solana that holds tokens and state; acco… More changes, a custom Geyser Plugin can streamline the process and reduce the need for constant RPC polling. Once you get comfortable with the fundamentals, you can explore advanced optimizations, custom filtering, and robust error handling to match any scale and complexity you need.
• Dive deeper into the solana-geyser-plugin-interface documentation.
• Explore official Solana references on Geyser Plugin setup.
• Experiment with your own database or queue integrations to see how far you can extend real-time Solana data streaming.
Engineer. CEO of GS Node. Marketing Manager at Smithii.