Yellowstone gRPC 提供两种相关但不同的订阅类型来追踪网络进度:
- Slot — 轻量级更新,指示 Slot 何时达到
processed、confirmed 或 finalized 承诺。低带宽,适合共识监控。
- 区块 — 完整区块数据,包括交易、账户更新和条目。较高带宽,适合索引器和分析。
Slot 订阅
过滤参数
| 参数 | 类型 | 描述 |
|---|
filterByCommitment | boolean | 为 true 时,仅发出与订阅承诺级别匹配的 Slot 更新。为 false(默认)时,发出所有承诺级别的更新。 |
interslotUpdates | boolean | 为 true 时,发出 Slot 内的状态变化,而不仅仅是 Slot 边界。适合精细的实时监控。 |
示例:追踪已确认 Slot
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 ${slot}(父 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();
区块订阅
过滤参数
| 参数 | 类型 | 描述 |
|---|
accountInclude | string[] | 过滤区块内的交易和账户更新,仅包含这些账户。 |
includeTransactions | boolean | 在每个区块更新中包含完整交易数据。 |
includeAccounts | boolean | 在每个区块更新中包含账户状态更新。 |
includeEntries | boolean | 在每个区块更新中包含条目(执行单元)。 |
启用 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(`区块 Slot: ${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();
如何选择 Slot 与区块订阅
| 需求 | 使用 |
|---|
| 检测 Slot 何时最终确定 | Slot 订阅(filterByCommitment: true) |
| 追踪区块高度进度 | Slot 订阅 |
| 索引区块中的所有交易 | 区块订阅(includeTransactions: true) |
| 监控每个区块的账户状态变化 | 区块订阅(includeAccounts: true) |
| 最低延迟共识信号 | processed 级别的 Slot 订阅 |
| 完整归档质量区块数据 | finalized 级别的区块订阅 |