eth_getLogs 區塊跨度上限與分段查詢
處理 eth_getLogs 區塊範圍限制與 logs_range_too_large 報錯:讀取各鏈的 max_logs_block_range,將大跨度查詢切分為多個區段。
直接答案
單次 eth_getLogs 的上限是目標鏈在 GET /v1/chains 中的 max_logs_block_range(HyperEVM 為 1,000 個區塊),區塊數按 toBlock − fromBlock + 1 計算。超限回傳 HTTP 200、JSON-RPC -32602 與 error.data.reason: logs_range_too_large,且 retryable: false(見錯誤目錄)。將區間分成 [from, min(from + max − 1, end)],成功後從上一段末尾加一繼續。
將以下程式碼儲存為 logs-minimal.mjs,設定環境變數 BLOCKVECTRA_API_KEY、合約地址 LOG_ADDRESS 及已確認的區塊範圍 FROM_BLOCK、TO_BLOCK,然後執行 node logs-minimal.mjs(Node.js 24 或以上)。用 CHAIN 選擇目標鏈;預設使用 robinhood_mainnet。
const { BLOCKVECTRA_API_KEY: key, LOG_ADDRESS: address, FROM_BLOCK, TO_BLOCK } = process.env;
if (!key || !/^0x[0-9a-f]{40}$/i.test(address ?? '')) throw new Error('Set BLOCKVECTRA_API_KEY and LOG_ADDRESS');
if (![FROM_BLOCK, TO_BLOCK].every(value => /^(0x[0-9a-f]+|[0-9]+)$/i.test(value ?? ''))) {
throw new Error('Set FROM_BLOCK and TO_BLOCK to nonnegative block numbers');
}
const start = BigInt(FROM_BLOCK), end = BigInt(TO_BLOCK);
if (start > end) throw new Error('FROM_BLOCK must not exceed TO_BLOCK');
const chainSlug = process.env.CHAIN ?? 'robinhood_mainnet';
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 === chainSlug);
if (!chain || !Number.isSafeInteger(chain.max_logs_block_range) || chain.max_logs_block_range <= 0) {
throw new Error('Missing or invalid max_logs_block_range');
}
const matches = pattern => pattern.endsWith('*') ? 'eth_getLogs'.startsWith(pattern.slice(0, -1)) : pattern === 'eth_getLogs';
if (!chain.methods?.allow?.some(matches) || chain.methods?.deny?.some(matches)) {
throw new Error('eth_getLogs is unavailable on this chain');
}
const max = BigInt(chain.max_logs_block_range);
const rpcUrl = new URL(`./${chainSlug}`, chainsUrl).href;
const hex = value => `0x${value.toString(16)}`;
for (let from = start; from <= end;) {
const to = from + max - 1n < end ? from + max - 1n : end;
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: 1, method: 'eth_getLogs',
params: [{ address, fromBlock: hex(from), toBlock: hex(to) }] }),
});
const body = await response.json();
if (!response.ok || body.error || !Array.isArray(body.result)) {
throw new Error(`RPC HTTP ${response.status}: ${JSON.stringify(body.error ?? 'Invalid result')}`);
}
console.log(JSON.stringify({ fromBlock: hex(from), toBlock: hex(to), result: body.result }));
from = to + 1n;
}每行輸出一個已成功區段;任何 HTTP 或 JSON-RPC 錯誤都會終止範例,不會跳過失敗區段。429 處理見下方批次與速率限制說明。
eth_getLogs 的區塊跨度上限
在呼叫 JSON-RPC 方法 eth_getLogs 時,單次請求的區塊跨度按照 toBlock − fromBlock + 1 計算,不能超過目標鏈透過 GET /v1/chains 公布的 max_logs_block_range 上限。
該限制因鏈而異——各鏈的參數透過公開端點 GET /v1/chains 發布(鏈清單見支援的鏈)。該端點免驗證、不計費。在編寫用戶端程式碼時,請在執行時透過該端點動態讀取目標鏈的 max_logs_block_range,切勿將上限數值寫死在程式碼中。
過濾參數 fromBlock 與 toBlock 省略或為 null 時,按 latest 處理。
各鏈 eth_getLogs 上限
以下為 GET /v1/chains 公布的各鏈 max_logs_block_range;「未公布」不表示無限制。呼叫前同時核對該鏈的 methods.allow 與 methods.deny,其中 deny 優先;區塊跨度上限不代表結果數量或查詢耗時上限。
| 鏈 | 鏈識別碼 | max_logs_block_range(區塊數) |
|---|---|---|
| Arbitrum One | arb_mainnet | 1,000 |
| Base | base_mainnet | 1,000 |
| BNB Smart Chain | bsc_mainnet | 1,000 |
| Ethereum | eth_mainnet | 1,000 |
| Ethereum Sepolia | eth_sepolia | 1,000 |
| HyperEVM | hyperevm_mainnet | 1,000 |
| Polygon | polygon_mainnet | 1,000 |
| Robinhood Chain | robinhood_mainnet | 1,000 |
| Robinhood Chain Testnet | robinhood_testnet | 1,000 |
常見報錯原文
先區分區塊跨度、結果數量與查詢耗時;同一個 JSON-RPC 錯誤碼可能代表不同問題。
| 報錯原文 / 識別代號 | 出處 | 處理方式 |
|---|---|---|
eth_getLogs block range too large: max <N> blocks;-32602;logs_range_too_large | BlockVectra 錯誤目錄 | <N> 是該鏈的 max_logs_block_range;縮小跨度後重發,原樣重試無效。 |
query block range exceeds server limit, narrow your filter: <N> | Erigon eth_getLogs 原始碼 | <N> 是該節點的區塊範圍上限;縮小查詢區間後重發。 |
query returns too many logs, narrow your filter: <N> | Erigon eth_getLogs 原始碼 | <N> 是該節點的結果數量上限;縮小區間,並用 address、topics 收窄過濾。即使只查一個區塊,也可能需要更精確的過濾條件。 |
以上報錯範本中的 <N> 在實際回應中替換為端點上限。第三方原文對應其自身的端點與限制,措辭可能隨用戶端版本變化;使用 BlockVectra 時,以 /v1/chains 和 error.data.reason 為準。
超出跨度上限的表現
當單次請求的區塊跨度 toBlock − fromBlock + 1 超過該鏈的 max_logs_block_range 時,請求回傳 HTTP 200 與 JSON-RPC 錯誤:
- 錯誤碼:
-32602 - 錯誤訊息:
eth_getLogs block range too large: max <N> blocks - 計費狀態:不計費。
範例請求
以下請求僅在區塊跨度大於目標鏈目前的 max_logs_block_range 時超限:
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getLogs",
"params": [
{
"fromBlock": "0x45a2409",
"toBlock": "0x45a27f1"
}
]
}範例回應
超出上限時回傳的錯誤回應範例:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "eth_getLogs block range too large: max <N> blocks"
}
}其中 <N> 為該鏈的 max_logs_block_range(透過 GET /v1/chains 發布)。
在包含多個呼叫的批次請求中,如果其中某個 eth_getLogs 跨度過大,該呼叫同樣會在對應位置回傳上述 -32602 錯誤,且該呼叫不計費。
分段查詢實作
當需要檢索跨越較長區間的日誌時,應先讀取目標鏈的 max_logs_block_range,再將目標區間按照 [from, from + max - 1] 劃分為若干段閉區間,按順序逐段請求並合併結果。
以下範例以 robinhood_mainnet 為例示範分段查詢流程:
export BLOCKVECTRA_API_KEY="rgw_your_api_key"
# 1. 從公開端點讀取目標鏈的 max_logs_block_range(免驗證、不計費)
curl -s "https://api.blockvectra.com/v1/chains"
# 2. 發起單次合規請求:區塊跨度(toBlock - fromBlock + 1)不超過該鏈的 max_logs_block_range
curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
-H 'Content-Type: application/json' \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getLogs",
"params": [{
"address": "0x1111111111111111111111111111111111111111",
"fromBlock": "0x45a2409",
"toBlock": "0x45a246c"
}]
}'批次請求注意事項
若考慮將切分後的多個分段呼叫打包進單個 JSON-RPC 批次請求,需要遵循批次與突發上限規則:
- 批次大小限制:批次請求支援 1~100 個呼叫;超過 100 個呼叫會被直接拒絕,回傳 HTTP 200 與錯誤碼
-32600 batch too large: max 100 calls(不計費)。 - 單請求突發上限:若單次請求內所有呼叫的 CU 權重之和超過該 key 的突發容量(
burst_cu),請求會被拒絕並回傳 HTTP 429-32022 request cost <N> CU exceeds burst capacity <M> CU(不計費);請拆分成更小的批次。 - 權杖桶容量不足:若單請求滿權重之和未超過突發上限,但目前權杖桶內可用容量不足,服務回傳 HTTP 429 與錯誤碼
-32005 rate limit exceeded(帶Retry-After),詳見哪些情況不扣費:錯誤碼與計費規則。
因此,在大跨度日誌查詢時,建議採用循序逐段請求;若使用批次請求,應嚴格控制批內呼叫數量,避免滿權重之和超出突發上限。
相關指南與計費規則
- 參閱 eth_getLogs 方法參考以取得過濾參數、回傳值與 CU 權重。
- 參閱 logs_range_too_large 錯誤參考以取得錯誤詳情與建議處理動作。
- 關於
eth_getLogs與 Data API 轉帳端點(地址轉帳與代幣轉帳)的功能定位、覆蓋範圍及最終性差異,請參閱節點近況與已索引歷史:何時使用 eth_getLogs,何時使用轉帳 API。 - 關於計算單位(CU)、每小時結算與不計費錯誤回應的完整說明,請參閱哪些情況不扣費:錯誤碼與計費規則。
下一步
最後更新: