지원되는 윈도우 내에서 과거 EVM 상태 조회
인증된 상태 윈도우, 키 없는 과거 데이터 및 로그 범위를 구분합니다. eth_call을 위한 고정 블록을 선택하고 state_window 오류를 진단하세요.
과거 시점의 eth_call은 체인의 eth_getLogs 블록 범위 제한이 아니라 체인의 상태 윈도우(state window)에 따라 결정됩니다. 이전 컨트랙트 값을 읽기 전에 상태 윈도우, 엔드포인트의 인증 모드, 대상 블록을 확인하세요.
세 가지 서로 다른 과거 데이터 제한
| 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 Agent는 상태 윈도우와 로그 쿼리 범위를 각각 확인해야 합니다. 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와 같은 16진수 수량으로 변환합니다. 비교 대상이 되는 모든 호출에서 해당 번호를 고정하여 사용하세요. latest를 반복 호출하면 서로 다른 블록이 사용될 수 있습니다.
상태 조회의 경우 상태 윈도우 정책에 따라 earliest, safe, finalized는 -32011을 반환합니다. 대신 선언된 윈도우 내의 명시적인 블록 번호를 지정하세요. 블록 해시 형식으로 요청한다고 해서 추가 과거 데이터를 얻을 수 있는 것은 아닙니다. 키 없는 상태 읽기에서는 거부되며, 인증된 요청 역시 제공 가능한 상태 범위에 종속됩니다.
블록 번호는 체인 재구성(reorg) 후 다른 블록을 가리킬 수 있습니다. 결과 블록을 정확히 식별해야 한다면 eth_getBlockByNumber로 블록 해시를 함께 기록하세요. 또한 윈도우 내의 블록 번호라 하더라도 동기화된 체인 상태와 해당 높이에 컨트랙트가 실제로 존재해야 합니다.
고정 블록 컨트랙트 조회
Ethereum에서 WETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)는 선택자 0x313ce567을 갖는 decimals()를 제공합니다. 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.js 24 이상에서 BLOCKVECTRA_API_KEY 환경 변수를 설정한 후 node historical-state.mjs를 실행하세요. 인증된 엔드포인트를 사용하고 동일한 컨트랙트 및 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를 사용합니다. 키 없는 조회를 수행하려면 public.url에서 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 status | 200; HTTP가 성공하더라도 JSON-RPC error를 검사하세요 |
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 요금제.
최종 수정일: