# Kueri State EVM Historis dalam Jendela yang Didukung

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

`eth_call` historis bergantung pada jendela state chain, bukan batas rentang blok `eth_getLogs`. Periksa jendela state, mode autentikasi endpoint, dan blok tujuan sebelum membaca nilai kontrak sebelumnya.

## Tiga batas historis yang berbeda

| Bidang dalam [GET /v1/chains](https://api.blockvectra.com/v1/chains) | Yang dikendalikannya                                                                                                                                  | Yang perlu diperiksa                                                                                                                                                 |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state_window_blocks`                                                | Seberapa jauh pembacaan state terautentikasi seperti `eth_call`, `eth_getBalance`, `eth_getCode`, dan `eth_getStorageAt` dapat menelusuri ke belakang | Dengan head `H` dan jendela yang dinyatakan `W`, blok bernomor yang lebih lama dari `H − W` berada di luar jendela. Periksa juga `methods.allow` dan `methods.deny`. |
| `public.history_blocks`                                              | Referensi blok historis melalui `public.url` tanpa API key                                                                                            | Gunakan hanya `public.methods`. Untuk pembacaan state, batas yang lebih kecil antara riwayat publik dan jendela state yang dinyatakan berlaku.                       |
| `max_logs_block_range`                                               | Jumlah blok dalam satu permintaan `eth_getLogs` terautentikasi                                                                                        | Hitung `toBlock − fromBlock + 1`. Rentang yang diizinkan tidak memastikan state kontrak atau log lama tersedia.                                                      |

Batas ini menggunakan satuan blok, bukan hari. Jendela state `null` atau yang tidak dinyatakan tidak memastikan cakupan arsip. Ketersediaan metode tanpa API key terpisah dari ketersediaan metode terautentikasi: rentang log saja tidak mengaktifkan `eth_getLogs` publik.

## Bandingkan jendela state per chain

Tabel menampilkan jendela state yang dipublikasikan, riwayat tanpa API key, rentang log, dan dataset Data API yang dinyatakan dari snapshot publik. Untuk permintaan saat ini, baca kembali [GET /v1/chains](https://api.blockvectra.com/v1/chains) dan [GET /v1/status](https://api.blockvectra.com/v1/status).

Pengembang dan agen AI harus memeriksa jendela status dan rentang kueri log secara terpisah. Jendela status null tidak menetapkan cakupan arsip. Riwayat publik hanya berlaku untuk metode publik yang dideklarasikan.

| Rantai | Slug rantai | Jendela status terautentikasi: state_window_blocks (blok) | Riwayat tanpa key: public.history_blocks (blok) | Rentang kueri log terautentikasi: max_logs_block_range (blok) | Kumpulan data Data API yang dideklarasikan |
| --- | --- | --- | --- | --- | --- |
| 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` | Tidak dideklarasikan | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| HyperEVM | `hyperevm_mainnet` | Tidak dideklarasikan | 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 dinonaktifkan |

[GET /v1/chains](https://api.blockvectra.com/v1/chains) · Diambil sampel (UTC): 2026-10-09

[GET /v1/status](https://api.blockvectra.com/v1/status) · Diambil sampel (UTC): 2026-10-09

## Pilih tag blok

Gunakan `latest` untuk nilai saat ini. Untuk perbandingan historis, baca `eth_blockNumber` sekali dan konversikan nomor blok yang dipilih ke kuantitas heksadesimal seperti `0x18efa2f`. Pertahankan nomor tersebut untuk setiap panggilan dalam perbandingan; panggilan `latest` berulang dapat menggunakan blok berbeda.

Untuk pembacaan state, `earliest`, `safe`, dan `finalized` mengembalikan `-32011` berdasarkan kebijakan jendela state. Pilih nomor blok eksplisit dalam jendela yang dinyatakan. Bentuk hash blok bukan cara memperoleh riwayat tambahan: pembacaan state tanpa API key menolaknya, dan permintaan terautentikasi tetap bergantung pada state yang tersedia.

Nomor blok dapat merujuk ke blok berbeda setelah reorganisasi. Catat hash blok dengan `eth_getBlockByNumber` jika perlu mengidentifikasi blok hasilnya. Nomor dalam jendela juga memerlukan chain yang tersinkronisasi dan kontrak yang sudah ada pada tinggi tersebut.

## Pembacaan kontrak pada blok tetap

Di Ethereum, WETH pada `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` menyediakan `decimals()` dengan selector `0x313ce567`. Panggilan tanpa API key yang diambil sampelnya pada 2026-10-08 (UTC) di blok `0x18efa2f` mengembalikan HTTP 200 dengan hasil berikut:

Permintaan ke `public.url` chain:

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

Respons:

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

Bilangan bulat yang dikodekan ABI adalah 18. Hasilnya merupakan nilai decimals, bukan saldo, dan tidak memastikan ketersediaan pada tinggi lain. Blok tetap tersebut akan keluar dari jendela berbatas seiring waktu; gunakan blok terbaru saat menjalankan contoh berikut di kemudian hari.

Simpan contoh sebagai `historical-state.mjs` dan jalankan `node historical-state.mjs` dengan Node.js 24 atau lebih baru dan variabel lingkungan `BLOCKVECTRA_API_KEY` diatur. Contoh menggunakan endpoint terautentikasi, mempertahankan kontrak dan calldata yang sama, serta membandingkan `latest`, satu blok tetap terbaru, dan blok di luar jendela terautentikasi yang dipublikasikan. Setiap keluaran menyertakan status HTTP dan body JSON-RPC nyata; HTTP 200 tetap dapat berisi error. Contoh berhenti pada respons yang tidak diharapkan alih-alih menganggapnya sebagai pembacaan berhasil.

```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');
  }
}
```

Respons yang dicatat di atas menggunakan `public.url`; skrip menggunakan API key. Untuk pembacaan tanpa API key, ambil URL langsung dari `public.url`, hilangkan API key, dan pilih blok dalam `public.history_blocks` serta jendela state. Mengubah autentikasi dapat mengubah riwayat yang diizinkan, bahkan untuk kontrak dan calldata yang sama.

## Diagnosis error di luar jendela

Pada endpoint tanpa API key yang sama, panggilan yang diambil sampelnya pada 2026-10-08 (UTC) dengan hanya mengubah blok tujuan menjadi `0x18ef650` (dan ID permintaan) mengembalikan HTTP 200 dengan `error.code: -32011`, `error.data.reason: state_window`, dan `error.data.retryable: false`. Pesannya adalah `block reference is outside the public history window`. Ini kegagalan riwayat publik; endpoint terautentikasi memiliki jendela state sendiri.

Gunakan bidang berikut dari [entri error state\_window](https://docs.blockvectra.com/en/errors/#state_window) untuk mengenali kegagalan, alih-alih mengandalkan angka jendela tertentu dalam pesan:

| Bidang                 | Nilai atau makna yang didokumentasikan                                                                                                 |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Status HTTP            | `200`; periksa `error` JSON-RPC meskipun HTTP berhasil                                                                                 |
| `error.code`           | `-32011`                                                                                                                               |
| `error.message`        | Error jendela state terautentikasi menjelaskan jumlah blok terbaru yang didukung; error riwayat publik dapat menggunakan pesan berbeda |
| `error.data.reason`    | `state_window`                                                                                                                         |
| `error.data.docs_url`  | Tautan ke penjelasan `state_window` dalam katalog error                                                                                |
| `error.data.retryable` | `false`: mengirim permintaan yang sama kemudian tidak memulihkan state lama                                                            |

Pilih blok bernomor yang lebih baru atau gunakan `latest` jika tugas memerlukan nilai saat ini. Mengurangi rentang `eth_getLogs` tidak memulihkan state `eth_call` historis. Alasan `-32011` lain membutuhkan tindakan berbeda: [range\_not\_indexed](https://docs.blockvectra.com/en/errors/#range_not_indexed) memerlukan rentang yang tercakup; [history\_not\_ready](https://docs.blockvectra.com/en/errors/#history_not_ready) mengizinkan percobaan ulang setelah pengindeksan menyusul. Periksa `error.data.reason`, bukan hanya kode numeriknya.

State dasar juga dapat tidak tersedia dengan `-32000`, atau riwayat blok yang dipangkas dengan `4444`; lihat [katalog error](https://docs.blockvectra.com/en/errors/). Jangan mencoba ulang blok lama tanpa perubahan atau menganggap jendela yang dinyatakan lebih besar menjamin setiap respons.

## Pilih kueri berikutnya

Untuk daftar pemeriksaan beban kerja lengkap dan pengujian mandiri, mulai dengan [Cara memilih penyedia RPC](https://docs.blockvectra.com/en/guides/choose-rpc-provider/).

Saat memilih penyedia untuk pembacaan kontrak berulang, [bandingkan anggaran harian dan siklus untuk pembacaan EVM](https://docs.blockvectra.com/en/guides/infura-alternative/). Periksa blok historis yang diperlukan terlebih dahulu, lalu rencanakan distribusi harian dan throughput tugas; sesuai dengan anggaran kredit tidak memastikan cakupan state.

Saat membandingkan penyedia untuk pembacaan historis, pastikan terlebih dahulu keduanya dapat melayani blok tujuan. [Perbandingan penggunaan berlebih untuk permintaan lengkap](https://docs.blockvectra.com/en/guides/chainstack-alternative/) membandingkan harga RU tambahan dengan biaya berbasis metode, memisahkan kuota yang disertakan dari penggunaan tambahan, dan menjelaskan kelas penagihan full versus archive.

Untuk blok terindeks sebelumnya, transaksi, transfer, atau dataset lain, periksa dataset Data API yang dinyatakan dalam tabel dan [referensi Data API](https://docs.blockvectra.com/en/api/data/). Catatan terindeks tidak menyediakan eksekusi kontrak historis sebarang atau menyiratkan bahwa setiap chain memiliki saldo historis.

* [Referensi metode eth\_call](https://docs.blockvectra.com/en/api/json-rpc/methods/eth_call/) untuk parameter panggilan dan pengodean hasil.
* [Rentang blok eth\_getLogs dan kueri bertahap](https://docs.blockvectra.com/en/guides/getlogs-block-range/) untuk riwayat log peristiwa.
* [Konfigurasi RPC kustom dompet](https://docs.blockvectra.com/en/guides/wallet-custom-rpc/) untuk koneksi dompet dan API key khusus.
* [Chain yang didukung](https://docs.blockvectra.com/en/chains/) untuk ketersediaan jaringan dan [harga CU](https://docs.blockvectra.com/en/guides/reading-cu-pricing/) untuk biaya metode.
