getProgramAccounts RPC 方法是查询 Solana 区块链的强大工具。它允许您检索由特定链上程序拥有的所有账户。这对于多种应用程序至关重要,从查找与特定代币铸造相关的所有用户代币账户,到发现去中心化应用程序的所有用户特定数据账户。
由于程序可能拥有的大量账户,getProgramAccounts 提供了强大的过滤功能,帮助您缩小搜索范围,仅高效检索所需数据。
对于需要查询非常大程序账户集的应用程序,请考虑使用 getProgramAccountsV2,该方法提供基于游标的分页支持,每次请求最多可配置 10,000 个账户。
常见用例
- 查找铸币的所有代币账户: 发现特定 SPL 代币的所有持有者。
- 检索用户特定数据: 获取程序为特定用户创建的所有账户(例如,用户在 DeFi 协议中的头寸,或他们在游戏中的状态)。
- 列出自定义账户类型的所有实例: 如果您的程序定义了特定账户结构,
getProgramAccounts可以找到该结构的所有实例。 - 监控程序状态: 观察与程序相关的所有账户,以跟踪其整体状态或活动。
- 构建探查器和分析工具: 聚合有关程序及其关联账户的数据。
请求参数
-
programId(string, 必需):- 您要获取其账户的程序的 base-58 编码公钥。
- 示例:
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"(用于 SPL 代币程序)。
-
options(object, 可选项): 包含以下字段的配置对象:commitment(string): 指定承诺级别(例如,"finalized","confirmed")。encoding(string): 每个返回账户中data字段的编码。默认为"base64"。"base58": 较慢的二进制数据替代方案。"base64": 标准的base64编码用于二进制数据。"base64+zstd": base64编码的zstd压缩二进制数据。"jsonParsed": 如果RPC节点有程序账户类型的解析器(例如,SPL Token,Stake),则data字段将是一个结构化的JSON对象。这对于可读性和易用性非常推荐。
filters(array): 要应用于账户的过滤器对象数组。这对于性能和相关性至关重要。你最多可以使用4个过滤器。常见的过滤器包括:dataSize(object):dataSize(u64): 按字节过滤账户的数据长度。示例:{ "dataSize": 165 }(用于SPL Token账户)。
memcmp(object): 内存比较。将账户数据的切片与提供的字节进行比较。offset(usize): 开始比较的账户数据的字节偏移量。bytes(string): 要匹配的字节的base-58编码字符串。字节字符串必须小于129字节。- 示例: 要查找特定铸币的代币账户,可以使用
memcmp与offset: 0(其中铸币地址存储在代币账户中) 和bytes设置为铸币的公钥。
dataSlice(object): 仅返回每个账户数据的特定切片。当您只需要部分数据时,这对大账户非常有用。offset(usize): 开始切片的字节偏移量。length(usize): 要返回的字节数。- 注意:
dataSlice主要用于二进制编码,而非jsonParsed。
withContext(boolean): 如果true, 则响应将是一个RpcResponse对象,包含一个context(带有slot) 和value(账户数组)。如果false或省略,通常只返回账户数组。行为可能因RPC提供商而略有不同。minContextSlot(u64): 可以评估请求的最小槽位。
响应结构
响应是一个对象数组,其中每个对象代表一个找到的账户,并包括:pubkey(string): 账户的 base-58 编码公钥。account(object):lamports(u64): 账户以 lamports 为单位的余额。owner(string): 拥有此账户的程序的 base-58 编码公钥(这将是您查询的programId)。data(string,array, 或object): 根据encoding参数格式化的账户数据。- 对于
jsonParsed: 表示反序列化账户状态的 JSON 对象。 - 对于
base64: 一个数组["encoded_string", "base64"]。
- 对于
executable(boolean): 账户是否可执行(即自身为程序)。rentEpoch(u64): 此账户下次欠租的纪元。space(u64, 可选): 账户数据的字节长度。如果数据是缓冲区,或作为解析结构的一部分,有时称为data.length。
withContext: true,这个数组将嵌套在 value 字段中的 RpcResponse 对象中。
示例
1. 查找特定铸币(USDC)的所有代币账户
此示例查找持有 USDC 的所有 SPL 代币账户。它使用dataSize 过滤代币账户(165 字节)并使用 memcmp 匹配在偏移量 0 的 USDC 铸币地址。
2. 查找由特定钱包拥有的所有代币账户
此示例查找由特定钱包地址拥有的所有 SPL 代币账户。它使用dataSize(165 字节)和 memcmp 在偏移量 32(所有者公钥存储在令牌账户中的位置)。
高级过滤
使用过滤器优化查询以减少响应大小并提高性能:API Reference
getProgramAccounts
过滤器类型
memcmp: 过滤在特定偏移处匹配特定模式的账户dataSize: 按账户的精确数据大小进行过滤- 多重过滤器:所有条件必须满足(逻辑与)
开发者提示
- 性能:
getProgramAccounts在没有过滤器或程序拥有许多账户时,可能对RPC节点资源消耗较大。务必使用过滤器(dataSize,memcmp)和dataSlice来减少查询范围和响应大小。 - 大结果集: 对于返回许多结果的查询,响应可能会被截断或超时。使用过滤减少范围,或考虑使用
getProgramAccountsV2进行分页支持。 - 速率限制: 注意RPC提供商的速率限制,因为频繁或大量的
getProgramAccounts调用可能会达到这些限制。 - 数据布局知识: 有效使用
memcmp需要了解您正在查询的账户数据的字节布局。 jsonParsed可用性:jsonParsed编码依赖于RPC节点是否有特定程序账户类型的解析器。对于常见程序,如SPL Token,广泛支持。
getProgramAccounts 是开发人员需要查询和交互程序所拥有账户集的重要方法。掌握其过滤选项是构建高效稳健的Solana应用程序的关键。
大数据集的分页
对于处理拥有大量账户(10,000+)的程序的应用,使用getProgramAccountsV2,该方法提供:
- 基于游标的分页: 设置
limit(1-10,000)并使用paginationKey导航结果 - 增量更新: 使用
changedSinceSlot仅获取自特定槽以来修改的账户 - 更好的性能: 防止超时和减少内存使用
- 分页行为: 只有在不返回账户时才表示分页结束。由于过滤,返回的账户可能少于限制 - 继续分页直到
paginationKey为null