in-solana by Supanode

Solana gRPC in Python — Examples

TL;DR

  • - Use the yellowstone-grpc Python client (gRPC generated stubs) to stream Solana data
  • - Subscribe to accounts, transactions, slots, and blocks with server-side filters
  • - Handle reconnection and backpressure for production-grade streams

Python is a popular choice for data pipelines, analytics, and trading bots on Solana. The Yellowstone gRPC interface provides low-latency streaming of accounts, transactions, and slots using standard gRPC protocol buffers.

Setup

Install the gRPC dependencies:

pip install grpcio grpcio-tools

You need the Yellowstone gRPC protobuf definitions to generate Python stubs:

git clone https://github.com/rpcpool/yellowstone-grpc
cd yellowstone-grpc
python -m grpc_tools.protoc \
  -I proto \
  --python_out=. \
  --grpc_python_out=. \
  proto/geyser.proto

This generates geyser_pb2.py and geyser_pb2_grpc.py.

Basic subscription

import grpc
import geyser_pb2
import geyser_pb2_grpc

GRPC_ENDPOINT = "your-grpc-endpoint:443"
TOKEN = "your-auth-token"

def create_channel():
    credentials = grpc.ssl_channel_credentials()
    call_credentials = grpc.access_token_call_credentials(TOKEN)
    combined = grpc.composite_channel_credentials(credentials, call_credentials)
    return grpc.secure_channel(GRPC_ENDPOINT, combined)

channel = create_channel()
stub = geyser_pb2_grpc.GeyserStub(channel)

Subscribe to account updates

def subscribe_accounts(stub, owner_pubkey):
    request = geyser_pb2.SubscribeRequest(
        accounts={
            "token_accounts": geyser_pb2.SubscribeRequestFilterAccounts(
                owner=[owner_pubkey],
            )
        },
        commitment=geyser_pb2.CommitmentLevel.CONFIRMED,
    )

    def request_iterator():
        yield request

    for response in stub.Subscribe(request_iterator()):
        if response.HasField("account"):
            update = response.account
            print(f"Account: {update.account.pubkey.hex()}")
            print(f"Slot: {update.slot}")
            print(f"Data length: {len(update.account.data)}")

Subscribe to transactions by program

def subscribe_transactions(stub, program_id):
    request = geyser_pb2.SubscribeRequest(
        transactions={
            "program_txs": geyser_pb2.SubscribeRequestFilterTransactions(
                account_include=[program_id],
            )
        },
        commitment=geyser_pb2.CommitmentLevel.CONFIRMED,
    )

    def request_iterator():
        yield request

    for response in stub.Subscribe(request_iterator()):
        if response.HasField("transaction"):
            tx = response.transaction
            sig = tx.transaction.signature.hex()
            print(f"Transaction: {sig}")
            print(f"Slot: {tx.slot}")

Subscribe to slots

def subscribe_slots(stub):
    request = geyser_pb2.SubscribeRequest(
        slots={"slot_updates": geyser_pb2.SubscribeRequestFilterSlots()},
    )

    def request_iterator():
        yield request

    for response in stub.Subscribe(request_iterator()):
        if response.HasField("slot"):
            slot = response.slot
            print(f"Slot: {slot.slot} Status: {slot.status}")

Reconnection handling

Production streams must handle disconnections:

import time

def subscribe_with_reconnect(stub_factory, subscribe_fn, max_retries=None):
    retries = 0
    while max_retries is None or retries < max_retries:
        try:
            stub = stub_factory()
            subscribe_fn(stub)
        except grpc.RpcError as e:
            retries += 1
            wait = min(2 ** retries, 60)
            print(f"Disconnected: {e.code()}. Reconnecting in {wait}s...")
            time.sleep(wait)
        else:
            retries = 0

Async variant

For higher throughput, use the async gRPC client:

import asyncio
import grpc.aio

async def subscribe_async():
    channel = grpc.aio.secure_channel(GRPC_ENDPOINT, credentials)
    stub = geyser_pb2_grpc.GeyserStub(channel)

    async def request_iterator():
        yield request

    async for response in stub.Subscribe(request_iterator()):
        if response.HasField("account"):
            process_account(response.account)

FAQ

Is there an official Python SDK for Yellowstone gRPC? There is no official high-level Python SDK. You use the generated gRPC stubs from the protobuf definitions. Community wrappers exist but may lag behind the protocol version.

How does Python performance compare to Rust or TypeScript? Python’s gRPC client is C-backed (grpcio) and handles the network I/O efficiently. The bottleneck is usually in processing the received data. For high-throughput streams (thousands of updates per second), Rust or TypeScript with native gRPC bindings may be faster.

Can I use Python gRPC with asyncio? Yes. The grpc.aio module provides a fully async interface that works with Python’s asyncio event loop.

Updated: