ขีดจำกัดอัตรา HyperEVM RPC และการดึงข้อมูล log ย้อนหลัง
บน BlockVectra คำขอ eth_getLogs ที่มีการยืนยันตัวตนของ HyperEVM ครอบคลุมสูงสุด 1,000 บล็อก โดยนับรวมจุดสิ้นสุดทั้งสองฝั่ง; ให้แบ่งช่วงเวลาที่ยาวขึ้นและบันทึกบล็อกล่าสุดที่เสร็จสมบูรณ์เพื่อกลับมาดำเนินการต่อ
คำตอบโดยตรง
HyperEVM public RPC อย่างเป็นทางการที่เป็นค่าเริ่มต้นอนุญาต 50 บล็อกต่อหนึ่งคิวรี eth_getLogs (แหล่งข้อมูล: เอกสาร JSON-RPC ทางการของ Hyperliquid) บน BlockVectra คำขอ eth_getLogs ที่มีการยืนยันตัวตนครอบคลุมสูงสุด 1,000 บล็อกต่อหนึ่งคิวรี (hyperevm_mainnet.max_logs_block_range จาก GET /v1/chains) โดยนับรวมจุดสิ้นสุดทั้งสองฝั่ง ช่วงที่กว้างกว่านี้จะส่งกลับ HTTP 200, JSON-RPC -32602 และ logs_range_too_large พร้อม retryable: false (ดู สารบัญข้อผิดพลาด); ให้แบ่งเป็น [from, min(from + max − 1, end)] บันทึกเคอร์เซอร์ของคุณ และขยับไปยังจุดสิ้นสุดบวกหนึ่งหลังจากสำเร็จเพื่อดำเนินการต่อ ขีดจำกัดอัตราต่อ IP ของ public RPC อย่างเป็นทางการและขีดจำกัดของคีย์ของ BlockVectra ได้รับการอธิบายแยกต่างหากใน ขีดจำกัดอัตราของ public RPC อย่างเป็นทางการและ 429 และพารามิเตอร์การให้บริการด้านล่าง
- ขั้นตอนแรก: อ่านบล็อกล่าสุดโดยไม่ต้องใช้ API key โดยใช้คำสั่ง curl ด้านล่าง
- สำเร็จเมื่อ: สคริปต์ดึงข้อมูลย้อนหลังแสดงผล
fromBlock,toBlockและอาร์เรย์resultสำหรับทุก chunk ในช่วงที่คุณเลือก; อาร์เรย์ว่างหมายถึงไม่มี log ที่ตรงกันใน chunk นั้น
พารามิเตอร์ของเชนและตัวเลือกการเข้าถึง
งานที่คู่มือนี้ช่วยให้คุณทำสำเร็จ
- ตรวจสอบ HyperEVM RPC ด้วยการอ่านแบบสาธารณะโดยใช้ viem หรือ ethers ก่อนเลือกเมธอดที่มีการยืนยันตัวตน
- ดึงข้อมูล log ย้อนหลังในช่วงที่จำกัดขอบเขต ให้อยู่ภายในขีดจำกัด
eth_getLogsของ HyperEVM พร้อมการตัดสินใจลองใหม่ตามข้อผิดพลาดที่ได้รับกลับมา - อ่านกิจกรรมของแอดเดรส ผ่านธุรกรรมและการโอนที่ทำดัชนีไว้ด้วยคีย์ พร้อมตรวจสอบข้อมูลเมทาดาตาความครอบคลุมและความสดใหม่ที่ส่งกลับมา
งาน 3 ขั้นตอน: ดึงข้อมูล log ของ HyperEVM ย้อนหลังในช่วงที่จำกัดขอบเขต
อ่านบล็อกล่าสุดโดยไม่ต้องใช้คีย์, สร้างคีย์, จากนั้นดึง event log สำหรับสัญญาในช่วงบล็อกที่จำกัด
เลือกสัญญาและช่วงบล็อกที่คุณต้องการ งานนี้ครอบคลุมช่วงที่จำกัดนั้น; ไม่ได้รับประกันประวัติสัญญาที่สมบูรณ์ทั้งหมด
1. อ่านบล็อกล่าสุดโดยไม่ต้องใช้ API key
curl -sS "https://api.blockvectra.com/v1/hyperevm_mainnet/public" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'result ของ JSON-RPC คือหมายเลขบล็อกล่าสุดในรูปแบบเลขฐานสิบหก นี่คือ public.url ของ HyperEVM ที่เผยแพร่โดย GET /v1/chains เมธอด public.methods ของ endpoint สาธารณะไม่ได้รวม eth_getLogs; ขั้นตอนที่ 3 จำเป็นต้องใช้คีย์
2. สร้าง API key
สร้างคีย์สำหรับการดึงข้อมูลย้อนหลังนี้ สร้างคีย์และบันทึก secret ที่แสดงในกล่องโต้ตอบไว้สำหรับใช้งานกับ hyperevm_mainnet
สำหรับ AI Agent ที่ใช้ HTTP โดยไม่มีเบราว์เซอร์ ให้ทำตาม คู่มือการลงทะเบียนแบบโปรแกรม ส่ง ref ที่ถูกต้องของ URL คู่มือใน JSON body ของ POST /auth/siwe/login แทนที่จะเป็น docs-signup ของตัวอย่าง; ละเว้นได้หากไม่มี อย่าขอให้ผู้ใช้แปะคีย์ลงในแชท
3. ดึงข้อมูล log ย้อนหลังด้วยคีย์ของคุณ
เทมเพลตเริ่มต้นฉบับสมบูรณ์: blockvectra/hyperevm-backfill
บันทึกสคริปต์ต่อไปนี้เป็น hyperevm-task.ts ซึ่งรันด้วย Node.js 24 ขึ้นไป โดยไม่ต้องมีแพ็กเกจเพิ่มเติม ตั้งค่า BLOCKVECTRA_API_KEY เป็นคีย์ที่คุณบันทึกไว้ และ LOG_ADDRESS เป็นแอดเดรสของสัญญาที่ส่งเหตุการณ์ที่คุณต้องการตรวจสอบ; เก็บรักษาคีย์ไว้บนเซิร์ฟเวอร์หรือในเทอร์มินัลภายในเครื่องของคุณ
export BLOCKVECTRA_API_KEY='replace-with-your-key'
export LOG_ADDRESS='replace-with-contract-address'
node hyperevm-task.tsตามค่าเริ่มต้น สคริปต์จะดึงบล็อกล่าสุดจำนวน max_logs_block_range บล็อก หรือน้อยกว่านั้นหากอยู่ใกล้กับบล็อกเริ่มต้น (genesis) สคริปต์จะอ่านขีดจำกัดนั้นจาก /v1/chains ขณะรันไทม์ หากต้องการเลือกช่วงที่จำกัดอื่น ให้ตั้งค่าทั้ง FROM_BLOCK และ TO_BLOCK เป็นหมายเลขบล็อกแบบฐานสิบหรือฐานสิบหกขึ้นต้นด้วย 0x ก่อนรัน ช่วงที่ใหญ่ขึ้นจะถูกแบ่งออกเป็น chunk ต่อเนื่องกัน โดยแต่ละ chunk จะมีขนาดไม่เกินขีดจำกัดที่ประกาศไว้
const apiKey = process.env.BLOCKVECTRA_API_KEY;
const address = process.env.LOG_ADDRESS;
if (!apiKey || apiKey === "replace-with-your-key") throw new Error("Set BLOCKVECTRA_API_KEY");
if (!address || !/^0x[0-9a-f]{40}$/i.test(address)) throw new Error("Set LOG_ADDRESS to a contract address");
const fromBlock = process.env.FROM_BLOCK;
const toBlock = process.env.TO_BLOCK;
if ((fromBlock !== undefined || toBlock !== undefined) && (!fromBlock || !toBlock)) {
throw new Error("Set both FROM_BLOCK and TO_BLOCK");
}
const chainsUrl = "https://api.blockvectra.com/v1/chains";
const rpcUrl = new URL("./hyperevm_mainnet", chainsUrl).href;
async function readJson(url: string) {
const response = await fetch(url, { signal: AbortSignal.timeout(15_000) });
if (!response.ok) throw new Error(`Metadata HTTP ${response.status}`);
return response.json();
}
const catalog = await readJson(chainsUrl);
const chain = catalog.chains.find((item: { chain: string }) => item.chain === "hyperevm_mainnet");
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");
}
if (!chain.methods.allow.includes("eth_getLogs") || chain.methods.deny.includes("eth_getLogs")) {
throw new Error("eth_getLogs is unavailable on this chain");
}
const maxRange = BigInt(chain.max_logs_block_range);
const plans = await readJson("https://console-api.blockvectra.com/v1/plans");
function weight(method: string): bigint {
const row = plans.method_weights.find((item: { method: string }) => item.method === method);
if (!row || !Number.isSafeInteger(row.cu_weight) || row.cu_weight <= 0) {
throw new Error(`Missing or invalid CU weight for ${method}`);
}
return BigInt(row.cu_weight);
}
const headWeight = weight("eth_blockNumber");
const logsWeight = weight("eth_getLogs");
type RpcBody = {
result?: unknown;
error?: { code: number; data?: { retryable?: boolean } };
};
async function rpc(method: string, params: unknown[]): Promise<unknown> {
for (let attempt = 0; attempt < 4; attempt++) {
const response = await fetch(rpcUrl, {
method: "POST",
redirect: "error",
headers: { "Content-Type": "application/json", "x-api-key": apiKey! },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
signal: AbortSignal.timeout(15_000),
});
const body = await response.json() as RpcBody;
if (response.ok && !body.error && body.result !== undefined) return body.result;
if (body.error?.data?.retryable !== true || attempt === 3) {
throw new Error(`RPC failed: HTTP ${response.status}, code ${body.error?.code ?? "unknown"}`);
}
const retryAfter = response.headers.get("Retry-After");
const delay = retryAfter === null ? 0 : /^\d+$/.test(retryAfter)
? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now();
if (delay > 30_000) throw new Error("Retry-After exceeds 30 seconds; rerun later");
const backoff = 1000 * 2 ** attempt + Math.random() * 250;
await new Promise((resolve) => setTimeout(resolve, Math.max(backoff, Number.isFinite(delay) ? delay : 0)));
}
throw new Error("Retry limit reached");
}
function block(value: string): bigint {
if (!/^(0x[0-9a-f]+|[0-9]+)$/i.test(value)) throw new Error("Invalid block number");
return BigInt(value);
}
const head = await rpc("eth_blockNumber", []);
if (typeof head !== "string" || !/^0x[0-9a-f]+$/i.test(head)) throw new Error("Invalid chain head");
const latest = block(head);
const end = toBlock ? block(toBlock) : latest;
const start = fromBlock ? block(fromBlock)
: end >= maxRange - 1n ? end - maxRange + 1n : 0n;
if (start > end || end > latest) throw new Error("Require 0 <= FROM_BLOCK <= TO_BLOCK <= latest");
const chunks = (end - start + maxRange) / maxRange;
console.error(`Window ${start}..${end}; chunks=${chunks}; estimated CU=${headWeight + chunks * logsWeight}`);
const hex = (value: bigint) => `0x${value.toString(16)}`;
for (let from = start; from <= end; from += maxRange) {
const to = from + maxRange - 1n < end ? from + maxRange - 1n : end;
const result = await rpc("eth_getLogs", [{ address, fromBlock: hex(from), toBlock: hex(to) }]);
if (!Array.isArray(result)) throw new Error("Expected eth_getLogs result array");
console.log(JSON.stringify({ fromBlock: hex(from), toBlock: hex(to), result }));
}คำขอจะทำงานตามลำดับ ข้อผิดพลาด JSON-RPC จะได้รับการลองใหม่ก็ต่อเมื่อ error.data.retryable เป็น true โดยลองใหม่ได้สูงสุดสี่ครั้งต่อหนึ่งคำขอ พร้อม exponential backoff และ jitter รวมถึงรองรับ Retry-After ในรูปแบบวินาทีหรือวันที่ HTTP การรอที่นานกว่า 30 วินาทีจะหยุดการทำงานของสคริปต์เพื่อให้คุณสามารถรันใหม่ในภายหลัง ความล้มเหลวของเครือข่าย, การหมดเวลา, การตอบกลับที่ผิดรูปแบบ และข้อผิดพลาดที่ไม่สามารถลองใหม่ได้จะหยุดทำงานทันที; สคริปต์จะออกจากการทำงานแบบไม่สำเร็จแทนที่จะรายงานว่าการดึงข้อมูลย้อนหลังเสร็จสมบูรณ์
แต่ละบรรทัดที่แสดงผลบน standard output ประกอบด้วย fromBlock, toBlock และอาร์เรย์ result ของแต่ละ chunk โดยที่ result: [] หมายถึงไม่มี log ที่ตรงกันใน chunk นั้น ให้อ่านฟิลด์เหล่านี้ในแต่ละ log:
| ฟิลด์ | ความหมาย |
|---|---|
address | สัญญาที่ส่งเหตุการณ์ออกมา |
blockNumber, blockHash | บล็อกที่มี log; หมายเลขอยู่ในรูปแบบเลขฐานสิบหก |
transactionHash, transactionIndex, logIndex | ตำแหน่งธุรกรรมและ log; ดัชนีอยู่ในรูปแบบเลขฐานสิบหก |
topics, data | อาร์กิวเมนต์เหตุการณ์ที่ทำดัชนีและอาร์กิวเมนต์ที่ไม่ทำดัชนีซึ่งเข้ารหัสตาม ABI; ถอดรหัสด้วย ABI ของสัญญา |
removed | ระบุว่า log ถูกลบออกเนื่องจากการจัดระเบียบเชนใหม่ (chain reorganization) หรือไม่ |
บล็อกล่าสุดไม่ใช่เครื่องหมายบอกความเป็นที่สิ้นสุด (finality) หากคุณต้องการช่วงประวัติที่เสถียร ให้เลือก TO_BLOCK ที่ได้รับการยืนยันแล้วของแอปพลิเคชันของคุณ และจัดการกับการจัดระเบียบเชนใหม่ (reorg)
สำหรับช่วงที่มีขนาด B = TO_BLOCK − FROM_BLOCK + 1 บล็อกและขีดจำกัดที่ประกาศไว้ L จำนวน chunk จะเป็น N = ceil(B / L) ให้อ่าน method_weights[].cu_weight สำหรับ eth_getLogs และ eth_blockNumber จาก GET /v1/plans สคริปต์จะพิมพ์ค่าประมาณการไปยัง standard error: N × weight(eth_getLogs) + weight(eth_blockNumber) รวมถึงการค้นหา head ที่ใช้คีย์ด้วย ซึ่งไม่รวมการเรียกเพิ่มเติมและการลองใหม่ที่คิดค่าบริการ; โปรดดู กฎการเรียกเก็บเงิน สำหรับการชำระบัญชี CU ขึ้นอยู่กับจำนวนการเรียก ไม่ใช่จำนวน log ที่ส่งกลับมา
การส่งมอบเหตุการณ์: ใช้การโพลล์ HTTP แบบแบ่งส่วนด้านล่าง หรือส่งเหตุการณ์ของแอดเดรสที่ติดตามไปยังตัวรับ HTTPS ด้วย webhook push โดย GET /v1/push/chains จะแสดงรายการเชนที่รองรับ และการตั้งค่าการยืนยัน; ยืนยันตัวตนด้วย x-api-key ลายเซ็น webhook, การขจัดข้อมูลซ้ำ และการเล่นซ้ำมีอธิบายอยู่ในคู่มือนั้น ทั้งนี้ Webhook push จะแยกต่างหากจากการสมัครสมาชิก WebSocket (ws และ subscriptions ใน /v1/chains)
เชื่อมต่อด้วย viem หรือ ethers
| พารามิเตอร์ / เอนด์พอยต์ | ค่า / เทมเพลต | การยืนยันตัวตน |
|---|---|---|
| Chain ID (EIP-155) | 999 | — |
| JSON-RPC (คีย์ในพาธ) | POST https://api.blockvectra.com/v1/hyperevm_mainnet/{api_key} | API key ในพาธ URL |
| JSON-RPC (คีย์ในส่วนหัว) | POST https://api.blockvectra.com/v1/hyperevm_mainnet | ส่วนหัว x-api-key: {api_key} |
| ที่อยู่หลัก Data API | GET https://api.blockvectra.com/v1/data/hyperevm_mainnet/… | ส่วนหัว x-api-key: {api_key} |
| สถานะสาธารณะ | GET https://api.blockvectra.com/v1/status | ไม่ต้องยืนยันตัวตน (สาธารณะ) |
นักพัฒนาและ AI Agent สามารถใช้การตั้งค่าฝั่งเซิร์ฟเวอร์เดียวกันได้ ใช้ Node.js 24 ขึ้นไป, viem 2 หรือ ethers 6 และเริ่มต้นด้วยการอ่านแบบสาธารณะ ตั้งค่า BLOCKVECTRA_API_KEY อย่างปลอดภัยในสภาพแวดล้อมสำหรับเมธอดที่ใช้คีย์ เก็บรักษาคีย์และ RPC URL ที่มีคีย์ให้พ้นจากโค้ดของเบราว์เซอร์, ล็อก และการควบคุมเวอร์ชัน
บันทึกไฟล์นี้เป็น network.mjs ซึ่งจะอ่าน chain_id และนโยบายเมธอดจาก GET /v1/chains สำหรับการอ่านแบบไม่ใช้คีย์ ให้ใช้ public.url ของสารบบและเฉพาะเมธอดที่ระบุไว้ใน public.methods; ความพร้อมใช้งานของ HTTP สาธารณะไม่ได้หมายความว่าสามารถเข้าถึง WebSocket ได้
const chainSlug = process.env.BLOCKVECTRA_CHAIN ?? 'hyperevm_mainnet';
const key = process.env.BLOCKVECTRA_API_KEY;
const catalogUrl = 'https://api.blockvectra.com/v1/chains';
const response = await fetch(catalogUrl, { signal: AbortSignal.timeout(15_000) });
if (!response.ok) throw new Error(`Chains HTTP ${response.status}`);
const catalog = await response.json();
export const chainInfo = catalog.chains.find(item => item.chain === chainSlug);
if (!chainInfo || !Number.isSafeInteger(chainInfo.chain_id) || chainInfo.chain_id <= 0) {
throw new Error('Missing chain or chain_id');
}
export function allows(method) {
const matches = pattern => pattern.endsWith('*')
? method.startsWith(pattern.slice(0, -1)) : pattern === method;
if (!key) return (chainInfo.public?.methods ?? []).some(matches);
return (chainInfo.methods?.allow ?? []).some(matches)
&& !(chainInfo.methods?.deny ?? []).some(matches);
}
if (!allows('eth_chainId')) throw new Error('eth_chainId is unavailable');
export const rpcUrl = key
? new URL(`./${chainSlug}/${encodeURIComponent(key)}`, catalogUrl).href
: chainInfo.public?.url;
if (!rpcUrl) throw new Error('Public RPC is unavailable; set BLOCKVECTRA_API_KEY');บันทึกเป็น viem-client.mjs, ติดตั้งด้วย npm install viem@2 แล้วรัน node viem-client.mjs
import { createPublicClient, defineChain, http } from 'viem';
import { chainInfo, rpcUrl } from './network.mjs';
export const chain = defineChain({
id: chainInfo.chain_id,
name: chainInfo.name,
nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 },
rpcUrls: { default: { http: [rpcUrl] } },
});
export const client = createPublicClient({ chain, transport: http(rpcUrl) });
if (await client.getChainId() !== chain.id) throw new Error('RPC chain ID mismatch');
console.error(await client.getBlockNumber());สำหรับ ethers ให้บันทึกเป็น ethers-client.mjs, ติดตั้งด้วย npm install ethers@6 แล้วรัน node ethers-client.mjs
import { JsonRpcProvider } from 'ethers';
import { chainInfo, rpcUrl } from './network.mjs';
const provider = new JsonRpcProvider(rpcUrl, chainInfo.chain_id, { batchMaxCount: 1 });
const network = await provider.getNetwork();
if (network.chainId !== BigInt(chainInfo.chain_id)) throw new Error('RPC chain ID mismatch');
console.log(await provider.getBlockNumber());
provider.destroy();ดีพลอยด้วย Foundry หรือ Hardhat
สารบบ hyperevm_mainnet ปัจจุบันมี ws=false และไม่มี eth_sendRawTransaction ใน methods.allow ใช้ BlockVectra สำหรับการอ่าน; การดีพลอยจำเป็นต้องใช้ RPC ที่รองรับการบรอดแคสต์ ตั้งค่า DEPLOY_RPC_URL เป็น URL HTTP ที่ผ่านการยืนยันตัวตนของผู้ให้บริการรายนั้น อย่าสันนิษฐานว่าผู้ให้บริการรายอื่นจะมีขีดจำกัดเมธอดหรือช่วงของ log เหมือนกับ BlockVectra โปรดตรวจสอบ chain ID ที่เลือกก่อนลงนาม
: "${DEPLOY_RPC_URL:?Set a broadcasting RPC URL}"
export RPC_URL="$DEPLOY_RPC_URL"
export CHAIN_ID="$(node --input-type=module -e "import { chainInfo } from './network.mjs'; console.log(chainInfo.chain_id)")"ดำเนินการต่อด้วย บทเรียนการดีพลอยด้วย Foundry หรือ Hardhat ที่ใช้ร่วมกัน เติม EVM HYPE ให้กับผู้ดีพลอยและตรวจสอบข้อกำหนด dual-block ด้านล่างก่อนทำการดีพลอยขนาดใหญ่
HYPE, บล็อกขนาดเล็ก และการดีพลอยขนาดใหญ่
คู่มือเครือข่ายอย่างเป็นทางการของ HyperEVM ระบุว่า HYPE เป็น gas โดยมีทศนิยม 18 ตำแหน่ง (เข้าถึงเมื่อ: 2026-10-07) ตรวจสอบให้แน่ใจว่าผู้ดีพลอยถือครอง HYPE บน HyperEVM; ยอดคงเหลือบน HyperCore เพียงอย่างเดียวไม่ใช่ยอด gas ของ EVM โปรดทำตามคำแนะนำการโอนแบบ native ตามลิงก์เมื่อย้ายเงินทุน
คู่มือ dual-block อธิบายถึงบล็อกขนาดเล็กที่รวดเร็วและบล็อกขนาดใหญ่ที่ช้ากว่าสำหรับธุรกรรมขนาดใหญ่ (เข้าถึงเมื่อ: 2026-10-07) ให้ประเมิน gas สำหรับการดีพลอยก่อน สำหรับการดีพลอยที่เกินงบประมาณบล็อกขนาดเล็ก ผู้ดีพลอยจะต้องเป็นผู้ใช้ HyperCore อยู่แล้ว และลงนามใน Core action {"type":"evmUserModify","usingBigBlocks":true}; การตั้งค่า gas limit ของธุรกรรมให้ใหญ่ขึ้นเพียงอย่างเดียวไม่ได้เป็นการเลือกบล็อกขนาดใหญ่ ให้กู้คืน usingBigBlocks=false ในภายหลังเพื่อกลับสู่บล็อกขนาดเล็ก
บนผู้ให้บริการที่รองรับ ให้ใช้ eth_usingBigBlocks เพื่อตรวจสอบโหมดแอดเดรส และใช้ eth_bigBlockGasPrice สำหรับ base fee ของบล็อกขนาดใหญ่ เอกสารอ้างอิง JSON-RPC อย่างเป็นทางการ มีเอกสารอธิบายเมธอดเหล่านี้ (เข้าถึงเมื่อ: 2026-10-07) ตรวจสอบเมธอดของผู้ให้บริการที่เลือก; ใช้ /v1/chains สำหรับ BlockVectra การดีพลอยขั้นต่ำด้านบนกำหนดเป้าหมายไปยังสัญญาขนาดเล็กและไม่ได้เปลี่ยนโหมดบัญชี Core
ข้อมูล HyperCore และ HyperEVM
EVM RPC ให้บริการสัญญา, ใบเสร็จ (receipt) และ log ส่วนข้อมูลการเทรดและการดำเนินการของ HyperCore จะใช้ Core API สัญญาอัจฉริยะสามารถอ่านสถานะ Core ผ่าน precompile และส่งการดำเนินการผ่าน CoreWriter; ใช้ คู่มือการโต้ตอบอย่างเป็นทางการ เมื่อผสานรวมเส้นทางเหล่านี้ (เข้าถึงเมื่อ: 2026-10-07) ทั้งนี้ EVM log ไม่สามารถแทนที่การคิวรี order book หรือโพซิชันของ Core ได้
ธุรกรรมระบบ (system transaction) ของ HyperEVM (เช่น การโอนจาก HyperCore ไปยัง HyperEVM) จะไม่รวมอยู่ในการตอบกลับ eth_getBlockByNumber มาตรฐาน และให้บริการแยกต่างหากโดย RPC อย่างเป็นทางการผ่าน eth_getSystemTxsByBlockNumber และ eth_getSystemTxsByBlockHash (ดู เอกสาร JSON-RPC อย่างเป็นทางการ, เข้าถึงเมื่อ: 2026-10-07) ในปัจจุบัน ข้อมูลบล็อก, ธุรกรรม และ Data API ของ HyperEVM บน BlockVectra ยังไม่รวมธุรกรรมระบบ; ให้ใช้สองเมธอด RPC ทางการนี้โดยตรงเมื่อต้องการข้อมูลธุรกรรมระบบ
การจัดการข้อผิดพลาดทางการ 10055
คู่มือ HyperEVM อย่างเป็นทางการ กำหนดว่า 10055 เป็นข้อผิดพลาดบริเวณรอยต่อ Core/EVM รวมถึงความล้มเหลวเกี่ยวกับ nonce, เงินทุนไม่เพียงพอ, แฮชซ้ำ และค่าธรรมเนียมการแทนที่ต่ำเกินไป (underpriced-replacement) (เข้าถึงเมื่อ: 2026-10-07) ตรวจสอบข้อความจาก RPC ที่บรอดแคสต์ก่อนตัดสินใจว่าจะกู้คืนอย่างไร:
- Nonce: เปรียบเทียบ
eth_getTransactionCountกับธุรกรรมที่รอดำเนินการของคุณ; จัดลำดับการส่งจากผู้ดีพลอยรายเดียวและกระทบยอด nonce ถัดไป - Funds: ตรวจสอบยอดคงเหลือ EVM HYPE ของผู้ดีพลอยเทียบกับมูลค่ารวมกับค่า gas
- Duplicate hash: ค้นหาธุรกรรมและใบเสร็จที่มีอยู่ก่อนส่งธุรกรรมอื่น
- Replacement fee: ตรวจสอบ nonce และค่าธรรมเนียมที่มีอยู่ จากนั้นใช้นโยบายการแทนที่ของผู้บรอดแคสต์; การส่งไบต์เดิมซ้ำไม่ได้เป็นการเพิ่มค่าธรรมเนียม
10055 เพียงอย่างเดียวไม่เพียงพอที่จะสุ่มลองใหม่โดยไม่ตรวจสอบ โปรดอ่านข้อผิดพลาดและคำแนะนำในการกู้คืนแยกต่างหากใน ข้อมูลอ้างอิงข้อผิดพลาด BlockVectra
ขีดจำกัดอัตราของ public RPC อย่างเป็นทางการและ 429
เอกสารการจำกัดอัตราอย่างเป็นทางการ ของ Hyperliquid ระบุไว้สูงสุด 100 คำขอ EVM JSON-RPC ต่อนาทีต่อ IP สำหรับ rpc.hyperliquid.xyz/evm ส่วน เอกสาร JSON-RPC ยังจำกัด eth_getLogs ไว้ที่ 50 บล็อกต่อหนึ่งคิวรีและไม่เกิน 4 topics เข้าถึงเมื่อ: 2026-10-07
เมื่อพบ HTTP 429 ให้หยุดส่งคำขอชั่วคราวและปฏิบัติตาม Retry-After ก่อนเป็นอันดับแรก (หน่วยเป็นวินาทีหรือวันที่ HTTP) หากไม่มี ให้ใช้ exponential backoff ร่วมกับ jitter และจำกัดจำนวนครั้งในการลองใหม่ โดยลองใหม่กับ chunk เดิมที่ยังไม่เสร็จสมบูรณ์ ลดการทำงานพร้อมกันและความถี่ในการโพลล์ และแบ่งการคิวรี log ออกเป็น chunk ให้อยู่ภายในขีดจำกัดของ endpoint การแบ่ง chunk เพียงอย่างเดียวไม่ได้ขจัดขีดจำกัดอัตราออกไป; ไคลเอนต์ที่ใช้ IP ร่วมกันจำเป็นต้องประสานอัตราคำขอของตน
สำหรับ endpoint ที่ใช้คีย์ของ BlockVectra ให้อ่าน max_logs_block_range, methods.allow และ methods.deny ของ hyperevm_mainnet จาก GET /v1/chains แทนที่จะนำช่วงบล็อกหรือขีดจำกัดคำขอต่อนาทีของ public RPC ทางการมาใช้ อัตราคำขอจะขึ้นอยู่กับ cu_per_sec, burst_cu ของคีย์ และขีดจำกัดการเรียกของแผนบริการฟรีแยกต่างหาก (ดูหัวข้อถัดไป) เมื่อพบ 429 ให้ตรวจสอบ error.data.reason และ retryable; request_exceeds_burst จำเป็นต้องส่งคำขอที่มีขนาดเล็กลงแทนที่จะลองใหม่แบบไม่เปลี่ยนแปลงค่าพร้อม backoff
พารามิเตอร์และกฎการให้บริการของ BlockVectra
BlockVectra ให้บริการ HyperEVM mainnet ผ่าน endpoints แบบ JSON-RPC และ REST Data API:
- พารามิเตอร์ของเชนและขีดจำกัดของ log:
จาก
GET /v1/chainsสำหรับhyperevm_mainnet:- ตัวระบุเชน (Slug):
hyperevm_mainnet, Chain ID999 max_logs_block_range: กำกับดูแลโดยฟิลด์max_logs_block_rangeจากGET /v1/chainsคำขอeth_getLogsรายการเดียวสามารถครอบคลุมบล็อกได้สูงสุดไม่เกินจำนวนนี้ (toBlock − fromBlock + 1) การส่งคำขอเกินกว่าช่วงนี้จะส่งกลับ HTTP 200 พร้อมรหัสข้อผิดพลาด JSON-RPC-32602(eth_getLogs block range too large: max <N> blocks) ซึ่งไม่คิดค่าบริการstate_window_blocks: กำกับดูแลโดยฟิลด์state_window_blocksจากGET /v1/chainsการเรียกที่อ่านสถานะ (เช่นeth_callและeth_getBalance) จะอยู่ภายใต้กรอบเวลาการเก็บรักษาที่ระบุไว้ในฟิลด์นี้ (เมื่อเป็นnullสถานะเต็มจะถูกเก็บรักษาไว้โดยไม่มีขีดจำกัดแบบ rolling window)- นโยบายเมธอด: กำกับดูแลโดย
methods.allowและmethods.denyเมธอด EVM มาตรฐาน (eth_blockNumber,eth_getLogs,eth_call,eth_getBalance,eth_getBlockByNumber,eth_getTransactionReceiptฯลฯ) ได้รับอนุญาต; ส่วนเมธอดตัวกรองและการสมัครสมาชิก (eth_subscribe,eth_unsubscribe,eth_newFilter,eth_newBlockFilter) จะถูกปฏิเสธ โดยส่งกลับ-32601(ไม่คิดค่าบริการ)
- ตัวระบุเชน (Slug):
- ขีดจำกัดอัตราของระดับฟรีและการอัปเกรด:
จาก
GET /v1/plans:free.max_calls_per_sec: สูงสุด 25 คำขอต่อวินาที แชร์ร่วมกันระหว่างทุกคีย์ในบัญชี ทุกเชน และ Data API- ขีดจำกัดเริ่มต้นของคีย์: แต่ละ API key มี bucket ของ CU (อัตราเติม
cu_per_sec, ความจุburst_cu— ค่าเริ่มต้นคือ 400 CU/s และ burst 1,600 CU) เมธอดต่างๆ จะถูกวัดปริมาณตามค่าน้ำหนัก Compute Unit (CU) - การอัปเกรดขีดจำกัด: หลังจากการเติมเงิน ขีดจำกัดคำขอต่อวินาทีของทั้งบัญชีจะถูกยกเลิก; แต่ละคีย์ยังคงอยู่ภายใต้อัตราและขีดจำกัด burst ของ Compute Unit (CU) สำหรับอัตราและหน่วยการเรียกเก็บเงินปัจจุบัน โปรดดู หน้าราคา
การดึงข้อมูล log ย้อนหลัง: eth_getLogs แบบแบ่งส่วนและตรรกะการลองใหม่
เมื่อทำการคิวรี log ย้อนหลัง ช่วงเวลาที่กว้างจะต้องถูกแบ่งออกเป็น chunk ต่อเนื่องกันซึ่งถูกจำกัดโดย max_logs_block_range ของเชนเป้าหมาย กลยุทธ์การลองใหม่ของไคลเอนต์ควรตรวจสอบฟิลด์ retryable ภายในการตอบกลับข้อผิดพลาด
การประเมิน retryable ในการตอบกลับข้อผิดพลาด
บน BlockVectra อ็อบเจกต์ข้อผิดพลาด JSON-RPC จะมีเพย์โหลด error.data ซึ่งประกอบด้วย reason, docs_url และ retryable (บูลีน):
retryable: true: สภาวะชั่วคราว รวมถึงบริการโอเวอร์โหลด (overloaded), ขีดจำกัดคำขอต่อวินาทีของแผนบริการฟรี (free_plan_call_limit), การซิงก์โหนด (node_syncing) หรืออัปสตรีมไม่พร้อมใช้งาน (upstream_unavailable) ไคลเอนต์ควรปฏิบัติตามส่วนหัวRetry-Afterเมื่อปรากฏ หรือใช้ exponential backoff ร่วมกับ jitterretryable: false: ข้อผิดพลาดที่ไม่ใช่สภาวะชั่วคราว เช่น ช่วงบล็อกเกินขีดจำกัด (-32602/logs_range_too_large), พารามิเตอร์ไม่ถูกต้อง (invalid_params), API key ขาดหายไป (missing_api_key) หรือคำขอเกินความจุ burst (-32022/request_exceeds_burst) การลองใหม่โดยไม่ปรับพารามิเตอร์จะไม่ประสบความสำเร็จ
ด้านล่างนี้คือการตอบกลับที่ได้รับเมื่อไม่ได้ระบุ API key:
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32024,
"message": "missing API key: send it in the request path (/v1/{chain}/<api_key>) or in the x-api-key header",
"data": {
"reason": "missing_api_key",
"docs_url": "https://docs.blockvectra.com/en/errors/#missing_api_key",
"retryable": false
}
}
}การใช้ Data API endpoints แทนการสแกน getLogs ปริมาณมาก
เมื่อแอปพลิเคชันติดตามประวัติธุรกรรมหรือการเคลื่อนไหวของโทเค็นสำหรับแอดเดรสที่ระบุ การสแกนผ่าน eth_getLogs จะต้องส่งคำขอแบบแบ่งส่วนตามลำดับซึ่งถูกจำกัดโดย max_logs_block_range และต้องแยกวิเคราะห์ raw Transfer event logs
BlockVectra Data API มี REST endpoints ที่ทำดัชนีไว้ล่วงหน้าสำหรับ hyperevm_mainnet ซึ่งรองรับช่วงสูงสุดถึง 100,000 บล็อกพร้อมการแบ่งหน้าด้วยเคอร์เซอร์:
- ธุรกรรมของแอดเดรส:
GET /v1/data/hyperevm_mainnet/addresses/{address}/transactions- พารามิเตอร์:
from_block(จำเป็น),to_block(จำเป็น),direction(ไม่บังคับ:from,to,any, ค่าเริ่มต้นany),clamp(สตริงบูลีนไม่บังคับ, ค่าเริ่มต้นfalse; เมื่อตั้งค่าเป็นtrueช่วงที่เกิน 100,000 บล็อกหรือสูงกว่าas_of_blockจะถูกตัดทอนแทนที่จะส่งกลับ 409),limit(ไม่บังคับ, สูงสุด 500),cursor(โทเค็นการแบ่งหน้า)
- พารามิเตอร์:
- การโอนโทเค็นของแอดเดรส:
GET /v1/data/hyperevm_mainnet/addresses/{address}/transfers- พารามิเตอร์:
standard(จำเป็น:erc20หรือerc721;erc1155ไม่สามารถคิวรีตามแอดเดรสได้และจะส่งกลับ422 no_coverage),token(ตัวกรองสัญญาโทเค็นไม่บังคับ),from_block(จำเป็น),to_block(จำเป็น),direction(ไม่บังคับ:in,out,any),clamp(ไม่บังคับ),limit,cursor
- พารามิเตอร์:
โครงสร้างการตอบกลับ
การตอบกลับใช้ schema มาตรฐาน:
data: อาร์เรย์ของระเบียน ธุรกรรมประกอบด้วยhash,block_number,block_timestamp,from,to,value,tx_index,gas_limit,gas_usedและstatusการโอนประกอบด้วยtoken,standard,from,to,block_number,block_timestamp,tx_hash,tx_indexและlog_index(amountสำหรับ ERC-20,token_idสำหรับ ERC-721)next_cursor: โทเค็นการแบ่งหน้าแบบทึบแสง (opaque) ที่ส่งกลับมาเมื่อมีระเบียนถัดไป (ไม่มีในหน้าสุดท้าย ไม่ใช่null)meta: ข้อมูลเมทาดาตาประกอบด้วยchain,chain_slug,chain_external_id,as_of_block,safe_block,finalized_block,coverage(fullหรือpartial) และrefreshed_at
ตัวอย่างโค้ด: การคิวรี Data API
export BLOCKVECTRA_API_KEY="rgw_your_api_key"
# 1. Query address transaction history (clamp=true prevents 409 errors)
curl -s "https://api.blockvectra.com/v1/data/hyperevm_mainnet/addresses/0x2222222222222222222222222222222222222222/transactions?from_block=0&to_block=50000&clamp=true" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"
# 2. Query address ERC-20 token transfers
curl -s "https://api.blockvectra.com/v1/data/hyperevm_mainnet/addresses/0x2222222222222222222222222222222222222222/transfers?standard=erc20&from_block=0&to_block=50000&clamp=true" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"การติดตามแบบเรียลไทม์: การโพลล์บล็อกใหม่
สำหรับการรับส่งข้อมูลแบบ HTTP ให้ติดตามบล็อกด้วยการโพลล์และดึง event log ใน chunk ที่ต่อเนื่องกันภายใน max_logs_block_range เลือก WebSocket เฉพาะเมื่อ /v1/chains รายงาน ws=true และมีรายการ subscriptions ที่ต้องการ สำหรับการส่งข้อมูลไปยังตัวรับ HTTPS ให้ใช้ webhook push
หากต้องการทดสอบสัญญา Hello ที่ดีพลอยแล้ว ให้ตั้งค่า LOG_ADDRESS เป็นแอดเดรสของสัญญา ส่ง ping() ผ่าน RPC ที่บรอดแคสต์ จากนั้นดึงข้อมูลบล็อกของใบเสร็จย้อนหลังด้วยสคริปต์การดึงข้อมูลย้อนหลังในหน้านี้ ดำเนินการต่อจาก chunk ล่าสุดที่เสร็จสมบูรณ์สำหรับเหตุการณ์ใหม่
cast send "$CONTRACT_ADDRESS" "ping()" --rpc-url "$DEPLOY_RPC_URL" \
--private-key "$DEPLOYER_PRIVATE_KEY"โฟลว์การโพลล์
- ส่งคำขอแบบ lightweight ไปยัง
eth_blockNumberเป็นระยะเพื่อตรวจสอบ block head ล่าสุดของเชน - เปรียบเทียบหมายเลขบล็อกที่ส่งกลับมากับ
lastSeenBlockที่ประมวลผลก่อนหน้านี้ - หาก
currentBlock > lastSeenBlockให้แบ่ง[lastSeenBlock + 1, currentBlock]ออกเป็น chunk ที่มีขนาดไม่เกินmax_logs_block_rangeบันทึกค่าlastSeenBlockแบบถาวรหลังจากประมวลผลแต่ละ chunk สำเร็จแล้วเท่านั้น; หากล้มเหลว ให้ลองใหม่กับ chunk ที่ยังไม่เสร็จสมบูรณ์ กำจัดข้อมูลซ้ำซ้อนด้วย(blockHash, transactionHash, logIndex)และเล่นซ้ำช่วงที่ทับซ้อนกันหลังจากเชื่อมต่อใหม่เพื่อจัดการกับการจัดระเบียบเชนใหม่ (reorg) - ฟังก์ชัน
watchBlockNumberหรือwatchBlocksของ viem ใช้วิธีการโพลล์ HTTP ภายใต้ transport แบบ HTTP โดยตรง ซึ่งช่วยให้สามารถปรับแต่งผ่านพารามิเตอร์pollingIntervalได้ (เช่น 1,000 ms)
โพลล์ event logs ใน chunk ที่จำกัดขอบเขต
บันทึกเป็น poll-logs.mjs ไว้ข้าง network.mjs และ viem-client.mjs ตั้งค่า BLOCKVECTRA_API_KEY, LOG_ADDRESS และ FROM_BLOCK จากนั้นรัน node poll-logs.mjs ตัวอย่างจำกัดนี้จะสุ่มตรวจตัวอย่าง head 12 ครั้ง ห่างกันครั้งละห้าวินาที และคิวรีทุกช่วงใหม่ใน chunk ตามลำดับ หากเกิดข้อผิดพลาดจะหยุดการทำงานของสคริปต์ก่อนที่จะขยับผ่าน chunk ที่ล้มเหลว
import { isAddress } from 'viem';
import { client } from './viem-client.mjs';
import { chainInfo, allows } from './network.mjs';
const address = process.env.LOG_ADDRESS;
const start = process.env.FROM_BLOCK;
if (!address || !isAddress(address)) throw new Error('Set LOG_ADDRESS');
if (!/^(0x[0-9a-f]+|[0-9]+)$/i.test(start ?? '')) throw new Error('Set FROM_BLOCK');
if (!allows('eth_getLogs')) throw new Error('eth_getLogs requires an available keyed endpoint');
if (!Number.isSafeInteger(chainInfo.max_logs_block_range) || chainInfo.max_logs_block_range <= 0) {
throw new Error('Invalid max_logs_block_range');
}
const max = BigInt(chainInfo.max_logs_block_range);
let from = BigInt(start);
for (let poll = 0; poll < 12; poll++) {
const head = await client.getBlockNumber();
while (from <= head) {
const to = from + max - 1n < head ? from + max - 1n : head;
const logs = await client.getLogs({ address, fromBlock: from, toBlock: to });
console.log(JSON.stringify({ from: from.toString(), to: to.toString(), logs },
(_, value) => typeof value === 'bigint' ? value.toString() : value));
from = to + 1n;
}
if (poll < 11) await new Promise(resolve => setTimeout(resolve, 5_000));
}ผลลัพธ์แต่ละรายการจะบันทึก chunk ที่เสร็จสมบูรณ์ หากต้องการดำเนินการต่อ ให้ตั้งค่า FROM_BLOCK เป็น to + 1 ของ chunk นั้น; consumer ที่ทนทานจะต้องบันทึกเหตุการณ์และเคอร์เซอร์ไว้ด้วยกัน, กำจัดข้อมูลซ้ำ และกระทบยอดการจัดระเบียบเชนใหม่ตามที่อธิบายไว้ข้างต้น สำหรับ 429 หรือความล้มเหลวอื่นๆ ที่สามารถลองใหม่ได้ ให้ใช้คำแนะนำ bounded-backoff กับ chunk เดิมที่ยังไม่เสร็จสมบูรณ์
คู่มือที่เกี่ยวข้อง
- ค้นหา public RPC URL, เมธอดที่รองรับ และขีดจำกัดปัจจุบันได้ใน หน้าเชน HyperEVM
- สำหรับกฎทั้งหมดเกี่ยวกับช่วงของ
eth_getLogsและอัลกอริทึมการแบ่ง chunk โปรดดู ขีดจำกัดช่วงบล็อกของ eth_getLogs และการคิวรีแบบแบ่งส่วน - สำหรับการเปรียบเทียบ
eth_getLogsกับการโอนของ Data API, การทำความเข้าใจขอบเขตas_of_blockและมาร์กเกอร์safe_block/finalized_blockโปรดดู eth_getLogs และการโอนที่ทำดัชนี: ความครอบคลุมและความเป็นที่สิ้นสุด - สำหรับรายละเอียดเกี่ยวกับการวัดปริมาณ CU, ข้อผิดพลาดที่ไม่คิดค่าบริการ และการลองใหม่ โปรดดู สิ่งที่ไม่คิดค่าบริการ: รหัสข้อผิดพลาดและกฎการเรียกเก็บเงิน
ขั้นตอนถัดไป
- เลือกดูสารบบชุดข้อมูล เพื่อดูทุกชุดข้อมูลที่ BlockVectra ทำดัชนี
- ดูแผนบริการฟรีและราคา เพื่อตรวจสอบสิ่งที่บัญชีของคุณได้รับ
- เข้าสู่ระบบคอนโซล เพื่อสร้าง API key
อัปเดตล่าสุด: