Skip to main content

What Are Entries?

Entries are the fundamental execution units within a Solana block. Each block is composed of one or more entries, where each entry contains a batch of transactions that were executed sequentially. Entries represent the most granular level of block data — below blocks and above individual transactions. Monitoring entries is useful for:
  • Building custom block parsers that need precise transaction ordering
  • Reconstructing execution order within a block
  • Low-latency detection of specific transactions within a slot
For most use cases, transaction or block subscriptions are simpler. Use entry monitoring when you need sub-block granularity or are building infrastructure that processes entries directly (e.g. a custom ledger parser).

Filter Parameters

Entry subscriptions do not support content-based filters — you receive all entries for the subscribed commitment level. The only configuration is the commitment level set on the subscription request.

Example: Stream All Entries

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 PING_INTERVAL_MS = 30_000;

const client = new Client(GRPC_URL, X_TOKEN, {
  "grpc.max_receive_message_length": 1024 * 1024 * 1024, // 1 GiB
});

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

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

  stream.on("data", (data) => {
    if (data.entry) {
      const { slot, index, numHashes, hash, transactions, startingTransactionIndex } = data.entry;
      console.log(`Entry [slot ${slot}, index ${index}]:`);
      console.log(`  Hash: ${Buffer.from(hash).toString("base64")}`);
      console.log(`  Num hashes: ${numHashes}`);
      console.log(`  Transactions in entry: ${transactions?.length ?? 0}`);
      console.log(`  Starting tx index: ${startingTransactionIndex}`);
    } else if (data.pong) {
      console.log("Pong received");
    }
  });

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

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

  setInterval(() => {
    stream.write({ ping: { id: 1 }, accounts: {}, accountsDataSlice: [], transactions: {}, transactionsStatus: {}, slots: {}, blocks: {}, blocksMeta: {}, entry: {} }, () => {});
  }, PING_INTERVAL_MS);

  await streamClosed;
}

main();

Entry Data Fields

FieldTypeDescription
slotuint64The slot this entry belongs to
indexuint64Position of this entry within the slot (0-indexed)
numHashesuint64Number of PoH hashes since the previous entry
hashbytesPoH hash for this entry
transactionsConfirmedTransaction[]Transactions included in this entry
startingTransactionIndexuint64Index of the first transaction in this entry within the block

Combining Entries with Other Subscriptions

Entries are rarely subscribed to in isolation. A common pattern is to combine an entry subscription with a slot subscription to know when a slot is finalized and then process its entries:
const request: SubscribeRequest = {
  entry: {
    entryStream: {},
  },
  slots: {
    slotUpdates: {
      filterByCommitment: true,
    },
  },
  commitment: CommitmentLevel.CONFIRMED,
  accounts: {},
  accountsDataSlice: [],
  transactions: {},
  transactionsStatus: {},
  blocks: {},
  blocksMeta: {},
};
This lets you buffer entries per slot and process them atomically once the slot reaches your target commitment level.