跳转到主要内容

参数

programId
string
必填
程序公钥(base-58 编码)
config
object

响应

result
array
账户信息对象数组
pubkey
string
账户公钥(base-58 编码)
account
object
data
array
指定编码格式的账户数据
executable
boolean
账户是否可执行
lamports
number
账户余额(以 lamports 为单位)
owner
string
账户所有者(base-58 编码)
rentEpoch
number
账户下次需要支付租金的 epoch

代码示例

基本请求

curl https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getProgramAccounts",
  "params": [
    "PROGRAM_ID"
  ]
}'

带过滤器的请求

curl https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getProgramAccounts",
  "params": [
    "PROGRAM_ID",
    {
      "filters": [
        {
          "dataSize": 165
        },
        {
          "memcmp": {
            "offset": 0,
            "bytes": "BASE58_ENCODED_BYTES"
          }
        }
      ]
    }
  ]
}'

使用 web3.js

import { Connection, PublicKey } from '@solana/web3.js';

const connection = new Connection('https://fra.rpc.orbitflare.com?api_key=YOUR-API-KEY');

// Get all program accounts
const accounts = await connection.getProgramAccounts(
  new PublicKey('PROGRAM_ID')
);
console.log('Accounts:', accounts);

// Get filtered program accounts
async function getFilteredProgramAccounts(
  programId: PublicKey,
  filters: any[]
) {
  const accounts = await connection.getProgramAccounts(programId, {
    filters
  });
  
  return accounts.map(({ pubkey, account }) => ({
    pubkey: pubkey.toBase58(),
    data: account.data,
    lamports: account.lamports,
    owner: account.owner.toBase58(),
    executable: account.executable
  }));
}

注意事项

  1. 返回特定程序拥有的所有账户
  2. 可以应用过滤器缩小结果范围
  3. 可以对账户数据进行切片以减少响应大小
  4. 响应是即时的,因为它从当前状态读取
  5. 可以为账户数据指定不同的编码格式

最佳实践

  1. 使用过滤器高效查询特定账户
  2. 考虑使用 dataSlice 减少响应大小
  3. 在适当时缓存结果以减少 RPC 负载
  4. 使用分页处理大型结果集
  5. 根据需求使用适当的编码格式

常见错误

错误码消息解决方案
-32601Method not found验证是否连接到 Solana RPC 节点
-32602Invalid params检查 programId 和配置参数
-32007Account information unavailable节点可能正在启动或同步中

用例

  1. 程序账户分析
    interface ProgramAccountAnalysis {
      pubkey: string;
      dataSize: number;
      dataHash: string;
      lamports: number;
      metadata: {
        timestamp: number;
      };
    }
    
    async function analyzeProgramAccounts(
      programId: PublicKey,
      filters?: any[]
    ): Promise<ProgramAccountAnalysis[]> {
      const accounts = await connection.getProgramAccounts(programId, {
        filters,
        encoding: 'base64'
      });
      
      return accounts.map(({ pubkey, account }) => {
        const data = account.data[0];
        const dataSize = Buffer.from(data, 'base64').length;
        
        return {
          pubkey: pubkey.toBase58(),
          dataSize,
          dataHash: require('crypto')
            .createHash('sha256')
            .update(data)
            .digest('hex'),
          lamports: account.lamports,
          metadata: {
            timestamp: Date.now()
          }
        };
      });
    }
    
  2. 程序账户监控
    interface ProgramAccountChange {
      pubkey: string;
      type: 'created' | 'deleted' | 'modified';
      previous: any;
      current: any;
      difference: number;
    }
    
    class ProgramAccountMonitor {
      private previousAccounts: Map<string, any> = new Map();
      
      async monitorProgramAccounts(
        programId: PublicKey,
        filters?: any[],
        interval: number = 5000
      ): Promise<ProgramAccountChange[]> {
        const accounts = await connection.getProgramAccounts(programId, {
          filters
        });
        const changes: ProgramAccountChange[] = [];
        
        accounts.forEach(({ pubkey, account }) => {
          const address = pubkey.toBase58();
          const current = account;
          const previous = this.previousAccounts.get(address);
          
          if (!previous && current) {
            changes.push({
              pubkey: address,
              type: 'created',
              previous: null,
              current,
              difference: current.lamports
            });
          } else if (previous && !current) {
            changes.push({
              pubkey: address,
              type: 'deleted',
              previous,
              current: null,
              difference: -previous.lamports
            });
          } else if (previous && current) {
            const difference = current.lamports - previous.lamports;
            if (difference !== 0 || current.data[0] !== previous.data[0]) {
              changes.push({
                pubkey: address,
                type: 'modified',
                previous,
                current,
                difference
              });
            }
          }
          
          this.previousAccounts.set(address, current);
        });
        
        return changes;
      }
    }
    
  3. 程序账户分页
    interface ProgramAccountPage {
      accounts: Array<{
        pubkey: string;
        data: any;
        lamports: number;
      }>;
      total: number;
      page: number;
      pageSize: number;
      metadata: {
        timestamp: number;
      };
    }
    
    async function getProgramAccountPage(
      programId: PublicKey,
      page: number = 1,
      pageSize: number = 100,
      filters?: any[]
    ): Promise<ProgramAccountPage> {
      const accounts = await connection.getProgramAccounts(programId, {
        filters,
        encoding: 'base64'
      });
      
      const start = (page - 1) * pageSize;
      const end = start + pageSize;
      const pageAccounts = accounts.slice(start, end);
      
      return {
        accounts: pageAccounts.map(({ pubkey, account }) => ({
          pubkey: pubkey.toBase58(),
          data: account.data[0],
          lamports: account.lamports
        })),
        total: accounts.length,
        page,
        pageSize,
        metadata: {
          timestamp: Date.now()
        }
      };
    }