Truy vấn trạng thái EVM lịch sử trong cửa sổ được hỗ trợ
Phân biệt cửa sổ trạng thái có xác thực, lịch sử không cần key và khoảng log. Chọn khối cố định cho eth_call và chẩn đoán lỗi state_window.
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 | 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 và GET /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 · Thời điểm lấy mẫu (UTC):
GET /v1/status · Thời điểm lấy mẫu (UTC):
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:
{
"jsonrpc": "2.0",
"id": 2,
"method": "eth_call",
"params": [
{ "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x313ce567" },
"0x18efa2f"
]
}Phản hồi:
{
"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.
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 để 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 cần khoảng được bao phủ; 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. Đừ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.
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. 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 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. 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 cho tham số gọi và mã hóa trả về.
- Khoảng khối eth_getLogs và truy vấn theo phần cho lịch sử log sự kiện.
- Cấu hình RPC tùy chỉnh cho ví cho kết nối ví và key riêng.
- Chuỗi được hỗ trợ cho khả năng mạng và giá CU cho chi phí phương thức.
Cập nhật lần cuối:
Giá DEX hàng ngày
Truy vấn giá OHLC và VWAP DEX hàng ngày từ Data API, xử lý phân số hữu tỉ chính xác trong TypeScript và Python, đồng thời tải bù dữ liệu lịch sử hiệu quả.
Gói miễn phí
Tìm hiểu gói miễn phí bao gồm những gì dựa trên trọng số phương thức thực tế, với tính toán theo tác vụ và cách nâng cấp.