mcpField
D
data

data

github.com/stellar数据与数据库55359 次安装1 周前更新
代码仓库

关于 data

面向开发者的参考技能,介绍如何选择 Stellar RPC 或 Horizon 来查询 Stellar 链上数据,涵盖实时状态、事件、交易流程及更深入的历史数据选项。

主要功能

  1. 01查询账户和账本状态
  2. 02模拟并提交交易
  3. 03读取事件和交易结果
  4. 04使用 Horizon 处理旧版需求与历史数据
  5. 05了解历史数据来源

适用场景

  1. 01使用 RPC 构建 Stellar 新应用
  2. 02维护依赖 Horizon 的应用
  3. 03检查近期合约事件和状态
  4. 04查找超出 RPC 保留期限的数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/stellar/stellar-dev-skill --skill data

安装后在 Claude Code 中输入/data确认已加载。

附带文件horizon.md

详细介绍

Stellar Data:RPC + Horizon

用于读取链上状态的 API 访问方式。Stellar RPC 是新项目的首选入口;Horizon 则继续用于传统工作流和历史查询工作流。若要查询超出 RPC 7 天范围的更深层历史记录,请使用 Hubble/Galexie。

何时使用此技能

  • 调用 Stellar RPC 方法(getLatestLedger、getLedgerEntries、getEvents、simulateTransaction、sendTransaction)
  • 查询 Horizon 端点(账户、交易、操作、效果、账本)
  • 实时流式传输事件或操作
  • 拉取超出 RPC 7 天范围的历史数据(Hubble、Galexie)
  • 为给定工作流选择 RPC 或 Horizon

相关技能

  • 构建要发送的交易 → ../dapp/SKILL.md
  • 智能合约模拟和事件发出 → ../smart-contracts/SKILL.md
  • 资产余额和信任线查询 → ../assets/SKILL.md
  • 标准(SEP-7 深度链接、SEP-10 身份验证)→ ../standards/SKILL.md

概述

Stellar 提供两种 API 范式:

API状态使用场景
Stellar RPC首选智能合约、实时状态、新项目
Horizon面向传统应用历史数据、传统应用

建议:所有新项目都使用 Stellar RPC。Horizon 主要用于历史查询和传统兼容路径。

阅读与任务相匹配的文件

任务文件
RPC 方法和用法Stellar RPC(下文)
Horizon 端点、常见操作、流式传输、分页horizon.md
迁移策略迁移:从 Horizon 到 RPC(下文)
历史数据/索引选项历史数据访问(下文)
环境设置和端点网络配置(下文)

Stellar RPC

端点

注意:SDF 直接提供 Futurenet 公共 RPC。对于 Mainnet RPC,请从 RPC 提供商目录 中选择提供商。

网络RPC URL
Mainnet提供商专属端点(参见 RPC 提供商目录)
Testnethttps://soroban-testnet.stellar.org
Futurenethttps://rpc-futurenet.stellar.org
Localhttp://localhost:8000/soroban/rpc
设置
import * as StellarSdk from "@stellar/stellar-sdk";

const rpc = new StellarSdk.rpc.Server("https://soroban-testnet.stellar.org");
主要方法
获取账户
const account = await rpc.getAccount(publicKey);
// Returns account with sequence number for transaction building
获取运行状况
const health = await rpc.getHealth();
// { status: "healthy" }
获取最新账本
const ledger = await rpc.getLatestLedger();
// { id: "...", sequence: 123456, protocolVersion: 25 }
获取账本条目
// Read contract storage
const key = StellarSdk.xdr.LedgerKey.contractData(
  new StellarSdk.xdr.LedgerKeyContractData({
    contract: new StellarSdk.Address(contractId).toScAddress(),
    key: StellarSdk.xdr.ScVal.scvSymbol("Counter"),
    durability: StellarSdk.xdr.ContractDataDurability.persistent(),
  })
);

const entries = await rpc.getLedgerEntries(key);
if (entries.entries.length > 0) {
  const value = StellarSdk.scValToNative(
    entries.entries[0].val.contractData().val()
  );
}
模拟交易
const simulation = await rpc.simulateTransaction(transaction);

if (StellarSdk.rpc.Api.isSimulationError(simulation)) {
  console.error("Simulation failed:", simulation.error);
} else if (StellarSdk.rpc.Api.isSimulationSuccess(simulation)) {
  console.log("Cost:", simulation.cost);
  console.log("Result:", simulation.result);
}
发送交易
const response = await rpc.sendTransaction(signedTransaction);

if (response.status === "PENDING") {
  // Poll for result
  let result = await rpc.getTransaction(response.hash);
  while (result.status === "NOT_FOUND") {
    await new Promise(r => setTimeout(r, 1000));
    result = await rpc.getTransaction(response.hash);
  }

  if (result.status === "SUCCESS") {
    console.log("Success:", result.returnValue);
  } else {
    console.error("Failed:", result.status);
  }
}
获取交易
const tx = await rpc.getTransaction(txHash);
// status: "SUCCESS" | "FAILED" | "NOT_FOUND"
// returnValue: ScVal (for contract calls)
// ledger: number
获取事件
const events = await rpc.getEvents({
  startLedger: 1000000,
  filters: [
    {
      type: "contract",
      contractIds: [contractId],
      topics: [
        ["*", StellarSdk.xdr.ScVal.scvSymbol("transfer").toXDR("base64")],
      ],
    },
  ],
});

for (const event of events.events) {
  console.log("Event:", event.topic, event.value);
}
RPC 的限制
  • 大多数方法仅支持 7 天历史记录:getTransaction、getEvents 等方法仅涵盖近期数据
  • getLedgers 例外:对于由数据湖支持的提供商,“无限滚动”可回溯到保留期限之前,最远可达该提供商的数据湖范围(可能追溯至创世账本)。对于普通 RPC 实例,范围受 getHealth().oldestLedger 限制;查询更早的数据会失败并返回 -32600。请先检查,勿假定其可查询更深的历史。
  • 不支持流式传输:轮询更新(不支持 WebSocket)
  • 面向合约:经典 Stellar 数据有限

迁移:从 Horizon 到 RPC

加载账户
// Horizon (old)
const account = await horizonServer.loadAccount(publicKey);

// RPC (new)
const account = await rpc.getAccount(publicKey);
// Note: RPC returns less data, just what's needed for transactions
提交交易
// Horizon (for classic transactions)
const result = await horizonServer.submitTransaction(tx);

// RPC (for smart contract transactions)
const response = await rpc.sendTransaction(tx);
const result = await pollForResult(response.hash);
历史数据
// Horizon - full history
const allTxs = await horizonServer
  .transactions()
  .forAccount(publicKey)
  .call();

// RPC - most methods limited to the retention window (~7 days)
// Exception: getLedgers can page further back (Infinite Scroll), but only as far
// as the chosen provider's retention or data-lake integration reaches.
// Always check the floor of the instance you're talking to first:
const { oldestLedger } = await rpc.getHealth();
// For guaranteed full history, use:
// 1. Hubble (SDF's BigQuery dataset)
// 2. Galexie (data pipeline)
// 3. Your own indexer
流式传输替代方案
// Horizon - native streaming
server.payments().stream({ onmessage: handlePayment });

// RPC - polling (no native streaming)
async function pollForUpdates() {
  const lastLedger = await rpc.getLatestLedger();
  // Check for new events/transactions
  // Repeat on interval
}
setInterval(pollForUpdates, 5000);

历史数据访问

对于早于 RPC 保留期限(约 7 天)的数据(大多数 RPC 方法无法访问;只有由数据湖支持的提供商的 getLedgers 才能查询更早的数据,参见下文的数据湖):

Hubble(BigQuery)
-- Query Stellar data in BigQuery
SELECT *
FROM `crypto-stellar.crypto_stellar.history_transactions`
WHERE source_account = 'G...'
ORDER BY created_at DESC
LIMIT 100
Galexie

用于处理 Stellar 账本数据的可自托管数据管道:

数据湖

RPC“无限滚动”由 Stellar 数据湖提供支持——一种基于云的对象存储(SEP-0054 格式)。深入查询 getLedgers 历史记录是提供方的能力,而非方法本身的能力:只有当实例运营方接入了数据湖时,实例才会提供超出其保留窗口的历史记录。未接入数据湖的实例(包括 SDF 公共测试网 RPC)会对较早的起始账本返回 JSON-RPC -32600 错误——分页回溯前,请将目标账本与 getHealth().oldestLedger 进行比较。

第三方索引器

对于超出 RPC/Horizon 能力范围的复杂查询、事件流或自定义数据管道:

查看完整的索引器目录:https://developers.stellar.org/docs/data/indexers

网络配置

关于 React/Next.js 专用设置,请参阅 dapp skill。 关于主网 RPC,请从 RPC 提供方目录中的提供方获取 STELLAR_MAINNET_RPC_URL。

基于环境的设置
// lib/stellar-config.ts
import * as StellarSdk from "@stellar/stellar-sdk";

type NetworkConfig = {
  rpcUrl: string;
  horizonUrl: string;
  networkPassphrase: string;
  friendbotUrl: string | null;
};

const requireEnv = (name: string): string => {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required env var: ${name}`);
  return value;
};

// Lazy per-network factories: requireEnv only runs for the selected network,
// so testnet/local work without the mainnet env var set.
const configs: Record<string, () => NetworkConfig> = {
  mainnet: () => ({
    rpcUrl: requireEnv("STELLAR_MAINNET_RPC_URL"),
    horizonUrl: "https://horizon.stellar.org",
    networkPassphrase: StellarSdk.Networks.PUBLIC,
    friendbotUrl: null,
  }),
  testnet: () => ({
    rpcUrl: "https://soroban-testnet.stellar.org",
    horizonUrl: "https://horizon-testnet.stellar.org",
    networkPassphrase: StellarSdk.Networks.TESTNET,
    friendbotUrl: "https://friendbot.stellar.org",
  }),
  local: () => ({
    rpcUrl: "http://localhost:8000/soroban/rpc",
    horizonUrl: "http://localhost:8000",
    networkPassphrase: "Standalone Network ; February 2017",
    friendbotUrl: "http://localhost:8000/friendbot",
  }),
};

const network = process.env.STELLAR_NETWORK || "testnet";
const makeConfig = configs[network];
if (!makeConfig) throw new Error(`Unknown network: ${network}`);
export const config = makeConfig();

export const rpc = new StellarSdk.rpc.Server(config.rpcUrl);
export const horizon = new StellarSdk.Horizon.Server(config.horizonUrl);

最佳实践

以下情况使用 RPC:
  • 开发新应用
  • 智能合约交互
  • 交易模拟和提交
  • 实时账户状态
以下情况使用 Horizon:
  • 查询历史交易
  • 支付流
  • 维护旧版应用
  • 丰富的账户元数据
错误处理
// RPC errors
try {
  const result = await rpc.sendTransaction(tx);
} catch (error) {
  if (error.code === 400) {
    // Invalid transaction
  } else if (error.code === 503) {
    // Service unavailable
  }
}

// Horizon errors
try {
  const result = await horizon.submitTransaction(tx);
} catch (error) {
  const extras = error.response?.data?.extras;
  if (extras?.result_codes) {
    // Detailed error codes
    console.log("Transaction:", extras.result_codes.transaction);
    console.log("Operations:", extras.result_codes.operations);
  }
}
速率限制

RPC 和 Horizon 均有速率限制:

  • 重试时使用指数退避
  • 适时缓存响应
  • 对于高流量应用,可考虑运行自己的节点
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  let lastError: Error;
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      if (error.response?.status === 429) {
        // Rate limited - exponential backoff
        await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
      } else {
        throw error;
      }
    }
  }
  throw lastError;
}

评论

支持 Markdown