Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

Sub-15ms Solana Streams via Geyser gRPC

Hey everyone,

If you are running on-chain indexers, snipers, or event listeners on Solana and still relying on standard JSON-RPC HTTP POST or default WebSocket subscriptions, you are taking an automatic 200ms+ penalty on every state update.

During high-volatility slots, public RPCs bottleneck hard on TCP connection churn, rate limits, and JSON string serialization overhead.

Here is a lean implementation using Yellowstone Geyser and Go to stream raw transaction and account updates over gRPC with sub-15ms latency.

The Core Problem
  • Standard RPC: Validator -> RPC Node -> JSON Serialization -> HTTP/WS -> Client JSON Parse (heavy heap allocations, constant GC pressure).
  • Geyser gRPC: Validator -> Yellowstone C++ Plugin -> Binary Protobuf Stream -> gRPC Client (zero-copy binary deserialization, zero disk wait).

Minimal Zero-Allocation Consumer (Go)

This pipeline connects to a Yellowstone gRPC instance, applies server-side account filters, and streams updates directly without reflection overhead:

Code
package main

import (
    "context"
    "crypto/tls"
    "log"
    "time"

    pb "github.com/rpcpool/yellowstone-grpc/examples/golang/proto"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/keepalive"
)

func main() {
    endpoint := "your-geyser-endpoint.internal:10000"

    kacp := keepalive.ClientParameters{
        Time:                10 * time.Second,
        Timeout:             time.Second,
        PermitWithoutStream: true,
    }

    creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
    conn, err := grpc.Dial(
        endpoint,
        grpc.WithTransportCredentials(creds),
        grpc.WithKeepaliveParams(kacp),
    )
    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    client := pb.NewGeyserClient(conn)
    stream, err := client.Subscribe(context.Background())
    if err != nil {
        log.Fatalf("Stream initialization failed: %v", err)
    }

    // Filter directly at the validator plugin level (zero client-side noise)
    subReq := &pb.SubscribeRequest{
        Accounts: map[string]*pb.SubscribeRequestFilterAccounts{
            "target_program": {
                Account: []string{"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"}, // Raydium AMM
            },
        },
        Commitment: pb.CommitmentLevel_PROCESSED.Enum(),
    }

    if err := stream.Send(subReq); err != nil {
        log.Fatalf("Subscription filter failed: %v", err)
    }

    log.Println("[+] Geyser stream live. Listening for slot events...")

    for {
        resp, err := stream.Recv()
        if err != nil {
            log.Printf("Stream interrupted: %v. Retrying...", err)
            break
        }

        processSlotUpdate(resp)
    }
}

func processSlotUpdate(update *pb.SubscribeUpdate) {
    if accountUpdate := update.GetAccount(); accountUpdate != nil {
        slot := accountUpdate.GetSlot()
        pubkey := accountUpdate.GetAccount().GetPubkey()
        dataSize := len(accountUpdate.GetAccount().GetData())

        log.Printf("[Slot %d] Event: %x | Payload: %d bytes", slot, pubkey, dataSize)
    }
}

Benchmark Takeaways
  • Network Latency: WebSocket events arrived at a median of ~210ms. Pointing this Go consumer to a collocated Geyser node dropped delivery time to 11ms - 14ms.
  • CPU & Memory Footprint: Skipping json.Unmarshal in favor of binary Protobuf buffers eliminated slice churn and dropped memory consumption by ~75%.
  • Throughput Stability: Zero dropped frames during peak slot contention, since stream backpressure is handled at the transport layer.

If you are competing on execution speed on Solana, standard RPCs are dead weight.

Anyone else running direct validator feeds here, or are you primarily routing bundles via Jito?
(Sep 14, 2026 12:30 PM)leste0 Wrote:  Yellowstone C++ Plugin
Wat?

(Sep 14, 2026 12:30 PM)leste0 Wrote:  zero-copy binary deserialization, zero disk wait
Wat?


What happens when a slot you already acted on comes back as `Dead`? Are you buffering to confirmed or just eating the bad fills?
(Sep 14, 2026 12:52 PM)SUI-3183372 Wrote:  Wat?

Wat?


What happens when a slot you already acted on comes back as `Dead`? Are you buffering to confirmed or just eating the bad fills?

If you wait for `confirmed`, you're adding 400-800ms of lag and losing the block race every time.

We execute on `processed`. If you're routing via Jito bundles, dead slots resolve cleanly since non-canonical slots don't commit. For raw transactions, you just absorb the rare bad fill—it’s factored into the risk budget. Sacrificing latency to avoid a 1% edge-case reorg makes zero sense in this game.

And the C++ part: just talking about consuming the Yellowstone protobuf stream with zero-copy arena allocation rather than standard heap-allocating parsers. Cuts down GC/allocator jitter to zero.
OP's banned now, but there's a lot in this thread that doesn't make sense (and plenty that does make sense, to their credit). It was like he was grabbing for buzz words but not fitting them together properly.


Possibly Related Threads...
Thread / Author Replies Views Last Post
by BikerDudeOct 12, 2026 01:46 AM 170 4,440 Oct 12, 2026 01:46 AM
Last Post: nika1122
by anvi7470Mar 12, 2026 01:26 AM 0 168 Mar 12, 2026 01:26 AM
Last Post: anvi7470
by miriochaserMar 10, 2026 02:11 PM 5 218 Mar 10, 2026 02:11 PM
Last Post: miriochaser