Skip to content

thru-client

View as Markdown

Use thru-client when you want an ergonomic Rust RPC client instead of assembling channels, metadata, and request types on top of the raw generated bindings.

Terminal window
cargo add thru-client thru-base url
cargo add tokio --features macros,rt-multi-thread

Choose this crate when you want to:

  • Query accounts, balances, transactions, block heights, chain info, and node status with typed helper methods.
  • Submit signed transactions and wait for execution with execute_transaction, or fire-and-forget with send_transaction and batch_send_transactions.
  • Track many in-flight transactions over one connection with stream_confirmations.
  • Generate state proofs and prepare account decompression without touching proto types.
  • You need keys, transaction builders, address parsing, or proof helpers: use thru-base. thru-client submits already-signed wire bytes; it does not build or sign transactions.
  • You want to stay close to the wire format or call the generated services directly: use thru-grpc-client.

Build a Client with ClientBuilder (also reachable as Client::builder()):

use std::time::Duration;
use thru_client::{Client, ClientBuilder};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client: Client = ClientBuilder::new()
.http_endpoint(url::Url::parse("http://127.0.0.1:8472")?)
.timeout(Duration::from_secs(30))
.build()?;
let height = client.get_block_height().await?;
println!("finalized height: {}", height.finalized_height);
Ok(())
}
Builder methodWhat it configures
http_endpoint(url::Url)The node’s gRPC endpoint. Defaults to http://127.0.0.1:8472. An https:// URL enables TLS, configured when build runs, so the builder methods are order-independent.
timeout(Duration)Per-request timeout. Defaults to 30 seconds.
auth_token(Option<String>)Optional bearer token sent as the authorization metadata header on every request.
insecure(bool)Skip TLS certificate verification for https:// endpoints, for nodes presenting self-signed or otherwise untrusted certificates. Disables peer authentication, so only use it against endpoints you trust by other means. No effect on plaintext endpoints.
announce_pending_signature(bool)Print each pending transaction signature to stderr just before submission. Off by default.
build()Produce the Client. The connection itself is established lazily on first use.

All helpers are async and return thru_client::Result<T> (Result<T, ClientError>).

TaskMain entrypoints
Read accountsget_account_info, get_balance, get_account_at_slot
Read transactionsget_transaction, list_transactions_for_account, track_transaction_polling
Submit transactionsexecute_transaction, send_transaction, batch_send_transactions
Stream confirmationsstream_confirmations returning a ConfirmationStream
Node and chain infoget_version, get_chain_info, get_health, get_block_height, get_node_status
State and metricsget_state_roots, get_state_hashes, get_slot_metrics, list_slot_metrics
Proofs and decompressionmake_state_proof, prepare_account_decompression
Debuggingdebug_re_execute

get_account_info and get_transaction return Ok(None) when the node reports NOT_FOUND instead of surfacing an error.

Build and sign the transaction with thru-base, then hand the wire bytes to the client:

  • execute_transaction(transaction, timeout) submits and waits for execution over a server-side tracking stream, then fetches full TransactionDetails (consumed compute, memory, and state units, execution and VM error codes, events, accounts, and header fields). If tracking times out or fails in a way that leaves the submission outcome unknown, it falls back to polling for the transaction by signature.
  • send_transaction(transaction) submits without waiting and returns the 64-byte signature.
  • batch_send_transactions(transactions, num_retries) submits many pre-signed transactions in one request and returns (signature, accepted) per transaction, in order. Use stream_confirmations to observe when accepted transactions land on-chain.
use std::time::Duration;
let details = client
.execute_transaction(&wire_bytes, Duration::from_secs(30))
.await?;
assert_eq!(details.execution_result, 0);
assert_eq!(details.vm_error, 0);

stream_confirmations(fee_payer) opens a live server stream of confirmations for transactions paid for by fee_payer, letting one connection track many in-flight transactions:

let mut stream = client.stream_confirmations(&fee_payer).await?;
while let Some(confirmation) = stream.next(Duration::from_secs(10)).await? {
println!(
"slot {}: vm_error={} execution_result={}",
confirmation.slot, confirmation.vm_error, confirmation.execution_result
);
}

ConfirmationStream::next returns Ok(Some(Confirmation)) when a transaction is confirmed with an execution result, Ok(None) when the timeout elapses first, and Err(_) when the stream ends or errors. Drop the stream to unsubscribe.

Fallible calls return ClientError, whose variants distinguish Rpc, Transport, Validation, TransactionSubmission, TransactionVerification, AccountNotFound, and Generic failures. get_balance returns AccountNotFound for missing accounts.

  • The crate re-exports the generated proto modules as thru_client::proto, so response types that are passed through unconverted (for example from debug_re_execute) resolve without adding a direct thru-grpc-client dependency.
  • Helper methods take thru_base::tn_tools::Pubkey and Signature wrapper types, not raw byte arrays; signature_from_wire extracts the trailing 64-byte fee-payer signature from signed wire bytes.
  • In this repository, rpc/thru-client layers these helpers on top of thru-grpc-client; the Thru CLI is its main in-tree consumer.