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

> Source: https://docs.blockvectra.com/ja/guides/evm-historical-state/

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

## 3 種類の異なる履歴制限

| [GET /v1/chains](https://api.blockvectra.com/v1/chains) のフィールド | 制御対象                                                                             | 確認事項                                                                                                         |
| -------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `state_window_blocks`                                          | `eth_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_range`                                         | 1 回の認証付き `eth_getLogs` リクエストにおけるブロック数                                            | `toBlock − fromBlock + 1` でカウントします。許可されたスパンがあるからといって、古いコントラクト状態やログが利用可能であるとは限りません。                           |

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

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

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

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

| チェーン | チェーンスラッグ | 認証付き状態ウィンドウ：state_window_blocks（ブロック数） | キー不要の履歴：public.history_blocks（ブロック数） | 認証付きログクエリ範囲：max_logs_block_range（ブロック数） | 宣言された Data API データセット |
| --- | --- | --- | --- | --- | --- |
| Arbitrum One | `arb_mainnet` | 6,000 | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| Base | `base_mainnet` | 10,000 | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| BNB Smart Chain | `bsc_mainnet` | 100 | 100 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| Ethereum | `eth_mainnet` | 250,000 | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| Ethereum Sepolia | `eth_sepolia` | 未宣言 | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| HyperEVM | `hyperevm_mainnet` | 未宣言 | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, freshness |
| Polygon | `polygon_mainnet` | 126 | 126 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| Robinhood Chain | `robinhood_mainnet` | 900 | 900 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, dex_swaps, dex_prices, stocks, traces, freshness |
| Robinhood Chain Testnet | `robinhood_testnet` | 1,023 | 1,000 | 1,000 | Data API 利用不可 |

[GET /v1/chains](https://api.blockvectra.com/v1/chains) · サンプリング日時（UTC）: 2026-10-09

[GET /v1/status](https://api.blockvectra.com/v1/status) · サンプリング日時（UTC）: 2026-10-09

## ブロックタグの選択

現在の値には `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` へのリクエスト：

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

レスポンス：

```json
{
  "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 であってもエラーが含まれる場合があります。予期しないレスポンスが発生した場合は、読み取り成功として扱わずに停止します。

```js
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 エラーエントリ](https://docs.blockvectra.com/en/errors/#state_window)の以下のフィールドを使用して失敗を識別してください：

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

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

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

## 次のクエリを選択する

完全なワークロードチェックリストとセルフテストについては、まず [RPC プロバイダーの選び方](https://docs.blockvectra.com/en/guides/choose-rpc-provider/) を参照してください。

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

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

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

* 呼び出しパラメーターと戻り値のエンコードについては [eth\_call メソッドリファレンス](https://docs.blockvectra.com/en/api/json-rpc/methods/eth_call/) を参照してください。
* イベントログの履歴については [eth\_getLogs のブロック範囲制限と分割クエリ](https://docs.blockvectra.com/en/guides/getlogs-block-range/) を参照してください。
* ウォレットの接続と専用キーについては [ウォレットカスタム RPC の設定](https://docs.blockvectra.com/en/guides/wallet-custom-rpc/) を参照してください。
* ネットワークの利用可否については [対応チェーン](https://docs.blockvectra.com/en/chains/)、メソッドコストについては [CU 料金の読み解き方](https://docs.blockvectra.com/en/guides/reading-cu-pricing/) を参照してください。
