Consultar o estado histórico da EVM dentro das janelas suportadas

Distinga janelas de estado autenticadas, histórico sem chave e intervalos de logs. Escolha um bloco fixo para eth_call e diagnostique erros de state_window.

Chamadas históricas de eth_call dependem da janela de estado da rede, e não do limite de intervalo de blocos de eth_getLogs. Verifique a janela de estado, o modo de autenticação do endpoint e o bloco de destino antes de ler o valor anterior de um contrato.

Três limites históricos diferentes

Campo em GET /v1/chainsO que controlaO que verificar
state_window_blocksAté que ponto no passado leituras de estado autenticadas como eth_call, eth_getBalance, eth_getCode e eth_getStorageAt podem consultarCom o topo H e a janela declarada W, um bloco numerado anterior a H − W está fora da janela. Verifique também methods.allow e methods.deny.
public.history_blocksReferências a blocos históricos por meio da public.url sem chaveUse apenas public.methods. Para leituras de estado, aplica-se o menor valor entre o histórico público e a janela de estado declarada.
max_logs_block_rangeO número de blocos em uma única requisição autenticada de eth_getLogsConte toBlock − fromBlock + 1. Um intervalo permitido não estabelece que o estado antigo do contrato ou os logs estejam disponíveis.

Esses limites são em blocos, não em dias. Uma janela de estado null ou não declarada não estabelece cobertura de arquivamento. A disponibilidade de métodos sem chave é separada da disponibilidade de métodos autenticados: um intervalo de logs por si só não habilita o eth_getLogs público.

Comparar janelas de estado por rede

A tabela mostra as janelas de estado publicadas, o histórico sem chave, os intervalos de logs e os conjuntos de dados declarados da Data API a partir do snapshot público. Para uma requisição agora, consulte GET /v1/chains e GET /v1/status novamente.

Desenvolvedores e agentes de IA devem verificar janelas de estado e intervalos de consulta de logs separadamente. Uma janela de estado nula não estabelece cobertura de arquivo. O histórico público aplica-se apenas aos métodos públicos declarados.

RedeSlug da redeJanela de estado autenticada: state_window_blocks (blocos)Histórico sem chave: public.history_blocks (blocos)Intervalo de consulta de logs autenticado: max_logs_block_range (blocos)Conjuntos de dados da Data API declarados
Arbitrum Onearb_mainnet6,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Basebase_mainnet10,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
BNB Smart Chainbsc_mainnet1001001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Ethereumeth_mainnet250,0001,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Ethereum Sepoliaeth_sepoliaNão declarado1,0001,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
HyperEVMhyperevm_mainnetNão declarado1,0001,000blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, freshness
Polygonpolygon_mainnet1261261,000blocks, transactions, address_transactions, transfers, token_metadata, freshness
Robinhood Chainrobinhood_mainnet9009001,000blocks, transactions, address_transactions, transfers, token_metadata, balances, holders, nfts, dex_swaps, dex_prices, stocks, traces, freshness
Robinhood Chain Testnetrobinhood_testnet1,0231,0001,000Data API indisponível

GET /v1/chains · Amostragem (UTC):

GET /v1/status · Amostragem (UTC):

Escolher uma tag de bloco

Use latest para o valor atual. Para uma comparação histórica, leia eth_blockNumber uma vez e converta o número de bloco escolhido em uma quantidade hexadecimal como 0x18efa2f. Mantenha esse número fixo para todas as chamadas na comparação; chamadas repetidas com latest podem usar blocos diferentes.

Para leituras de estado, earliest, safe e finalized retornam -32011 sob a política de janela de estado. Escolha um número de bloco explícito dentro da janela declarada. O formato de hash de bloco não é uma forma de obter histórico adicional: leituras de estado sem chave o rejeitam, e uma requisição autenticada ainda depende do estado disponível.

Um número de bloco pode se referir a um bloco diferente após uma reorganização. Registre o hash do bloco com eth_getBlockByNumber se você precisar identificar o bloco do resultado. Um número dentro da janela também precisa de uma rede sincronizada e de um contrato existente nessa altura.

Leitura de contrato em bloco fixo

No Ethereum, o WETH em 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 expõe decimals() com o seletor 0x313ce567. Uma chamada sem chave amostrada em 2026-10-08 (UTC) no bloco 0x18efa2f retornou HTTP 200 com este resultado:

Requisição para a public.url da rede:

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

Resposta:

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

O número inteiro codificado em ABI é 18. O resultado é um valor de decimais, não um saldo, e não estabelece disponibilidade em outras alturas. Esse bloco fixo sairá de uma janela limitada com o tempo; use um bloco recente ao executar o exemplo a seguir posteriormente.

Salve o exemplo como historical-state.mjs e execute node historical-state.mjs com Node.js 24 ou superior e sua variável de ambiente BLOCKVECTRA_API_KEY definida. Ele usa o endpoint autenticado, mantém o mesmo contrato e calldata e compara latest, um bloco recente fixo e um bloco fora da janela autenticada publicada. Cada saída inclui o status HTTP real e o corpo JSON-RPC; um HTTP 200 ainda pode conter um erro. Ele é interrompido diante de uma resposta inesperada em vez de tratá-la como uma leitura bem-sucedida.

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

A resposta registrada acima usa public.url; o script usa uma API key. Para fazer uma leitura sem chave, obtenha a URL diretamente de public.url, omita a chave e escolha um bloco dentro de public.history_blocks bem como da janela de estado. Alterar a autenticação pode alterar o histórico permitido, mesmo para o mesmo contrato e calldata.

Diagnosticar um erro fora da janela

No mesmo endpoint sem chave, uma chamada amostrada em 2026-10-08 (UTC) alterando apenas o bloco de destino para 0x18ef650 (e o ID da requisição) retornou HTTP 200 com error.code: -32011, error.data.reason: state_window e error.data.retryable: false. Sua mensagem foi block reference is outside the public history window. Essa é uma falha de histórico público; o endpoint autenticado possui sua própria janela de estado.

Use estes campos da entrada de erro state_window para identificar a falha em vez de confiar em um número de janela específico na mensagem:

CampoValor documentado ou significado
Status HTTP200; inspecione o error JSON-RPC mesmo quando o HTTP for bem-sucedido
error.code-32011
error.messageErros de janela de estado autenticada descrevem a contagem de blocos suportados mais recente; erros de histórico público podem usar uma mensagem diferente
error.data.reasonstate_window
error.data.docs_urlLink para a explicação de state_window no catálogo de erros
error.data.retryablefalse: enviar a mesma requisição mais tarde não restaura o estado mais antigo

Escolha um bloco numerado mais recente ou use latest se a tarefa precisar do valor atual. Reduzir um intervalo de eth_getLogs não recupera o estado histórico de eth_call. Outros motivos para -32011 têm ações diferentes: range_not_indexed exige um intervalo coberto; history_not_ready permite nova tentativa após a indexação alcançar a rede. Inspecione error.data.reason, e não apenas o código numérico.

O estado subjacente também pode estar indisponível com -32000, ou o histórico de blocos podado com 4444; consulte o catálogo de erros. Não tente novamente um bloco antigo sem alteração nem presuma que uma janela declarada maior garanta todas as respostas.

Escolher a próxima consulta

Para uma lista completa de verificação de carga de trabalho e autotestes, comece com Como escolher um provedor RPC.

Ao escolher um provedor para leituras repetidas de contratos, compare orçamentos diários e de ciclo para leituras EVM. Verifique primeiro os blocos históricos necessários e, em seguida, planeje a distribuição diária e a taxa de transferência da tarefa; encaixar-se em um orçamento de créditos não estabelece cobertura de estado.

Ao comparar provedores para leituras históricas, primeiro confirme que ambos podem atender ao bloco de destino. A comparação de excedente em requisições full compara preços de RU adicionais com custos baseados em métodos, separa a cota incluída do uso excedente e explica as classes de cobrança full versus archive.

Para blocos indexados anteriores, transações, transferências ou outros conjuntos de dados, consulte os conjuntos de dados declarados da Data API na tabela e a referência da Data API. Registros indexados não oferecem execução histórica arbitrária de contratos nem implicam que todas as redes tenham saldos históricos.

Última atualização:

Nesta página