Что такое записи?
Записи — это базовые единицы выполнения внутри блока Solana. Каждый блок состоит из одной или нескольких записей, где каждая запись содержит пакет транзакций, выполненных последовательно. Записи представляют собой наиболее детальный уровень данных блока — ниже блоков и выше отдельных транзакций.
Мониторинг записей полезен для:
- Построения пользовательских парсеров блоков, требующих точного порядка транзакций
- Восстановления порядка выполнения внутри блока
- Низколатентного обнаружения конкретных транзакций внутри слота
Для большинства сценариев подписки на транзакции или блоки проще. Используйте мониторинг записей только при необходимости суб-блочной детализации или при построении инфраструктуры, обрабатывающей записи напрямую (например, пользовательский парсер реестра).
Параметры фильтрации
Подписки на записи не поддерживают фильтры на основе содержимого — вы получаете все записи для подписанного уровня подтверждения. Единственная настройка — уровень подтверждения в запросе подписки.
Пример: Потоковая передача всех записей
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();
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.entry) {
const { slot, index, numHashes, hash, transactions, startingTransactionIndex } = data.entry;
console.log(`Запись [слот ${slot}, индекс ${index}]:`);
console.log(` Хеш: ${Buffer.from(hash).toString("base64")}`);
console.log(` Количество хешей: ${numHashes}`);
console.log(` Транзакций в записи: ${transactions?.length ?? 0}`);
console.log(` Начальный индекс транзакции: ${startingTransactionIndex}`);
} else if (data.pong) {
console.log("Получен pong");
}
});
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: {} }, () => {});
}, 30_000);
await streamClosed;
}
main();
Поля данных записи
| Поле | Тип | Описание |
|---|
slot | uint64 | Слот, которому принадлежит эта запись |
index | uint64 | Позиция записи в слоте (начиная с 0) |
numHashes | uint64 | Количество хешей PoH с предыдущей записи |
hash | bytes | Хеш PoH для этой записи |
transactions | ConfirmedTransaction[] | Транзакции, включённые в эту запись |
startingTransactionIndex | uint64 | Индекс первой транзакции этой записи в блоке |
Комбинирование записей с другими подписками
Записи редко используются как единственная подписка. Распространённый паттерн — комбинирование подписки на записи с подпиской на слоты:
const request: SubscribeRequest = {
entry: {
entryStream: {},
},
slots: {
slotUpdates: {
filterByCommitment: true,
},
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {},
accountsDataSlice: [],
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
};
Это позволяет буферизировать записи по слотам и обрабатывать их атомарно, как только слот достигнет целевого уровня подтверждения.