Solana gRPC in Rust: Examples
TL;DR
- - Use yellowstone-grpc-client crate for Rust gRPC connections
- - Build filter requests with yellowstone-grpc-proto types
- - Handle the bidirectional stream with tokio async
- - Implement reconnection for production reliability
The yellowstone-grpc-client and yellowstone-grpc-proto crates provide a Rust client for Yellowstone gRPC. The client uses tonic for gRPC transport and tokio for async runtime.
Dependencies
[dependencies]
yellowstone-grpc-client = "2"
yellowstone-grpc-proto = "2"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
Connecting
use yellowstone_grpc_client::GeyserGrpcClient;
let mut client = GeyserGrpcClient::build_from_uri("https://your-endpoint.example.com")
.x_token(Some("your-auth-token".to_string()))
.connect()
.await?;
let (mut subscribe_tx, mut stream) = client.subscribe().await?;
Subscribing to accounts
use yellowstone_grpc_proto::prelude::*;
use std::collections::HashMap;
let mut accounts = HashMap::new();
accounts.insert(
"token_accounts".to_string(),
SubscribeRequestFilterAccounts {
account: vec![],
owner: vec!["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA".to_string()],
filters: vec![],
},
);
subscribe_tx.send(SubscribeRequest {
accounts,
slots: HashMap::new(),
transactions: HashMap::new(),
blocks: HashMap::new(),
blocks_meta: HashMap::new(),
commitment: Some(CommitmentLevel::Confirmed as i32),
..Default::default()
}).await?;
Reading the stream
use futures::StreamExt;
while let Some(msg) = stream.next().await {
match msg {
Ok(update) => {
if let Some(UpdateOneof::Account(account)) = update.update_oneof {
let info = account.account.unwrap();
println!("Account: {} ({} bytes)",
bs58::encode(&info.pubkey).into_string(),
info.data.len()
);
}
}
Err(e) => {
eprintln!("Stream error: {e}");
break;
}
}
}
Reconnection pattern
loop {
match connect_and_subscribe().await {
Ok(()) => break, // clean shutdown
Err(e) => {
eprintln!("Disconnected: {e}, reconnecting in 5s...");
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
}
}
Wrap the connection and stream reading in a function and retry on error. Use exponential backoff for production deployments.
FAQ
Which Rust async runtime does it need? Tokio. The gRPC client uses tonic, which requires the tokio runtime.
Can I run multiple subscriptions?
Send multiple named filters in a single SubscribeRequest. All matching data arrives on the same stream.
How do I parse transaction instructions?
Use solana-sdk to deserialize the transaction bytes from the update, then match on program IDs and instruction data.
Updated: