ขีดจำกัดช่วงบล็อกของ eth_getLogs และการคิวรีแบบแบ่งส่วน

สำหรับ logs_range_too_large ให้อ่าน max_logs_block_range ของเชน แบ่งช่วงบล็อกแบบรวมจุดสิ้นสุดให้อยู่ภายในขีดจำกัดดังกล่าว และขยับต่อไปหลังจากที่ chunk ปัจจุบันทำงานสำเร็จแล้วเท่านั้น

คำตอบโดยตรง

คำขอ eth_getLogs รายการเดียวถูกจำกัดไว้ที่ max_logs_block_range ของเชนเป้าหมายจาก GET /v1/chains (สำหรับ 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)] และขยับไปยังจุดสิ้นสุดของ chunk ก่อนหน้ารวมไปอีกหนึ่งหลังจากสำเร็จ

  • ขั้นตอนแรก: รัน curl -s "https://api.blockvectra.com/v1/chains" และอ่าน max_logs_block_range, methods.allow และ methods.deny ของเชนเป้าหมาย
  • สำเร็จเมื่อ: logs-minimal.mjs แสดงผล fromBlock, toBlock และอาร์เรย์ result ของแต่ละ chunk ที่เสร็จสมบูรณ์จนถึง TO_BLOCK ที่คุณเลือก โดยไม่มีข้อผิดพลาด HTTP หรือ JSON-RPC

พารามิเตอร์ของเชนและตัวเลือกการเข้าถึง

บันทึกไฟล์นี้เป็น 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;
}

แต่ละบรรทัดที่แสดงผลคือ chunk ที่เสร็จสมบูรณ์ ข้อผิดพลาด HTTP หรือ JSON-RPC ใดๆ จะหยุดการทำงานของตัวอย่างโดยไม่ข้าม chunk ที่ล้มเหลว โปรดดูคำแนะนำเกี่ยวกับ batch และการจำกัดอัตราด้านล่างสำหรับการจัดการ 429

ขีดจำกัดช่วงบล็อกของ eth_getLogs

เมื่อเรียกใช้เมธอด JSON-RPC eth_getLogs ช่วงบล็อกของคำขอรายการเดียวจะคำนวณเป็น toBlock − fromBlock + 1 และไม่สามารถเกิน max_logs_block_range ที่ประกาศไว้ของเชนเป้าหมายได้

ขีดจำกัดนี้แตกต่างกันไปในแต่ละเชน พารามิเตอร์ของแต่ละเชนเผยแพร่ผ่าน endpoint สาธารณะ GET /v1/chains (เชนต่างๆ แสดงอยู่ใน เชนที่รองรับ) endpoint นี้ไม่ต้องยืนยันตัวตนและไม่มีการคิดค่าบริการ เมื่อพัฒนาแอปพลิเคชันฝั่งไคลเอนต์ ให้คิวรี endpoint นี้แบบไดนามิกขณะรันไทม์แทนที่จะฮาร์ดโค้ดขีดจำกัดช่วงบล็อกลงในโค้ดของคุณ

ฟิลด์ตัวกรอง fromBlock และ toBlock มีค่าเริ่มต้นเป็น latest เมื่อละเว้นหรือเป็น null

ขีดจำกัด eth_getLogs ของแต่ละเชน

นี่คือค่า max_logs_block_range ของแต่ละเชนที่เผยแพร่โดย GET /v1/chains ข้อความ "ไม่เผยแพร่" ไม่ได้หมายความว่าไม่จำกัด โปรดตรวจสอบ methods.allow และ methods.deny ก่อนเรียกใช้ด้วยเช่นกัน โดยที่ deny จะมีความสำคัญกว่า; ขีดจำกัดช่วงบล็อกจะแยกต่างหากจากขีดจำกัดจำนวนผลลัพธ์หรือระยะเวลาการคิวรี

เชนSlug เชนmax_logs_block_range (บล็อก)
Arbitrum Onearb_mainnet1,000
Basebase_mainnet1,000
BNB Smart Chainbsc_mainnet1,000
Ethereumeth_mainnet1,000
Ethereum Sepoliaeth_sepolia1,000
HyperEVMhyperevm_mainnet1,000
Polygonpolygon_mainnet1,000
Robinhood Chainrobinhood_mainnet1,000
Robinhood Chain Testnetrobinhood_testnet1,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>ซอร์สโค้ด eth_getLogs ของ Erigon<N> คือขีดจำกัดช่วงของโหนดนั้น; ให้ลดช่วงที่คิวรีลงก่อนส่งใหม่
query returns too many logs, narrow your filter: <N>ซอร์สโค้ด eth_getLogs ของ Erigon<N> คือขีดจำกัดผลลัพธ์ของโหนดนั้น; ให้ลดช่วงและจำกัด address และ topics ให้แคบลง บล็อกเดียวอาจยังคงต้องใช้ตัวกรองที่เจาะจงมากขึ้น

ในเทมเพลตข้อความเหล่านี้ <N> จะถูกแทนที่ด้วยขีดจำกัดของ endpoint ข้อความจากบุคคลภายนอกจะอ้างอิงถึง endpoint และขีดจำกัดของตนเอง; สำนวนข้อความอาจแตกต่างกันตามเวอร์ชันของไคลเอนต์ สำหรับ 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)

ในคำขอแบบ batch ที่มีการเรียกหลายรายการ หากการเรียก eth_getLogs ใดเกินขีดจำกัดช่วงบล็อก รายการนั้นจะส่งกลับข้อผิดพลาด -32602 ข้างต้นและไม่คิดค่าบริการ

การดำเนินการคิวรีแบบแบ่งส่วน

ในการคิวรี log ในช่วงบล็อกขนาดใหญ่ อันดับแรกให้คิวรี max_logs_block_range ของเชนเป้าหมาย แบ่งช่วงเป้าหมายออกเป็น chunk ที่ต่อเนื่องกันขนาด [from, from + max - 1] และส่งคำขอตามลำดับพร้อมกับรวบรวมผลลัพธ์

ตัวอย่างต่อไปนี้ใช้ robinhood_mainnet เพื่อสาธิตการคิวรีแบบแบ่งส่วน:

export BLOCKVECTRA_API_KEY="rgw_your_api_key"

# 1. Read max_logs_block_range from the public chains endpoint (unauthenticated, unbilled)
curl -s "https://api.blockvectra.com/v1/chains"

# 2. Make a single compliant request within the chain's max_logs_block_range (toBlock - fromBlock + 1)
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"
    }]
  }'

ข้อควรพิจารณาสำหรับคำขอแบบ Batch

หากคุณพิจารณาที่จะรวมการคิวรีแบบแบ่งส่วนหลายรายการไว้ในคำขอ JSON-RPC batch เดียว โปรดคำนึงถึงกฎของ batch และ burst capacity:

  • ขีดจำกัดขนาดของ batch: คำขอแบบ batch รับได้ตั้งแต่ 1 ถึง 100 การเรียก การส่งมากกว่า 100 การเรียกจะถูกปฏิเสธด้วย HTTP 200 และรหัสข้อผิดพลาด -32600 batch too large: max 100 calls (ไม่คิดค่าบริการ)
  • ความจุ burst ของคำขอเดี่ยว: หากผลรวมค่าน้ำหนัก CU ของการเรียกในหนึ่งคำขอเกินความจุ burst ของคีย์ (burst_cu) คำขอจะถูกปฏิเสธด้วย HTTP 429 -32022 request cost <N> CU exceeds burst capacity <M> CU (ไม่คิดค่าบริการ); ให้แยกออกเป็น batch ที่เล็กลง
  • ความจุใน bucket ไม่เพียงพอ: หากผลรวมของค่าน้ำหนักเต็มไม่เกินความจุ burst แต่ token bucket มีความจุที่ใช้ได้ไม่เพียงพอ บริการจะส่งกลับ HTTP 429 พร้อมรหัสข้อผิดพลาด -32005 rate limit exceeded และ Retry-After; โปรดดู สิ่งที่ไม่คิดค่าบริการ: รหัสข้อผิดพลาดและกฎการเรียกเก็บเงิน สำหรับรายละเอียดการลองใหม่และการเรียกเก็บเงิน

ดังนั้น เมื่อดำเนินการคิวรี log ในปริมาณมาก จึงแนะนำให้ทำการคิวรีแบบแบ่งส่วนตามลำดับ; หากใช้ batch ให้รักษาจำนวนการเรียกต่อ batch ให้มีขนาดเล็กพอเพื่อให้ผลรวมของค่าน้ำหนักเต็มยังคงอยู่ภายในความจุ burst

ขั้นตอนถัดไป

อัปเดตล่าสุด:

ในหน้านี้