Запит історичного стану EVM у межах підтримуваних вікон
Розрізняйте автентифіковані вікна стану, історію без ключа та діапазони журналів. Обирайте фіксований блок для eth_call та діагностуйте помилки state_window.
Історичний виклик eth_call залежить від вікна стану мережі, а не від ліміту діапазону блоків для eth_getLogs. Перевірте вікно стану, режим автентифікації ендпоінта та цільовий блок перед читанням попереднього значення контракту.
Три різні історичні ліміти
| Поле в GET /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 | Кількість блоків в одному автентифікованому запиті eth_getLogs | Розраховується як toBlock − fromBlock + 1. Дозволений діапазон не гарантує доступності старого стану контракту чи журналів. |
Ці ліміти вимірюються в блоках, а не в днях. Значення null або незаявлене вікно стану не означає наявності архівного покриття. Доступність методів без ключа відокремлена від доступності автентифікованих методів: сам лише діапазон журналів не відкриває доступ до публічного eth_getLogs.
Порівняння вікон стану для різних мереж
У таблиці наведено опубліковані вікна стану, історію без ключа, діапазони журналів та заявлені набори даних Data API з публічного знімка. Для виконання запиту зараз знову зверніться до GET /v1/chains та GET /v1/status.
Розробники та AI-агенти повинні перевіряти вікна стану та діапазони запитів логів окремо. Вікно стану зі значенням null не означає повноти архіву (archive coverage). Загальнодоступна історія застосовується лише до оголошених публічних методів.
| Мережа | Slug мережі | Автентифіковане вікно стану: state_window_blocks (блоків) | Історія без ключа: public.history_blocks (блоків) | Автентифікований діапазон запитів логів: max_logs_block_range (блоків) | Оголошені набори даних Data API |
|---|---|---|---|---|---|
| Arbitrum One | arb_mainnet | 5,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 · Вибірку зроблено (UTC):
GET /v1/status · Вибірку зроблено (UTC):
Вибір тегу блоку
Використовуйте latest для отримання поточного значення. Для історичного порівняння один раз викличте eth_blockNumber та перетворіть обраний номер блоку на шістнадцяткове число, наприклад 0x18efa2f. Зберігайте цей номер фіксованим для кожного виклику в порівнянні; повторні виклики з latest можуть використовувати різні блоки.
Для читань стану теги earliest, safe та finalized повертають помилку -32011 згідно з політикою вікна стану. Замість цього вказуйте точний номер блоку в межах заявленого вікна. Використання хешу блоку не дозволяє отримати доступ до глибшої історії: читання стану без ключа відхиляють такий формат, а автентифікований запит усе одно залежить від доступності стану.
Після реорганізації ланцюга номер блоку може посилатися на інший блок. Збережіть хеш блоку за допомогою eth_getBlockByNumber, якщо вам потрібно точно ідентифікувати блок результату. Для успішного запиту за номером у межах вікна також потрібна синхронізована мережа та наявність розгорнутого контракту на цій висоті.
Читання контракту на фіксованому блоці
В Ethereum контракт WETH за адресою 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 надає метод decimals() із селектором 0x313ce567. Виклик без ключа, зафіксований 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 historical-state.mjs за допомогою Node.js 24 або новішої версії зі встановленою змінною середовища BLOCKVECTRA_API_KEY. Скрипт використовує автентифікований ендпоінт, зберігає той самий контракт і calldata та порівнює latest, один фіксований нещодавній блок і блок за межами опублікованого автентифікованого вікна. Кожен вивід містить фактичний 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. Щоб виконати читання без ключа, візьміть URL безпосередньо з public.url, опустіть ключ і оберіть блок у межах як public.history_blocks, так і вікна стану. Зміна способу автентифікації може змінювати дозволену глибину історії навіть для одного й того самого контракту та calldata.
Діагностика помилки виходу за межі вікна
На тому самому ендпоінті без ключа виклик, зафіксований 2026-10-08 (UTC), у якому було змінено лише цільовий блок на 0x18ef650 (та ID запиту), повернув 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; перевіряйте JSON-RPC error, навіть коли запит HTTP успішний |
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 вимагає запиту в межах покритого діапазону; history_not_ready дозволяє повторити спробу після завершення індексації. Аналізуйте error.data.reason, а не лише числовий код.
Базовий стан також може бути недоступним із кодом -32000, а обрізана історія блоків — із кодом 4444; дивіться каталог помилок. Не повторюйте запит до старого блоку без змін і не припускайте, що більше заявлене вікно гарантує успішність кожної відповіді.
Вибір наступного запиту
Повний чекліст робочого навантаження та самостійне тестування дивіться в посібнику Як обрати RPC-провайдера.
Обираючи провайдера для регулярних читань контрактів, порівняйте щоденні та циклічні бюджети для читань EVM. Спочатку перевірте необхідні історичні блоки, а потім плануйте щоденний розподіл і пропускну здатність завдання; вкладання в кредитний бюджет не гарантує покриття потрібного стану.
Порівнюючи провайдерів для історичних читань, спочатку переконайтеся, що обидва можуть обслуговувати цільовий блок. Порівняння перевищення ліміту для full-запитів порівнює ціни на додаткові RU з витратами за методами, розділяє включену квоту й додаткове використання та пояснює розрахункові класи full та archive.
Для більш ранніх індексованих блоків, транзакцій, переказів або інших наборів даних перевірте заявлені в таблиці набори даних Data API та довідник Data API. Індексовані записи не забезпечують довільного виконання історичних контрактів і не означають, що кожна мережа підтримує історичні баланси.
- Довідник методу eth_call щодо параметрів виклику та кодування значень, що повертаються.
- Діапазон блоків eth_getLogs та фрагментовані запити щодо історії журналів подій.
- Налаштування власного RPC у гаманці щодо підключення гаманців і виділених ключів.
- Підтримувані мережі щодо доступності мереж та тарифікація в CU щодо вартості методів.
Востаннє оновлено: