Перейти к основному содержанию

Предварительные требования

Вам понадобится:
  • Node.js 18+ (или среда Rust для Rust-клиента)
  • URL эндпоинта gRPC OrbitFlare и токен (доступны в разделе Лицензии вашей Панели управления)

Установка

Установите официальный TypeScript-клиент Yellowstone gRPC:
npm install @triton-one/yellowstone-grpc
Или через yarn:
yarn add @triton-one/yellowstone-grpc

Подключение к эндпоинту

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

const GRPC_URL = "https://your-endpoint.grpc.orbitflare.com";
const X_TOKEN = "YOUR_GRPC_TOKEN";

const client = new Client(GRPC_URL, X_TOKEN, {
  "grpc.max_receive_message_length": 64 * 1024 * 1024, // 64 МиБ
});
URL gRPC и токен находятся в разделе Лицензии Панели управления OrbitFlare. Токен передаётся вторым аргументом в new Client().

Открытие потока

const stream = await client.subscribe();

const streamClosed = new Promise<void>((resolve, reject) => {
  stream.on("error", (error) => {
    console.error("Ошибка потока:", error);
    reject(error);
    stream.end();
  });
  stream.on("end", () => resolve());
  stream.on("close", () => resolve());
});

stream.on("data", (data) => {
  if (data.slot) {
    console.log("Обновление слота:", data.slot.slot);
  } else if (data.transaction) {
    console.log("Транзакция:", data.transaction);
  } else if (data.account) {
    console.log("Обновление аккаунта:", data.account);
  } else if (data.pong) {
    console.log("Получен pong");
  }
});

Отправка первой подписки

Подписка на все обновления слотов на уровне подтверждения confirmed:
const subscribeRequest: SubscribeRequest = {
  slots: {
    slot: { filterByCommitment: true },
  },
  commitment: CommitmentLevel.CONFIRMED,
  accounts: {},
  accountsDataSlice: [],
  transactions: {},
  transactionsStatus: {},
  blocks: {},
  blocksMeta: {},
  entry: {},
};

await new Promise<void>((resolve, reject) => {
  stream.write(subscribeRequest, (err) => {
    if (err == null) resolve();
    else reject(err);
  });
});

await streamClosed;

Поддержание соединения

Облачные балансировщики нагрузки завершают незанятые соединения gRPC примерно через 10 минут. Отправляйте ping каждые 30 секунд:
const pingRequest: SubscribeRequest = {
  ping: { id: 1 },
  accounts: {},
  accountsDataSlice: [],
  transactions: {},
  transactionsStatus: {},
  blocks: {},
  blocksMeta: {},
  slots: {},
  entry: {},
};

const pingInterval = setInterval(async () => {
  await new Promise<void>((resolve, reject) => {
    stream.write(pingRequest, (err) => {
      if (err == null) resolve();
      else reject(err);
    });
  });
}, 30_000);

streamClosed.finally(() => clearInterval(pingInterval));

Автоматическое переподключение

Для production-приложений реализуйте автоматическое переподключение с экспоненциальной задержкой:
async function connectWithRetry(maxRetries = 10) {
  let attempt = 0;
  let delay = 1000;

  while (attempt < maxRetries) {
    try {
      const stream = await client.subscribe();
      // ... подключить обработчики и отправить подписку
      await streamClosed;
      break;
    } catch (err) {
      attempt++;
      console.error(`Ошибка потока (попытка ${attempt}):`, err);
      if (attempt >= maxRetries) throw err;
      await new Promise((r) => setTimeout(r, delay));
      delay = Math.min(delay * 2, 30_000);
    }
  }
}

Следующие шаги