サポートウィンドウ内での EVM 履歴状態の照会

認証付き状態ウィンドウ、キー不要の履歴、ログスパンを区別します。eth_call 用の固定ブロックを選択し、state_window エラーを診断します。

過去の時点に対する eth_call は、eth_getLogs のブロック範囲制限ではなく、そのチェーンの状態ウィンドウに依存します。以前のコントラクト値を読み取る前に、状態ウィンドウ、エンドポイントの認証モード、対象ブロックを確認してください。

3 種類の異なる履歴制限

GET /v1/chains のフィールド制御対象確認事項
state_window_blockseth_call、eth_getBalance、eth_getCode、eth_getStorageAt などの認証付き状態読み取りが遡れる範囲最新ブロックを H、宣言されたウィンドウを W とすると、H − W より古い番号のブロックはウィンドウ外となります。methods.allow と methods.deny も確認してください。
public.history_blocksキー不要の public.url を介した履歴ブロック参照public.methods のみを使用してください。状態の読み取りには、公開履歴と宣言された状態ウィンドウのいずれか小さい方が適用されます。
max_logs_block_range1 回の認証付き eth_getLogs リクエストにおけるブロック数toBlock − fromBlock + 1 でカウントします。許可されたスパンがあるからといって、古いコントラクト状態やログが利用可能であるとは限りません。

これらの制限は日数ではなくブロック数で指定されます。状態ウィンドウが null または未宣言であっても、アーカイブ範囲を保証するものではありません。キー不要メソッドの利用可否は認証付きメソッドの利用可否とは別個に管理されます。ログスパンがあるだけで公開 eth_getLogs が有効になるわけではありません。

チェーンごとの状態ウィンドウの比較

この表は、公開スナップショットから得られた公開状態ウィンドウ、キー不要の履歴、ログスパン、宣言された Data API データセットを示しています。現時点でのリクエストについては、GET /v1/chains と GET /v1/status を再度確認してください。

開発者および AI Agent は、状態ウィンドウとログクエリ範囲を個別に確認する必要があります。状態ウィンドウが null の場合でも、アーカイブの対応範囲を意味するものではありません。公開履歴は宣言された公開メソッドにのみ適用されます。

チェーンチェーンスラッグ認証付き状態ウィンドウ:state_window_blocks(ブロック数)キー不要の履歴:public.history_blocks(ブロック数)認証付きログクエリ範囲:max_logs_block_range(ブロック数)宣言された Data API データセット
Arbitrum Onearb_mainnet6,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Basebase_mainnet10,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
BNB Smart Chainbsc_mainnet1001001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Ethereumeth_mainnet250,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Ethereum Sepoliaeth_sepolia未宣言1,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
HyperEVMhyperevm_mainnet未宣言1,0001,000blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, freshness
Polygonpolygon_mainnet1261261,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Robinhood Chainrobinhood_mainnet9009001,000blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, dex_swaps, dex_prices, stocks, traces, freshness
Robinhood Chain Testnetrobinhood_testnet1,0231,0001,000Data API 利用不可

GET /v1/chains · サンプリング日時(UTC):

GET /v1/status · サンプリング日時(UTC):

ブロックタグの選択

現在の値には latest を使用します。履歴の比較を行うには、eth_blockNumber を 1 回読み取り、選択したブロック番号を 0x18efa2f などの 16 進数の数値に変換します。比較対象となるすべての呼び出しでその数値を固定してください。latest を繰り返し呼び出すと、異なるブロックが使用される可能性があります。

状態の読み取りにおいて、earliest、safe、finalized は状態ウィンドウポリシーに基づき -32011 を返します。代わりに、宣言されたウィンドウ内の明示的なブロック番号を選択してください。ブロックハッシュ形式を使用しても、追加の履歴を取得できるわけではありません。キー不要の状態読み取りでは拒否され、認証付きリクエストでも利用可能な状態に依存します。

リオーグ(再編成)が発生した場合、ブロック番号が異なるブロックを参照する可能性があります。結果に対応するブロックを特定する必要がある場合は、eth_getBlockByNumber でブロックハッシュを記録してください。また、ウィンドウ内のブロック番号であっても、チェーンが同期されており、そのブロック高でコントラクトが存在している必要があります。

固定ブロックでのコントラクト読み取り

Ethereum 上では、0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 にある WETH がセレクター 0x313ce567 で decimals() を公開しています。2026-10-08(UTC)にブロック 0x18efa2f でサンプリングされたキー不要の呼び出しでは、HTTP 200 と以下の結果が返されました:

チェーンの public.url へのリクエスト:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "eth_call",
  "params": [
    { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x313ce567" },
    "0x18efa2f"
  ]
}

レスポンス:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "0x0000000000000000000000000000000000000000000000000000000000000012"
}

ABI エンコードされた整数は 18 です。この結果は decimals(小数点桁数)の値であり、残高ではなく、他のブロック高での利用可能性を保証するものでもありません。この固定ブロックは有界ウィンドウから外れるため、後で以下の例を実行する際は最近のブロックを使用してください。

この例を historical-state.mjs として保存し、Node.js 24 以降で BLOCKVECTRA_API_KEY 環境変数を設定した上で node historical-state.mjs を実行してください。このコードは認証付きエンドポイントを使用し、同じコントラクトと calldata を維持しながら、latest、最近の固定ブロック 1 つ、および公開された認証ウィンドウ外のブロックを比較します。各出力には実際の HTTP ステータスと JSON-RPC レスポンス本文が含まれます。HTTP 200 であってもエラーが含まれる場合があります。予期しないレスポンスが発生した場合は、読み取り成功として扱わずに停止します。

const key = process.env.BLOCKVECTRA_API_KEY;
if (!key) throw new Error('Set BLOCKVECTRA_API_KEY');
const chainsUrl = 'https://api.blockvectra.com/v1/chains';
const catalogResponse = await fetch(chainsUrl, { signal: AbortSignal.timeout(15_000) });
if (!catalogResponse.ok) throw new Error(`Chains HTTP ${catalogResponse.status}`);
const catalog = await catalogResponse.json();
const chain = catalog.chains.find(item => item.chain === 'eth_mainnet');
const matches = (method, pattern) => pattern.endsWith('*')
  ? method.startsWith(pattern.slice(0, -1)) : method === pattern;
if (!chain?.jsonrpc || !['eth_call', 'eth_blockNumber'].every(method =>
  chain.methods?.allow?.some(pattern => matches(method, pattern)) &&
  !chain.methods?.deny?.some(pattern => matches(method, pattern)))) {
  throw new Error('Required methods are unavailable');
}
const window = chain.state_window_blocks;
if (!Number.isSafeInteger(window) || window < 10) {
  throw new Error('This example needs a declared state window of at least 10 blocks');
}
const rpcUrl = new URL('./eth_mainnet', chainsUrl).href;
let id = 0;
async function rpc(method, params) {
  const response = await fetch(rpcUrl, {
    method: 'POST', redirect: 'error', signal: AbortSignal.timeout(15_000),
    headers: { 'Content-Type': 'application/json', 'x-api-key': key },
    body: JSON.stringify({ jsonrpc: '2.0', id: ++id, method, params }),
  });
  return { http: response.status, body: await response.json() };
}
const headResponse = await rpc('eth_blockNumber', []);
if (headResponse.http !== 200 || headResponse.body.error ||
    !/^0x[0-9a-f]+$/i.test(headResponse.body.result ?? '')) {
  throw new Error(`Cannot read head: ${JSON.stringify(headResponse)}`);
}
const head = BigInt(headResponse.body.result);
if (head <= BigInt(window)) throw new Error('Head is too low for an out-of-window block');
const hex = value => `0x${value.toString(16)}`;
const fixedBlock = hex(head - 10n);
const outsideBlock = hex(head - BigInt(window) - 1n);
const call = { to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', data: '0x313ce567' };
for (const block of ['latest', fixedBlock, outsideBlock]) {
  const reply = await rpc('eth_call', [call, block]);
  console.log(JSON.stringify({ head: hex(head), block, ...reply }));
  if (block === outsideBlock) {
    if (reply.http !== 200 || reply.body.error?.code !== -32011 ||
        reply.body.error?.data?.reason !== 'state_window') {
      throw new Error('Expected state_window; inspect the actual response above');
    }
  } else if (reply.http !== 200 || reply.body.error ||
      reply.body.result !== '0x0000000000000000000000000000000000000000000000000000000000000012') {
    throw new Error('Expected the WETH decimals result; inspect the actual response above');
  }
}

上記の記録されたレスポンスは public.url を使用していますが、スクリプトは API key を使用しています。キー不要で読み取る場合は、public.url から直接 URL を取得し、キーを省略して、状態ウィンドウだけでなく public.history_blocks の範囲内にあるブロックを選択してください。認証方法を変更すると、同じコントラクトや calldata であっても、許可される履歴範囲が変わる場合があります。

ウィンドウ外エラーの診断

同じキー不要エンドポイントで、対象ブロックのみを 0x18ef650 に変更(およびリクエスト ID を変更)して 2026-10-08(UTC)にサンプリングされた呼び出しでは、HTTP 200 とともに error.code: -32011、error.data.reason: state_window、error.data.retryable: false が返されました。メッセージは block reference is outside the public history window でした。これは公開履歴の制限による失敗です。認証付きエンドポイントには独自の状態ウィンドウが存在します。

メッセージ内の特定のウィンドウ番号に依存するのではなく、state_window エラーエントリの以下のフィールドを使用して失敗を識別してください:

フィールドドキュメント記載の値または意味
HTTP ステータス200。HTTP が成功した場合でも JSON-RPC の error を確認してください
error.code-32011
error.message認証付き状態ウィンドウエラーにはサポートされる最新ブロック数が記載されます。公開履歴エラーでは異なるメッセージが使用される場合があります
error.data.reasonstate_window
error.data.docs_urlエラーカタログの state_window の解説へのリンク
error.data.retryablefalse:後で同じリクエストを再送信しても古い状態は復元されません

より新しい番号のブロックを選択するか、現在の値が必要なタスクの場合は latest を使用してください。eth_getLogs のスパンを縮小しても、過去の eth_call 状態が復旧するわけではありません。他の -32011 の原因には異なる対処が必要です:range_not_indexed ではカバーされている範囲が必要となり、history_not_ready ではインデックス処理が追いついた後に再試行できます。数値コードだけでなく、error.data.reason を確認してください。

基盤となる状態が利用できない場合は -32000 が返され、プルーニングされたブロック履歴の場合は 4444 が返されることもあります。エラーカタログを参照してください。古いブロックを変更せずに再試行したり、宣言されたウィンドウが大きいからといってすべてのレスポンスが保証されると思い込んだりしないでください。

次のクエリを選択する

完全なワークロードチェックリストとセルフテストについては、まず RPC プロバイダーの選び方 を参照してください。

繰り返しコントラクトを読み取るプロバイダーを選択する際は、EVM 読み取りの 1 日およびサイクルあたりの予算を比較してください。まず必要な履歴ブロックを確認し、次にタスクの日次分布とスループットを計画します。クレジット予算内に収まっているからといって、状態がカバーされていることの証明にはなりません。

履歴読み取りについてプロバイダーを比較する際は、まず双方が対象ブロックを提供できることを確認してください。full リクエストの超過料金比較では、追加の RU 価格とメソッドベースのコストを比較し、含まれるクォータと追加利用を区別し、full と archive の課金クラスについて解説しています。

より過去のインデックス済みブロック、トランザクション、転送、その他のデータセットについては、表に記載された Data API データセットおよび Data API リファレンス を確認してください。インデックスされたレコードがあるからといって、過去の任意のコントラクト実行が可能になるわけではなく、すべてのチェーンで過去の残高が提供されることを意味するわけでもありません。

最終更新:

このページの目次