Reconstructs Solana transactions from shreds in real time.
- Ingests shreds via UDP
- Parallelizes processing across Forward Error Correction (FEC) sets and entry batches
- Processes transactions via user-provided handler
- Provides optional Prometheus metrics for system performance monitoring
use anyhow::Result;
use unshred::{TransactionEvent, TransactionHandler, UnshredProcessor};
struct MyHandler;
impl TransactionHandler for MyHandler {
fn handle_transaction(&self, event: &TransactionEvent) -> Result<()> {
let signature = solana_sdk::bs58::encode(&event.transaction.signatures[0]).into_string();
println!("Slot {}: {} with {} instructions",
event.slot,
signature,
event.transaction.message.instructions().len()
);
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<()> {
let processor = UnshredProcessor::builder()
.handler(MyHandler)
.bind_address("0.0.0.0:8001")
.build()?;
processor.run().await
}See examples/drift-monitor for a production-ready implementation that:
- Filters transactions for Drift protocol liquidation events
- Stores events in ClickHouse
- Tracks system performance metrics with Prometheus
- Generates Grafana dashboards for liquidation and system monitoring
- Packages all components into a docker-compose deployment
The example demonstrates the activation of the internal metrics for unshred:
features = ["metrics"]inCargo.tomlUnshredProcessor::builder().metrics_registry(registry)to init
pub trait TransactionHandler: Send + Sync + 'static {
/// Called for each reconstructed transaction
/// # Returns
/// * `Ok(())` - to continue processing
/// * `Err(_)` - to log error and continue (does not stop processing)
fn handle_transaction(&self, event: &TransactionEvent) -> Result<()>;
}#[derive(Debug)]
pub struct TransactionEvent<'a> {
pub slot: u64,
pub transaction: &'a VersionedTransaction,
/// * `Some(_)` - data shred containing this transaction was directly received via UDP
/// * `None` - data shred containing this transaction was recovered via code shreds
///
/// Note: Estimated as the received_at_micros of the data shred that contained
/// the first byte of the Entry that contained this transaction.
pub received_at_micros: Option<u64>,
pub processed_at_micros: u64,
}