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. 01RPCでStellarの新規アプリを開発
  2. 02Horizonに依存するアプリを保守
  3. 03最近のコントラクトイベントと状態を確認
  4. 04RPCの保持期間を超えるデータを検索

インストール

コマンドをコピーしてターミナルで実行します。

$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 には 2 つの API パラダイムがあります。

APIステータスユースケース
Stellar RPC推奨スマートコントラクト、リアルタイムの状態、新しいプロジェクト
Horizonレガシー用途向け過去データ、レガシーアプリケーション

推奨事項:新しいプロジェクトではすべて Stellar RPC を使用してください。Horizon は主に過去データのクエリとレガシーとの互換性が必要な経路で使用してください。

タスクに合ったファイルを読む

タスクファイル
RPC メソッドと使い方Stellar RPC(以下)
Horizon エンドポイント、一般的な操作、ストリーミング、ページネーションhorizon.md
移行戦略Migration: Horizon to RPC(以下)
データ履歴/インデックス作成の選択肢Historical Data Access(以下)
環境設定とエンドポイントNetwork Configuration(以下)

Stellar RPC

エンドポイント

注:SDF は Futurenet の公開 RPC を直接提供しています。Mainnet RPC には、RPC providers directory からプロバイダーを選択してください。

ネットワークRPC URL
Mainnetプロバイダー固有のエンドポイント(RPC providers directory を参照)
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 の例外:データレイクを利用するプロバイダーでは、「Infinite Scroll」によって保持期間をさかのぼり、そのプロバイダーのデータレイクが到達する範囲(場合によってはジェネシスまで)を取得できます。通常の 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 は、データレイクを利用するプロバイダーでのみ、さらに古いデータを取得できます。以下の Data Lake を参照してください):

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 を比較してください。

  • パブリックアクセス:s3://aws-public-blockchain/v1.1/stellar/ledgers/pubnet(AWS Open Data)
  • セルフホスト:Galexie を使用して AWS S3 または Google Cloud Storage にエクスポートします
  • ホステッド:Quasar (Lightsail Network) は、ホステッド Galexie データレイクと Archive RPC エンドポイントを提供します
  • サイズ:約 3.8TB、年間約 0.5TB 増加
  • コスト:セルフホストの場合、月額約 160 ドル(コンピューティング 60 ドル+ストレージ 100 ドル)
  • ドキュメント:https://developers.stellar.org/docs/data/apis/rpc/admin-guide/data-lake-integration
サードパーティのインデクサー

RPC/Horizon では対応できない複雑なクエリ、イベントストリーミング、カスタムデータパイプラインには、次のものを利用できます。

インデクサーの一覧は、https://developers.stellar.org/docs/data/indexers をご覧ください。

ネットワークの設定

React/Next.js 固有のセットアップについては、dapp スキルをご覧ください。 メインネット 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;
}

コメント