# Truy vấn trạng thái EVM lịch sử trong cửa sổ được hỗ trợ

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

`eth_call` lịch sử phụ thuộc vào cửa sổ trạng thái của chuỗi, không phải giới hạn khoảng khối `eth_getLogs`. Kiểm tra cửa sổ trạng thái, chế độ xác thực endpoint và khối mục tiêu trước khi đọc giá trị hợp đồng trước đó.

## Ba giới hạn lịch sử khác nhau

| Trường trong [GET /v1/chains](https://api.blockvectra.com/v1/chains) | Kiểm soát gì                                                                                                                           | Cần kiểm tra gì                                                                                                                     |
| -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `state_window_blocks`                                                | Truy vấn đọc trạng thái có xác thực như `eth_call`, `eth_getBalance`, `eth_getCode` và `eth_getStorageAt` có thể truy vấn ngược bao xa | Với đầu chuỗi `H` và cửa sổ công bố `W`, khối có số cũ hơn `H − W` nằm ngoài cửa sổ. Kiểm tra cả `methods.allow` và `methods.deny`. |
| `public.history_blocks`                                              | Tham chiếu khối lịch sử qua `public.url` không cần key                                                                                 | Chỉ dùng `public.methods`. Với đọc trạng thái, áp dụng giới hạn nhỏ hơn giữa lịch sử công khai và cửa sổ trạng thái công bố.        |
| `max_logs_block_range`                                               | Số khối trong một yêu cầu `eth_getLogs` có xác thực                                                                                    | Tính `toBlock − fromBlock + 1`. Khoảng được phép không chứng minh trạng thái hợp đồng hoặc log cũ khả dụng.                         |

Các giới hạn này tính bằng khối, không phải ngày. Cửa sổ trạng thái `null` hoặc không công bố không chứng minh phạm vi archive. Khả năng phương thức không cần key tách biệt với khả năng phương thức có xác thực: chỉ khoảng log không cho phép `eth_getLogs` công khai.

## So sánh cửa sổ trạng thái theo chuỗi

Bảng hiển thị cửa sổ trạng thái công bố, lịch sử không cần key, khoảng log và bộ dữ liệu Data API khai báo từ snapshot công khai. Để gửi yêu cầu ngay lúc này, đọc lại [GET /v1/chains](https://api.blockvectra.com/v1/chains) và [GET /v1/status](https://api.blockvectra.com/v1/status).

Nhà phát triển và AI Agent nên kiểm tra riêng biệt cửa sổ trạng thái và phạm vi truy vấn log. Cửa sổ trạng thái null không có nghĩa là có lưu trữ toàn bộ lịch sử (archive). Lịch sử công khai chỉ áp dụng cho các phương thức công khai đã khai báo.

| Chuỗi | Slug chuỗi | Cửa sổ trạng thái xác thực: state_window_blocks (khối) | Lịch sử không cần key: public.history_blocks (khối) | Phạm vi truy vấn log xác thực: max_logs_block_range (khối) | Bộ dữ liệu Data API đã khai báo |
| --- | --- | --- | --- | --- | --- |
| 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` | Chưa khai báo | 1,000 | 1,000 | blocks, transactions, address_transactions, transfers, token_metadata, freshness |
| HyperEVM | `hyperevm_mainnet` | Chưa khai báo | 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 không khả dụng |

[GET /v1/chains](https://api.blockvectra.com/v1/chains) · Thời điểm lấy mẫu (UTC): 2026-10-09

[GET /v1/status](https://api.blockvectra.com/v1/status) · Thời điểm lấy mẫu (UTC): 2026-10-09

## Chọn block tag

Dùng `latest` cho giá trị hiện tại. Để so sánh lịch sử, đọc `eth_blockNumber` một lần và chuyển số khối đã chọn thành đại lượng thập lục phân như `0x18efa2f`. Giữ số đó cố định cho mọi lệnh gọi trong phép so sánh; các lần gọi `latest` lặp lại có thể dùng khối khác nhau.

Với đọc trạng thái, `earliest`, `safe` và `finalized` trả `-32011` theo chính sách cửa sổ trạng thái. Thay vào đó, chọn số khối tường minh trong cửa sổ công bố. Dạng hash khối không phải cách lấy thêm lịch sử: đọc trạng thái không cần key từ chối dạng này, và yêu cầu có xác thực vẫn phụ thuộc trạng thái khả dụng.

Số khối có thể trỏ tới khối khác sau tái tổ chức. Ghi hash khối bằng `eth_getBlockByNumber` nếu cần xác định khối của kết quả. Số khối trong cửa sổ cũng cần chuỗi đã đồng bộ và hợp đồng tồn tại tại độ cao đó.

## Đọc hợp đồng tại khối cố định

Trên Ethereum, WETH tại `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` cung cấp `decimals()` với selector `0x313ce567`. Lệnh gọi không cần key được lấy mẫu ngày 2026-10-08 (UTC) tại khối `0x18efa2f` trả HTTP 200 với kết quả này:

Yêu cầu tới `public.url` của chuỗi:

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

Phản hồi:

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

Số nguyên mã hóa ABI là 18. Kết quả là giá trị số chữ số thập phân, không phải số dư, và không chứng minh khả năng truy cập tại độ cao khác. Khối cố định đó sẽ cũ dần và ra ngoài cửa sổ có giới hạn; dùng khối gần đây khi chạy ví dụ sau vào thời điểm muộn hơn.

Lưu ví dụ thành `historical-state.mjs` và chạy `node historical-state.mjs` với Node.js 24 trở lên và biến môi trường `BLOCKVECTRA_API_KEY` đã đặt. Ví dụ dùng endpoint có xác thực, giữ cùng hợp đồng và calldata, và so sánh `latest`, một khối cố định gần đây và một khối ngoài cửa sổ có xác thực công bố. Mỗi đầu ra có trạng thái HTTP thực tế và body JSON-RPC; HTTP 200 vẫn có thể chứa lỗi. Ví dụ dừng khi phản hồi không như dự kiến thay vì coi đó là truy vấn đọc thành công.

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

Phản hồi ghi nhận phía trên dùng `public.url`; script dùng API key. Để đọc không cần key, lấy URL trực tiếp từ `public.url`, bỏ key và chọn khối nằm trong cả `public.history_blocks` lẫn cửa sổ trạng thái. Đổi cách xác thực có thể đổi lịch sử được phép, ngay cả với cùng hợp đồng và calldata.

## Chẩn đoán lỗi ngoài cửa sổ

Trên cùng endpoint không cần key, lệnh gọi được lấy mẫu ngày 2026-10-08 (UTC) chỉ đổi khối mục tiêu thành `0x18ef650` (và ID yêu cầu) trả HTTP 200 với `error.code: -32011`, `error.data.reason: state_window` và `error.data.retryable: false`. Thông báo là `block reference is outside the public history window`. Đây là lỗi lịch sử công khai; endpoint có xác thực có cửa sổ trạng thái riêng.

Dùng các trường này từ [mục lỗi state\_window](https://docs.blockvectra.com/en/errors/#state_window) để nhận diện lỗi thay vì dựa vào con số cửa sổ cụ thể trong thông báo:

| Trường                 | Giá trị hoặc ý nghĩa được mô tả                                                                                        |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Trạng thái HTTP        | `200`; kiểm tra `error` JSON-RPC ngay cả khi HTTP thành công                                                           |
| `error.code`           | `-32011`                                                                                                               |
| `error.message`        | Lỗi cửa sổ trạng thái có xác thực mô tả số khối gần nhất được hỗ trợ; lỗi lịch sử công khai có thể dùng thông báo khác |
| `error.data.reason`    | `state_window`                                                                                                         |
| `error.data.docs_url`  | Liên kết tới giải thích `state_window` trong danh mục lỗi                                                              |
| `error.data.retryable` | `false`: gửi lại cùng yêu cầu sau đó không khôi phục trạng thái cũ hơn                                                 |

Chọn khối có số mới hơn hoặc dùng `latest` nếu tác vụ cần giá trị hiện tại. Giảm khoảng `eth_getLogs` không khôi phục trạng thái `eth_call` lịch sử. Các lý do `-32011` khác cần thao tác khác: [range\_not\_indexed](https://docs.blockvectra.com/en/errors/#range_not_indexed) cần khoảng được bao phủ; [history\_not\_ready](https://docs.blockvectra.com/en/errors/#history_not_ready) cho phép thử lại sau khi lập chỉ mục bắt kịp. Kiểm tra `error.data.reason`, không chỉ mã số.

Trạng thái nền cũng có thể không khả dụng với `-32000`, hoặc lịch sử khối bị cắt tỉa với `4444`; xem [danh mục lỗi](https://docs.blockvectra.com/en/errors/). Đừng thử lại nguyên yêu cầu khối cũ hoặc giả định cửa sổ công bố lớn hơn bảo đảm mọi phản hồi.

## Chọn truy vấn tiếp theo

Để có danh sách kiểm tra tác vụ đầy đủ và tự kiểm tra, bắt đầu với [Cách chọn nhà cung cấp RPC](https://docs.blockvectra.com/en/guides/choose-rpc-provider/).

Khi chọn nhà cung cấp cho đọc hợp đồng lặp lại, [so sánh ngân sách hằng ngày và chu kỳ cho truy vấn đọc EVM](https://docs.blockvectra.com/en/guides/infura-alternative/). Kiểm tra các khối lịch sử cần thiết trước, rồi lập kế hoạch phân bố hằng ngày và thông lượng của tác vụ; phù hợp ngân sách credit không chứng minh phạm vi trạng thái.

Khi so sánh nhà cung cấp cho đọc lịch sử, trước hết xác nhận cả hai phục vụ được khối mục tiêu. [So sánh phí vượt hạn mức cho yêu cầu full](https://docs.blockvectra.com/en/guides/chainstack-alternative/) so sánh giá RU bổ sung với chi phí theo phương thức, tách hạn mức đi kèm khỏi mức sử dụng bổ sung và giải thích loại tính phí full với archive.

Với khối, giao dịch, chuyển tiền hoặc bộ dữ liệu khác trước đó đã lập chỉ mục, kiểm tra bộ dữ liệu Data API khai báo trong bảng và [tham chiếu Data API](https://docs.blockvectra.com/en/api/data/). Bản ghi được lập chỉ mục không cung cấp thực thi hợp đồng lịch sử tùy ý hoặc hàm ý mọi chuỗi có số dư lịch sử.

* [Tham chiếu phương thức eth\_call](https://docs.blockvectra.com/en/api/json-rpc/methods/eth_call/) cho tham số gọi và mã hóa trả về.
* [Khoảng khối eth\_getLogs và truy vấn theo phần](https://docs.blockvectra.com/en/guides/getlogs-block-range/) cho lịch sử log sự kiện.
* [Cấu hình RPC tùy chỉnh cho ví](https://docs.blockvectra.com/en/guides/wallet-custom-rpc/) cho kết nối ví và key riêng.
* [Chuỗi được hỗ trợ](https://docs.blockvectra.com/en/chains/) cho khả năng mạng và [giá CU](https://docs.blockvectra.com/en/guides/reading-cu-pricing/) cho chi phí phương thức.
