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

Обзор

Yellowstone gRPC предоставляет два связанных, но различных типа подписок для отслеживания прогресса сети:
  • Слоты — лёгкие обновления, указывающие, когда слот достигает уровней подтверждения processed, confirmed или finalized. Низкая пропускная способность, подходит для мониторинга консенсуса.
  • Блоки — полные данные блоков, включая транзакции, обновления аккаунтов и записи. Более высокая пропускная способность, подходит для индексаторов и аналитики.

Подписки на слоты

Параметры фильтрации

ПараметрТипОписание
filterByCommitmentbooleanПри true генерирует обновления слотов только для уровня подтверждения подписки. При false (по умолчанию) — для всех уровней.
interslotUpdatesbooleanПри true генерирует изменения состояния внутри слота, а не только на его границах.

Пример: Отслеживание подтверждённых слотов

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

const client = new Client(
  "https://your-endpoint.grpc.orbitflare.com",
  "YOUR_GRPC_TOKEN",
  { "grpc.max_receive_message_length": 64 * 1024 * 1024 }
);

async function main() {
  const stream = await client.subscribe();

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

  stream.on("data", (data) => {
    if (data.slot) {
      const { slot, parent, status } = data.slot;
      console.log(`Слот ${slot} (родительский: ${parent}) — статус: ${status}`);
    }
  });

  const request: SubscribeRequest = {
    slots: {
      slotUpdates: {
        filterByCommitment: true,
      },
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    accountsDataSlice: [],
    transactions: {},
    transactionsStatus: {},
    blocks: {},
    blocksMeta: {},
    entry: {},
    ping: { id: 1 },
  };

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

  await streamClosed;
}

main();

Подписки на блоки

Параметры фильтрации

ПараметрТипОписание
accountIncludestring[]Фильтрация транзакций и обновлений аккаунтов внутри блоков — только эти аккаунты.
includeTransactionsbooleanВключить полные данные транзакций в каждое обновление блока.
includeAccountsbooleanВключить обновления состояния аккаунтов в каждое обновление блока.
includeEntriesbooleanВключить записи (единицы выполнения) в каждое обновление блока.
Подписки на блоки с includeTransactions: true без фильтра аккаунтов производят очень большие объёмы данных. Используйте accountInclude для сужения потока или выделенный узел для устойчивой пропускной способности.

Пример: Потоковая передача блоков с транзакциями

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

const client = new Client(
  "https://your-endpoint.grpc.orbitflare.com",
  "YOUR_GRPC_TOKEN",
  { "grpc.max_receive_message_length": 1024 * 1024 * 1024 }
);

async function main() {
  const stream = await client.subscribe();

  stream.on("data", (data) => {
    if (data.block) {
      const { block } = data;
      console.log(`Слот блока: ${block.slot}`);
      console.log(`  Хеш блока: ${block.blockhash}`);
      console.log(`  Транзакций: ${block.transactions?.length ?? 0}`);
    }
  });

  const request: SubscribeRequest = {
    blocks: {
      blockStream: {
        accountInclude: [
          "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", // Raydium AMM
        ],
        includeTransactions: true,
        includeAccounts: false,
        includeEntries: false,
      },
    },
    commitment: CommitmentLevel.CONFIRMED,
    accounts: {},
    accountsDataSlice: [],
    transactions: {},
    transactionsStatus: {},
    slots: {},
    blocksMeta: {},
    entry: {},
    ping: { id: 1 },
  };

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

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

  await streamClosed;
}

main();

Выбор между слотами и блоками

ПотребностьИспользовать
Обнаружить финализацию слотаПодписка на слоты (filterByCommitment: true)
Отслеживать высоту блокаПодписка на слоты
Индексировать все транзакции в блокеПодписка на блоки (includeTransactions: true)
Мониторинг изменений аккаунтов на блокПодписка на блоки (includeAccounts: true)
Минимальная задержка сигнала консенсусаПодписка на слоты на уровне processed
Полные данные блоков архивного качестваПодписка на блоки на уровне finalized