Запрос исторического состояния 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 для окна состояния не означает полного покрытия архива. Публичная история применяется только к объявленным публичным методам.
| Сеть | Слаг сети | Окно аутентифицированного состояния: 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 · Время выборки (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-ключ. Чтобы выполнить чтение без ключа, возьмите URL напрямую из public.url, опустите ключ и выберите блок в пределах public.history_blocks, а также окна состояния. Смена способа аутентификации может изменить допустимую глубину истории даже для одного и того же контракта и calldata.
Диагностика ошибки выхода за пределы окна
На том же эндпоинте без ключа вызов, выполненный 2026-10-08 (UTC) с изменением только целевого блока на 0x18ef650 (и идентификатора запроса), вернул 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; проверяйте объект error в JSON-RPC, даже когда 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. Сначала определите необходимые исторические блоки, затем спланируйте суточное распределение и пропускную способность задачи; вхождение в бюджет кредитов не гарантирует покрытие состояния.
При сравнении провайдеров для исторического чтения сначала убедитесь, что оба могут предоставить целевой блок. Сравнение стоимости перерасхода по запросам сопоставляет цены на дополнительные RU с затратами по методам, разделяет включенную квоту и дополнительное использование, а также объясняет различия между полными и архивными классами тарификации.
Для ранее проиндексированных блоков, транзакций, переводов или других наборов данных обратитесь к объявленным наборам данных Data API в таблице и к справочнику по Data API. Проиндексированные записи не обеспечивают произвольное выполнение контрактов в прошлом и не означают, что на каждой сети доступны исторические балансы.
- Справочник по методу eth_call для параметров вызова и кодирования возвращаемых значений.
- Диапазон блоков eth_getLogs и составные запросы для истории событий логов.
- Настройка пользовательского RPC в кошельке для подключения кошельков и выделенных ключей.
- Поддерживаемые сети для проверки доступности сетей и тарификация CU для стоимости методов.
Последнее обновление:
Дневные цены DEX
Запрашивайте дневные цены DEX OHLC и VWAP из Data API, обрабатывайте точные рациональные дроби в TypeScript и Python и эффективно дозагружайте исторические данные.
Бесплатный план
Узнайте, что покрывает бесплатный план на основе реальных весов методов, с расчетами под задачи и путями перехода.