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

> Source: https://docs.blockvectra.com/th/guides/getlogs-block-range/

## คำตอบโดยตรง

คำขอ `eth_getLogs` รายการเดียวถูกจำกัดไว้ที่ `max_logs_block_range` ของเชนเป้าหมายจาก [GET /v1/chains](https://api.blockvectra.com/v1/chains) (สำหรับ HyperEVM คือ 1,000 บล็อก) โดยนับจำนวนบล็อกเป็น `toBlock − fromBlock + 1` การส่งคำขอเกินกว่านี้จะส่งกลับ HTTP 200, JSON-RPC `-32602` และ `error.data.reason: logs_range_too_large` พร้อม `retryable: false` (ดู [สารบัญข้อผิดพลาด](https://docs.blockvectra.com/en/errors/#logs_range_too_large)) ให้แบ่งช่วงออกเป็น `[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

[พารามิเตอร์ของเชนและตัวเลือกการเข้าถึง](https://blockvectra.com/en/chains/hyperevm_mainnet/)

บันทึกไฟล์นี้เป็น `logs-minimal.mjs`, ตั้งค่า `BLOCKVECTRA_API_KEY`, แอดเดรสของสัญญา `LOG_ADDRESS` และช่วงบล็อกที่ได้รับการยืนยันแล้วใน `FROM_BLOCK` และ `TO_BLOCK` จากนั้นรัน `node logs-minimal.mjs` ด้วย Node.js 24 ขึ้นไป เลือกเชนด้วย `CHAIN`; ค่าเริ่มต้นคือ `robinhood_mainnet`

```js
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` (เชนต่างๆ แสดงอยู่ใน [เชนที่รองรับ](https://docs.blockvectra.com/en/chains/)) endpoint นี้ไม่ต้องยืนยันตัวตนและไม่มีการคิดค่าบริการ เมื่อพัฒนาแอปพลิเคชันฝั่งไคลเอนต์ ให้คิวรี endpoint นี้แบบไดนามิกขณะรันไทม์แทนที่จะฮาร์ดโค้ดขีดจำกัดช่วงบล็อกลงในโค้ดของคุณ

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

## ขีดจำกัด eth\_getLogs ของแต่ละเชน

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

| เชน | Slug เชน | 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](https://docs.blockvectra.com/en/errors/#logs_range_too_large)                                                                                              | `<N>` คือ `max_logs_block_range` ของเชน; ให้ลดช่วงบล็อกลงก่อนส่งใหม่ การลองใหม่โดยไม่เปลี่ยนค่าจะไม่ช่วยแก้ปัญหา                        |
| `query block range exceeds server limit, narrow your filter: <N>`                     | [ซอร์สโค้ด eth\_getLogs ของ Erigon](https://github.com/erigontech/erigon/blob/9e603d74f60c21ca793a03a7ce373de19aa3fdc7/rpc/jsonrpc/eth_receipts.go#L343-L347) | `<N>` คือขีดจำกัดช่วงของโหนดนั้น; ให้ลดช่วงที่คิวรีลงก่อนส่งใหม่                                                                        |
| `query returns too many logs, narrow your filter: <N>`                                | [ซอร์สโค้ด eth\_getLogs ของ Erigon](https://github.com/erigontech/erigon/blob/9e603d74f60c21ca793a03a7ce373de19aa3fdc7/rpc/jsonrpc/eth_receipts.go#L439-L442) | `<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` ปัจจุบันของเชนเป้าหมาย:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_getLogs",
  "params": [
    {
      "fromBlock": "0x45a2409",
      "toBlock": "0x45a27f1"
    }
  ]
}
```

### ตัวอย่างการตอบกลับ

ตัวอย่างการตอบกลับข้อผิดพลาดที่เกี่ยวข้อง:

```json
{
  "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` เพื่อสาธิตการคิวรีแบบแบ่งส่วน:

**cURL**

```bash
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"
    }]
  }'
```


  **TypeScript**

```ts
const CHAIN = "robinhood_mainnet";
const RPC_ENDPOINT = "https://api.blockvectra.com/v1/robinhood_mainnet";

// 1. Fetch max_logs_block_range from the public GET /v1/chains endpoint (unauthenticated, unbilled)
const chainsUrl = new URL("/v1/chains", RPC_ENDPOINT);
const chainsRes = await fetch(chainsUrl);
const { chains } = (await chainsRes.json()) as {
  chains: Array<{ chain: string; max_logs_block_range: number }>;
};

const targetChain = chains.find((c) => c.chain === CHAIN);
if (!targetChain) {
  throw new Error(`Chain ${CHAIN} not found`);
}

const maxRange = targetChain.max_logs_block_range;

// 2. Query chunks sequentially over [from, from + max - 1] and aggregate results (both endpoints inclusive)
const fromBlock = 0x45a2409;
const toBlock = 0x45a2900;

const allLogs: unknown[] = [];
let cur = fromBlock;

while (cur <= toBlock) {
  const chunkEnd = Math.min(cur + maxRange - 1, toBlock);

  const res = await fetch(RPC_ENDPOINT, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
    },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "eth_getLogs",
      params: [
        {
          address: "0x1111111111111111111111111111111111111111",
          fromBlock: "0x" + cur.toString(16),
          toBlock: "0x" + chunkEnd.toString(16),
        },
      ],
    }),
  });

  const body = (await res.json()) as {
    result?: unknown[];
    error?: { code: number; message: string };
  };

  if (body.error) {
    throw new Error(`eth_getLogs error ${body.error.code}: ${body.error.message}`);
  }

  if (body.result) {
    allLogs.push(...body.result);
  }

  cur = chunkEnd + 1;
}

console.log(`Fetched ${allLogs.length} logs across blocks`);

// npx tsx example.mts
```


  **Python**

```python
import os
from urllib.parse import urljoin
import requests

CHAIN = "robinhood_mainnet"
RPC_ENDPOINT = "https://api.blockvectra.com/v1/robinhood_mainnet"

# 1. Fetch max_logs_block_range from the public GET /v1/chains endpoint (unauthenticated, unbilled)
chains_url = urljoin(RPC_ENDPOINT, "/v1/chains")
chains_res = requests.get(chains_url)
chains_res.raise_for_status()

chains = chains_res.json().get("chains", [])
target_chain = next((c for c in chains if c["chain"] == CHAIN), None)
if not target_chain:
    raise RuntimeError(f"Chain {CHAIN} not found")

max_range = target_chain["max_logs_block_range"]

# 2. Query chunks sequentially over [from, from + max - 1] and aggregate results (both endpoints inclusive)
from_block = 0x45a2409
to_block = 0x45a2900

all_logs: list = []
cur = from_block

while cur <= to_block:
    chunk_end = min(cur + max_range - 1, to_block)

    res = requests.post(
        RPC_ENDPOINT,
        headers={
            "Content-Type": "application/json",
            "x-api-key": os.environ["BLOCKVECTRA_API_KEY"],
        },
        json={
            "jsonrpc": "2.0",
            "id": 1,
            "method": "eth_getLogs",
            "params": [
                {
                    "address": "0x1111111111111111111111111111111111111111",
                    "fromBlock": hex(cur),
                    "toBlock": hex(chunk_end),
                }
            ],
        },
    )
    res.raise_for_status()
    body = res.json()

    if "error" in body:
        err = body["error"]
        raise RuntimeError(f"eth_getLogs error {err.get('code')}: {err.get('message')}")

    all_logs.extend(body.get("result", []))
    cur = chunk_end + 1

print(f"Fetched {len(all_logs)} logs across blocks")
```


## ข้อควรพิจารณาสำหรับคำขอแบบ 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`; โปรดดู [สิ่งที่ไม่คิดค่าบริการ: รหัสข้อผิดพลาดและกฎการเรียกเก็บเงิน](https://docs.blockvectra.com/en/guides/billing-rules/) สำหรับรายละเอียดการลองใหม่และการเรียกเก็บเงิน

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

## คู่มือและกฎการเรียกเก็บเงินที่เกี่ยวข้อง

* ดู [ข้อมูลอ้างอิงเมธอด eth\_getLogs](https://docs.blockvectra.com/en/api/json-rpc/methods/eth_getLogs/) สำหรับพารามิเตอร์ตัวกรอง, ค่าส่งกลับ และค่าน้ำหนัก CU
* ดู [ข้อมูลอ้างอิงข้อผิดพลาด logs\_range\_too\_large](https://docs.blockvectra.com/en/errors/#logs_range_too_large) สำหรับรายละเอียดข้อผิดพลาดและการดำเนินการที่แนะนำ
* สำหรับการเปรียบเทียบระหว่าง `eth_getLogs` และ endpoints การโอนของ Data API (การโอนของแอดเดรสและการโอนโทเค็น) รวมถึงความแตกต่างด้านความครอบคลุมและความเป็นที่สิ้นสุด (finality) โปรดดู [ข้อมูลโหนดล่าสุดเทียบกับประวัติที่ทำดัชนี: เมื่อใดควรใช้ eth\_getLogs และเมื่อใดควรใช้ Transfers API](https://docs.blockvectra.com/en/guides/logs-vs-transfers/)
* สำหรับรายละเอียดทั้งหมดเกี่ยวกับ compute unit (CU), การชำระบัญชีรายชั่วโมง และการตอบกลับข้อผิดพลาดที่ไม่คิดค่าบริการ โปรดดู [สิ่งที่ไม่คิดค่าบริการ: รหัสข้อผิดพลาดและกฎการเรียกเก็บเงิน](https://docs.blockvectra.com/en/guides/billing-rules/)

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

* [เลือกดูสารบบชุดข้อมูล](https://blockvectra.com/en/data/) เพื่อดูทุกชุดข้อมูลที่ BlockVectra ทำดัชนี
* [ดูแผนบริการฟรีและราคา](https://blockvectra.com/en/pricing/#free) เพื่อตรวจสอบสิ่งที่บัญชีของคุณได้รับ
* [เข้าสู่ระบบคอนโซล](https://console.blockvectra.com/login/?next=%2Fkeys%2F) เพื่อสร้าง API key
