🌊Geyser (Yellowstone)

Highly configurable real-time data streams.

gRPC is only available for dedicated nodes. You can provision a dedicated node directly from the Helius developer portal. To learn more, please visit Dedicated Nodes.

What are gRPC streams?

gRPC streams are the fastest way to stream Solana data to your backend. You may subscribe to blocks, slots, transactions, and account updates. It is highly configurable. You can filter or limit each subscription. It allows the client server to create new subscriptions or cancel existing ones immediately.

To learn more, please read the examples provided in the source repo: https://github.com/rpcpool/yellowstone-grpc.

Tips & Tricks

Connection Persistence & Pings

gRPC is typically accessed behind a load-balancer or proxy which will terminate an inactive connection after 10 minutes. Pinging the gRPC every N seconds or minutes is the best solution. The follow code provides a demonstration:

import Client, {
  CommitmentLevel,
  SubscribeRequest,
  SubscribeRequestFilterAccountsFilter,
} from "@triton-one/yellowstone-grpc";

const GRPC_URL = "insert_here";
const X_TOKEN = "insert_here";
const PING_INTERVAL_MS = 30_000; // 30s

async function main() {
  // Open connection.
  const client = new Client(GRPC_URL, X_TOKEN, {
    "grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB
  });

  // Subscribe for events
  const stream = await client.subscribe();

  // Create `error` / `end` handler
  const streamClosed = new Promise<void>((resolve, reject) => {
    stream.on("error", (error) => {
      reject(error);
      stream.end();
    });
    stream.on("end", () => {
      resolve();
    });
    stream.on("close", () => {
      resolve();
    });
  });

  // Handle updates
  stream.on("data", (data) => {
    let ts = new Date();
    if (data.filters[0] == "slot") {
      console.log(
        `${ts.toUTCString()}: Received slot update: ${data.slot.slot}`
      );
    } else if (data.pong) {
      console.log(`${ts.toUTCString()}: Processed ping response!`);
    }
  });

  // Example subscribe request.
  // Listen to all slot updates.
  const slotRequest: SubscribeRequest = {
    slots: {
      slot: { filterByCommitment: true },
    },
    commitment: CommitmentLevel.CONFIRMED,

    // Required, but unused arguments
    accounts: {},
    accountsDataSlice: [],
    transactions: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
  };

  // Send subscribe request
  await new Promise<void>((resolve, reject) => {
    stream.write(slotRequest, (err) => {
      if (err === null || err === undefined) {
        resolve();
      } else {
        reject(err);
      }
    });
  }).catch((reason) => {
    console.error(reason);
    throw reason;
  });

  // Send pings every 5s to keep the connection open
  const pingRequest: SubscribeRequest = {
    ping: { id: 1 },
    // Required, but unused arguments
    accounts: {},
    accountsDataSlice: [],
    transactions: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    slots: {},
  };
  setInterval(async () => {
    await new Promise<void>((resolve, reject) => {
      stream.write(pingRequest, (err) => {
        if (err === null || err === undefined) {
          resolve();
        } else {
          reject(err);
        }
      });
    }).catch((reason) => {
      console.error(reason);
      throw reason;
    });
  }, PING_INTERVAL_MS);

  await streamClosed;
}

main();

Last updated