LaserStream 的 gRPC 提供基于 Yellowstone 的接口,并通过历史重播、多节点故障转移和完全托管环境等功能进行增强。LaserStream 使用开源的 gRPC 协议,确保没有供应商锁定,并与现有 gRPC 实现最大兼容。
您可以直接连接 @yellowstone-grpc 或使用更高级别的 Helius LaserStream SDK 以获得更多好处(自动重连、订阅管理、错误处理等)。
性能注意 :如果您在使用 LaserStream 连接时遇到任何延迟或性能问题,请参阅 故障排除部分 以获取与客户端性能和网络优化相关的常见原因和解决方案。
端点与区域
LaserStream 在全球多个区域可用。选择离您的应用程序最近的端点以获得最佳性能:
主网端点
区域 位置 端点 ewr 纽瓦克,新泽西(靠近纽约) https://laserstream-mainnet-ewr.helius-rpc.compitt 匹兹堡,美国(中部) https://laserstream-mainnet-pitt.helius-rpc.comslc 盐湖城,美国(西海岸) https://laserstream-mainnet-slc.helius-rpc.comlax 洛杉矶,美国(西海岸) https://laserstream-mainnet-lax.helius-rpc.comlon 伦敦,欧洲 https://laserstream-mainnet-lon.helius-rpc.comams 阿姆斯特丹,欧洲 https://laserstream-mainnet-ams.helius-rpc.comfra 法兰克福,欧洲 https://laserstream-mainnet-fra.helius-rpc.comtyo 东京,亚洲 https://laserstream-mainnet-tyo.helius-rpc.comsgp 新加坡,亚洲 https://laserstream-mainnet-sgp.helius-rpc.com
开发网端点
网络 位置 端点 开发网 纽瓦克,新泽西(靠近纽约) https://laserstream-devnet-ewr.helius-rpc.com
网络与区域选择 :
对于 生产应用程序 ,选择离您的服务器最近的主网端点以获得最佳性能。例如,如果在欧洲部署,请使用阿姆斯特丹 (ams) 或法兰克福 (fra) 端点。
对于 开发和测试 ,使用开发网端点:https://laserstream-devnet-ewr.helius-rpc.com。
快速开始
创建一个新项目
mkdir laserstream-grpc-demo
cd laserstream-grpc-demo
npm init -y
安装依赖
npm install helius-laserstream
npm install --save-dev typescript ts-node
npx tsc --init
获取您的 API 密钥
从 Helius Dashboard 生成一个密钥。此密钥将作为您对 LaserStream 的身份验证令牌。 计划要求 :LaserStream devnet 需要开发者或商业计划。LaserStream mainnet 需要专业计划。确保您的 Helius 账户具有适当的计划以访问 LaserStream 功能。
创建订阅脚本
创建 index.ts ,内容如下: import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {
client: {
accountInclude: [ 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ],
accountExclude: [],
accountRequired: [],
vote: false ,
failed: false
}
},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
// Optionally, you can replay missed data by specifying a fromSlot:
// fromSlot: '224339000'
// Note: Currently, you can only replay data from up to 3000 slots in the past.
};
// Replace the values below with your actual LaserStream API key and endpoint
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key from https://dashboard.helius.dev/
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
替换您的 API 密钥并选择您的区域
在 index.ts 中,更新 config 对象,包含以下内容:
您从 Helius Dashboard 获取的实际 API 密钥
离您的服务器位置最近的 LaserStream 端点
const config : LaserstreamConfig = {
apiKey: 'YOUR_ACTUAL_API_KEY' , // Replace with your key from Helius Dashboard
endpoint: 'https://laserstream-mainnet-fra.helius-rpc.com' , // Example: Frankfurt mainnet
// For devnet: endpoint: 'https://laserstream-devnet-ewr.helius-rpc.com'
}
网络和区域选择示例:
用于生产(Mainnet) :
欧洲:使用 fra(法兰克福)或 ams(阿姆斯特丹)
美国东部:使用 ewr(纽约)
美国西部:使用 slc(盐湖城)
亚洲:使用 tyo(东京)或 sgp(新加坡)
用于开发(Devnet) :使用 https://laserstream-devnet-ewr.helius-rpc.com
运行并查看结果
每当一个 confirmed 代币交易涉及 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA 时,您将在控制台中看到数据。
订阅请求
在订阅请求中,您需要包含以下通用参数:
历史重放: 您可以选择在主 SubscribeRequest 对象中包含一个 fromSlot: string 字段,以从特定槽位开始重放数据。目前,重放支持最多回溯 3000 个槽位。
const subscriptionRequest : SubscribeRequest = {
commitment: CommitmentLevel . CONFIRMED ,
accountsDataSlice: [],
transactions: {},
accounts: {},
slots: {},
blocks: {},
blocksMeta: {},
entry: {},
}
接下来,您需要指定要订阅的数据的过滤器,例如账户、区块、插槽或交易。
定义插槽更新的过滤器。您使用的键(例如,mySlotLabel)是此特定过滤器配置的用户定义标签 ,允许您在需要时定义多个命名配置(尽管通常一个就足够了)。 slots : {
// mySlotLabel is a user-defined name for this slot update filter configuration
mySlotLabel : {
// filterByCommitment: true => Only broadcast slot updates at the specified subscribeRequest commitment
filterByCommitment : true
// interslotUpdates: true allows receiving updates for changes occurring within a slot, not just new slots.
interslotUpdates : true
}
},
定义账户数据更新的过滤器。您使用的键(例如,tokenAccounts)是此特定过滤器配置的用户定义标签 。 如果所有字段为空,则广播所有账户。否则:
字段作为逻辑 AND 操作。
数组中的值作为逻辑 OR 操作(除了 filters,它们作为逻辑 AND 操作)。
accounts : {
// tokenAccounts is a user-defined label for this account filter configuration
tokenAccounts : {
// Matches any of these public keys (logical OR)
account : [ "9SHQTA66Ekh7ZgMnKWsjxXk6DwXku8przs45E8bcEe38" ],
// Matches owners that are any of these public keys
owner : [ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" ],
// Filters - all must match (AND logic)
filters : [
{ dataSize: 165 },
{
memcmp: {
offset: 0 ,
data: { base58: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" }
}
}
]
}
},
定义交易更新的过滤器。您使用的键(例如,myTxSubscription)是此特定过滤器配置的用户定义标签 。 如果所有字段都为空,则广播所有交易。否则:
字段作为逻辑 AND 操作。
数组中的值被视为逻辑 OR 操作(除了 accountRequired,其中所有必须匹配)。
transactions : {
// myTxSubscription is a user-defined label for this transaction filter configuration
myTxSubscription : {
vote : false ,
failed : false ,
signature : "" ,
// Transaction must include at least one of these public keys (OR)
accountInclude : [ "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" ],
// Exclude if it matches any of these
accountExclude : [],
// Require all accounts in this array (AND)
accountRequired : []
}
},
定义区块更新的过滤器。您使用的键(例如,myBlockLabel)是此特定过滤器配置的用户定义标签 。 blocks : {
// myBlockLabel is a user-defined label for this block filter configuration
myBlockLabel : {
// Only broadcast blocks referencing these accounts
accountInclude : [ "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" ],
includeTransactions : true ,
includeAccounts : false ,
includeEntries : false
}
},
订阅分类账条目。您使用的键(例如,entrySubscribe)是此订阅的用户定义标签 。目前,条目没有可用的过滤器;所有条目都会被广播。 entry : {
entrySubscribe : {}
},
代码示例 (LaserStream SDK)
Slot Updates
Account Updates
Transaction Updates
Blocks
Block Metadata
Entries
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {
slot: { filterByCommitment: true },
},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
accounts: {
accountSubscribe: {
account: [ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ], // USDC mint account
owner: [],
filters: []
}
},
accountsDataSlice: [],
commitment: CommitmentLevel . CONFIRMED ,
slots: {},
transactions: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {}
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
transactions: {
client: {
accountInclude: [ 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' ],
accountExclude: [],
accountRequired: [],
vote: false ,
failed: false
}
},
commitment: CommitmentLevel . CONFIRMED ,
accounts: {},
slots: {},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {
blocks: {
accountInclude: []
}
},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {
blockmetadata: {}
},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
import { subscribe , CommitmentLevel , LaserstreamConfig , SubscribeRequest } from 'helius-laserstream'
async function main () {
const subscriptionRequest : SubscribeRequest = {
entry: {
entrySubscribe: {} // Subscribe to all entries
},
accounts: {},
accountsDataSlice: [],
slots: {},
blocks: {},
blocksMeta: {},
transactions: {},
transactionsStatus: {},
commitment: CommitmentLevel . CONFIRMED ,
};
const config : LaserstreamConfig = {
apiKey: 'YOUR_API_KEY' , // Replace with your key
endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com' , // Choose your closest region
}
await subscribe ( config , subscriptionRequest , async ( data ) => {
console . log ( data );
}, async ( error ) => {
console . error ( error );
});
}
main (). catch ( console . error );
SDK 选项
我们为多种编程语言提供官方 SDK:
对于其他语言或自定义实现,您可以直接使用 Yellowstone gRPC proto 文件 来为您偏好的语言生成 gRPC 客户端。
故障排除 / 常见问题
Q: 我的 LaserStream 连接出现延迟或性能缓慢的问题。可能是什么原因导致的?
A: LaserStream 连接的性能问题通常由以下原因引起:
Javascript 客户端缓慢 :当处理过多消息或消耗过多带宽时,JavaScript 客户端可能会滞后。考虑更精确地过滤您的订阅以减少消息量,或使用其他语言。
本地带宽有限 :大量订阅可能会使带宽有限的客户端不堪重负。监控您的网络使用情况,考虑升级您的连接或减少订阅范围。
地理距离 :对地理位置较远的服务器运行订阅可能会导致性能问题。TCP 数据包可能在长距离路由中丢失,并且您受限于最慢的中间网络路径。解决方案 :从我们可用的区域中选择离您的服务器位置最近的 LaserStream 端点(参见上面的 Endpoints & Regions )。
客户端处理瓶颈 :确保您的消息处理逻辑已优化,并且不会长时间阻塞主线程。
调试客户端延迟 :为了帮助您调试客户端,我们构建了一个工具来测试从您的节点到 Laserstream gRPC 服务器的最大带宽。要使用它,请运行:cargo install helius-laserstream-bandwidth
helius-laserstream-bandwidth --laserstream-url $LASERSTREAM_URL --api-key $API_KEY
输出将返回您的服务器与 Laserstream 服务器之间的最大网络容量。最低限度,您需要 10MB/s 来订阅所有交易数据,80MB/s 来订阅所有账户数据。我们建议至少拥有所需容量的 2 倍以获得最佳性能。
A: 验证您的 API 密钥和端点是否正确,并确保您的网络允许到指定端点的出站 gRPC 连接。检查 Helius 状态页面 以了解任何正在进行的事件。
A: 请仔细检查过滤器部分中描述的逻辑运算符(AND/OR)。确保公钥正确。查看请求中指定的承诺级别。
Q: 我可以在一个请求中订阅多种类型的数据(例如,账户和交易)吗?
A: 可以,您可以在同一个SubscribeRequest对象中定义多个键下的过滤器配置(例如,accounts, transactions)。
A: 我们没有实现消费者组。相反,LaserStream 提供团队所需的相同结果:恢复、重放和多节点可靠性,而无需协调层(以及随之而来的延迟/开销)。我们认为大多数工作负载不需要消费者组,它们会增加延迟和操作开销。例如,单个 LaserStream gRPC 连接可以发出高达 Solana 交易 + 账户数据的 10 倍,并且大多数客户端订阅一个小的、过滤后的片段。在这种情况下使用消费者组会消耗性能余量并引入另一个故障点。