helius-laserstream SDK 实时跟踪时隙进度、区块最终确认情况和网络性能指标。
前提条件: 本指南假设你已完成 LaserStream gRPC 快速入门并拥有 API 密钥。
监控类型
- Slot Updates
- Block Data
- Block Metadata
跟踪网络共识进度监控不同确认级别的时隙进展:时隙数据包括: 时隙编号、父时隙、确认状态(
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
const subscriptionRequest: SubscribeRequest = {
slots: {
slotSubscribe: {
filterByCommitment: false // Receive all commitment levels
}
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {}, transactions: {}, transactionsStatus: {},
blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
};
processed / confirmed / finalized)和领导者信息。最适合: 网络健康状况监控、时隙时间分析、共识跟踪。
监控完整区块信息以流的形式获取包含交易和账户更新的完整区块:区块数据包括: 区块元数据、交易、账户更新、区块时间。
const subscriptionRequest: SubscribeRequest = {
blocks: {
blockSubscribe: {
accountInclude: [], // All accounts
includeTransactions: true,
includeAccounts: true,
includeEntries: false
}
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {}, transactions: {}, transactionsStatus: {},
slots: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
};
数据量较大: 完整区块流会产生大量数据。请使用
accountInclude 过滤器减少数据量。轻量级区块信息获取不含交易详情的区块元数据:元数据包括: 区块哈希、父区块哈希、时隙、高度、交易数量、奖励。
const subscriptionRequest: SubscribeRequest = {
blocksMeta: {
blockMetaSubscribe: {}
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {}, transactions: {}, transactionsStatus: {},
slots: {}, blocks: {}, entry: {}, accountsDataSlice: [],
};
高效: 完整区块流的低带宽替代方案。
实用示例
示例 1:网络健康状况监控器
跟踪时隙进度并识别网络问题:import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
let lastSlot = 0;
let lastTimestamp = Date.now();
const slotTimes: number[] = [];
// CommitmentLevel only ships the forward (name → number) mapping, so we keep
// a small reverse lookup for the numeric status the SDK returns on slot updates.
const STATUS_NAMES = ['PROCESSED', 'CONFIRMED', 'FINALIZED'] as const;
async function monitorNetworkHealth() {
const subscriptionRequest: SubscribeRequest = {
slots: {
slotSubscribe: {
filterByCommitment: true // Track processed commitment levels
}
},
commitment: CommitmentLevel.PROCESSED,
accounts: {}, transactions: {}, transactionsStatus: {},
blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY',
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
};
await subscribe(config, subscriptionRequest, async (data) => {
if (!data.slot) return;
const slot = data.slot;
// The SDK returns u64 fields as strings to preserve precision.
const currentSlot = Number(slot.slot);
const currentTime = Date.now();
console.log(`\n📊 Slot Update:`);
console.log(` Slot: ${currentSlot}`);
console.log(` Parent: ${slot.parent}`);
// slot.status is a numeric enum (0=processed, 1=confirmed, 2=finalized).
console.log(` Status: ${STATUS_NAMES[slot.status] ?? slot.status}`);
if (lastSlot > 0) {
const slotDiff = currentSlot - lastSlot;
const timeDiff = currentTime - lastTimestamp;
if (slotDiff === 1) {
slotTimes.push(timeDiff);
if (slotTimes.length > 100) slotTimes.shift();
const avg = slotTimes.reduce((a, b) => a + b, 0) / slotTimes.length;
console.log(` Slot Time: ${timeDiff}ms`);
console.log(` Avg Slot Time: ${avg.toFixed(1)}ms`);
if (timeDiff > 800) {
console.log(` ⚠️ SLOW SLOT: ${timeDiff}ms (normal ~400ms)`);
}
} else if (slotDiff > 1) {
console.log(` ⚠️ SKIPPED ${slotDiff - 1} SLOTS`);
}
}
lastSlot = currentSlot;
lastTimestamp = currentTime;
}, async (error) => {
console.error('Stream error:', error);
});
}
monitorNetworkHealth().catch(console.error);
示例 2:区块生成监控器
跟踪区块生成和交易量:async function monitorBlockProduction() {
const subscriptionRequest: SubscribeRequest = {
blocksMeta: {
blockMetaSubscribe: {}
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {}, transactions: {}, transactionsStatus: {},
slots: {}, blocks: {}, entry: {}, accountsDataSlice: [],
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY',
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
};
await subscribe(config, subscriptionRequest, async (data) => {
if (!data.blockMeta) return;
const blockMeta = data.blockMeta;
console.log(`\n🧱 Block Produced:`);
console.log(` Slot: ${blockMeta.slot}`);
// blockHeight is a wrapper object: { blockHeight: '397657352' }
console.log(` Block Height: ${blockMeta.blockHeight?.blockHeight}`);
console.log(` Block Hash: ${blockMeta.blockhash}`);
console.log(` Parent Slot: ${blockMeta.parentSlot}`);
console.log(` Parent Hash: ${blockMeta.parentBlockhash}`);
console.log(` Transactions: ${blockMeta.executedTransactionCount}`);
console.log(` Entries: ${blockMeta.entriesCount}`);
if (blockMeta.blockTime?.timestamp) {
// blockTime.timestamp is a u64 as a string (Unix seconds).
console.log(` Block Time: ${new Date(Number(blockMeta.blockTime.timestamp) * 1000).toISOString()}`);
}
// rewards is a wrapper object: { rewards: [...], numPartitions: number | null }
if (blockMeta.rewards?.rewards?.length > 0) {
console.log(` Rewards:`);
blockMeta.rewards.rewards.forEach((r: any) => {
console.log(` ${r.pubkey}: ${r.lamports} lamports (${r.rewardType})`);
});
}
if (Number(blockMeta.executedTransactionCount) > 3000) {
console.log(` 🔥 HIGH ACTIVITY: ${blockMeta.executedTransactionCount} transactions`);
}
}, async (error) => {
console.error('Stream error:', error);
});
}
示例 3:筛选后的区块监控器
监控包含特定程序活动的区块:async function monitorDEXBlocks() {
const subscriptionRequest: SubscribeRequest = {
blocks: {
blockSubscribe: {
accountInclude: [
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", // Raydium
"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK", // Raydium CLMM
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4" // Jupiter
],
includeTransactions: true,
includeAccounts: false,
includeEntries: false
}
},
commitment: CommitmentLevel.CONFIRMED,
accounts: {}, transactions: {}, transactionsStatus: {},
slots: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
};
const config: LaserstreamConfig = {
apiKey: 'YOUR_API_KEY',
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
};
await subscribe(config, subscriptionRequest, async (data) => {
if (!data.block) return;
const block = data.block;
let successfulDexTx = 0;
let totalFees = 0; // lamports
block.transactions?.forEach((tx: any) => {
if (tx.meta && !tx.meta.err) {
successfulDexTx++;
// tx.meta.fee is a u64 string — coerce before adding.
totalFees += Number(tx.meta.fee ?? 0);
}
});
console.log(`\n🔄 DEX Activity Block:`);
console.log(` Slot: ${block.slot}`);
console.log(` Block Height: ${block.blockHeight?.blockHeight}`);
console.log(` Block Hash: ${block.blockhash}`);
console.log(` Total transactions in block: ${block.executedTransactionCount}`);
console.log(` Matched DEX transactions: ${block.transactions?.length ?? 0}`);
console.log(` Successful DEX transactions: ${successfulDexTx}`);
if (successfulDexTx > 0) {
console.log(` Total Fees: ${(totalFees / 1e9).toFixed(4)} SOL`);
console.log(` Avg Fee: ${(totalFees / successfulDexTx / 1e9).toFixed(6)} SOL`);
}
}, async (error) => {
console.error('Stream error:', error);
});
}
数据结构
Slot Data Structure
Slot Data Structure
{
slot: string; // Current slot number (u64 as string)
parent: string; // Parent slot number (u64 as string)
status: number; // CommitmentLevel enum: 0 = processed, 1 = confirmed, 2 = finalized
}
processed(初始)、confirmed(获得绝大多数投票)、finalized(不可逆)。u64 字段(slot、parent)会以字符串形式传入,以在超出
Number.MAX_SAFE_INTEGER 后保持精度。需要进行算术运算时,请使用 Number(slot.slot) 转换。status 是数值枚举;请使用 CommitmentLevel[slot.status] 获取人类可读的名称。Block Metadata Structure
Block Metadata Structure
{
slot: string; // u64 as string
blockhash: string;
rewards: {
rewards: Array<{
pubkey: string;
lamports: string; // u64 as string
rewardType: string; // "fee" | "rent" | "voting" | "staking"
}>;
numPartitions: number | null;
};
blockTime: { timestamp: string }; // Unix seconds as a u64 string
blockHeight: { blockHeight: string }; // u64 as string, wrapped
parentSlot: string; // u64 as string
parentBlockhash: string;
executedTransactionCount: string; // u64 as string
entriesCount: string; // u64 as string
}
数值字段(slot、parentSlot、executedTransactionCount、entriesCount,以及
blockHeight 和 blockTime 中的值)会以字符串形式输出,因为它们在底层 proto 中是 u64。进行算术运算或比较时,请使用 Number(...) 包装它们。Full Block Structure
Full Block Structure
{
slot: string; // u64 as string
blockhash: string;
rewards: {
rewards: Array<{
pubkey: string;
lamports: string; // u64 as string
rewardType: string;
}>;
numPartitions: number | null;
};
blockTime: { timestamp: string }; // Unix seconds (u64 string)
blockHeight: { blockHeight: string }; // u64 as string, wrapped
parentSlot: string; // u64 as string
parentBlockhash: string;
executedTransactionCount: string; // total executed tx in the block (u64 as string)
updatedAccountCount: string; // total account updates in the block (u64 as string)
entriesCount: string; // u64 as string
transactions: Array<{
signature: Buffer; // base58-encode for display
isVote: boolean;
transaction: TransactionMessage; // full transaction payload
meta: TransactionMeta; // execution metadata (fee, err, balances, …)
index: string; // u64 as string
}>;
accounts: AccountUpdate[]; // populated when includeAccounts: true
entries: Entry[]; // populated when includeEntries: true
}
Number(...) 包装数值字段。在每笔交易中,meta.fee、meta.preBalances、meta.postBalances 等也都是字符串。性能注意事项
Slot Monitoring
轻量级:带宽占用极低,处理开销很小。适用于监控仪表板。
Block Metadata
均衡:带宽占用适中,无需完整数据即可获得区块级洞察。适用于分析。
Full Blocks
数据量较大:包含完整交易数据,需要强大的处理能力。务必搭配过滤器使用。
Filtered Blocks
优化:使用
accountInclude,并禁用不需要的 includeAccounts/includeEntries。使用场景
- Network Monitoring
- Analytics & Metrics
- Application Synchronization
跟踪网络健康状况和性能,包括时隙时间、拥塞和共识。
const targetSlotTime = 400; // ms
const tolerance = 200; // ms
if (Math.abs(slotTime - targetSlotTime) > tolerance) {
console.log(`Network performance issue detected`);
}
收集区块链分析数据,包括交易量、费用分析、区块大小和活动模式。
const dailyStats = {
date: new Date().toDateString(),
totalTransactions: 0,
totalFees: 0,
blockCount: 0
};
使应用程序与网络保持同步,包括基于时隙的更新和区块确认。
if (data.slot && data.slot.status === 'finalized') {
updateApplicationState(data.slot.slot);
}
错误处理
Missing Slots
Missing Slots
High Volume
High Volume
症状: 区块数据过多。解决方案: 使用区块元数据代替完整区块;应用账户过滤器;禁用不必要的数据(条目、账户);进行异步处理。
Timing Issues
Timing Issues
症状: 时隙时间不一致。分析: 计算移动平均值;跟踪偏差;监控网络健康指标;与验证器性能进行关联分析。
最佳实践
生产环境准则:
- 从元数据开始 — 订阅完整区块之前,先使用区块元数据
- 应用过滤器 — 使用
accountInclude丢弃无关数据 - 监控时间 — 跟踪时隙进度,将其用作网络健康状况的预警指标
- 处理缺口 — 与历史重放结合使用,以便重新连接时自动回填缺失的时隙
- 异步处理 — 不要让繁重的计算阻塞流处理
- 根据需求选择确认级别 — 低延迟 UI 使用
processed,状态写入使用confirmed/finalized
后续步骤
Transaction Monitoring
按程序、账户、投票或失败状态筛选交易。
Stream Pump AMM Data
实际示例:监控 Pump AMM 交易。
Decoding Transaction Data
将二进制
transactionUpdate 载荷解析为可读的 Solana 交易。Yellowstone protocol reference
使用原始 Yellowstone gRPC 协议实现相同的工作流。