# คิวรีสถานะ EVM ย้อนหลังภายในหน้าต่างที่รองรับ

> Source: https://docs.blockvectra.com/th/guides/evm-historical-state/

`eth_call` ย้อนหลังขึ้นอยู่กับหน้าต่างสถานะของเชน ไม่ใช่ขีดจำกัดช่วงบล็อกของ `eth_getLogs` ตรวจสอบหน้าต่างสถานะ, โหมดการยืนยันตัวตนของ endpoint และบล็อกเป้าหมายก่อนอ่านค่าสัญญาย้อนหลัง

## ขีดจำกัดย้อนหลัง 3 ประการที่แตกต่างกัน

| ฟิลด์ใน [GET /v1/chains](https://api.blockvectra.com/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` ช่วงที่ได้รับอนุญาตไม่ได้เป็นเครื่องยืนยันว่าสถานะสัญญาเก่าหรือ log จะพร้อมใช้งาน                                          |

ขีดจำกัดเหล่านี้มีหน่วยเป็นบล็อก ไม่ใช่จำนวนวัน หน้าต่างสถานะที่เป็นค่า `null` หรือไม่ได้ประกาศไว้ไม่ได้เป็นเครื่องยืนยันความครอบคลุมระดับ archive ความพร้อมใช้งานของเมธอดแบบไม่ต้องใช้คีย์จะแยกต่างหากจากความพร้อมใช้งานของเมธอดที่มีการยืนยันตัวตน: ช่วงของ log เพียงอย่างเดียวไม่ได้ทำให้สามารถใช้งาน `eth_getLogs` แบบสาธารณะได้

## เปรียบเทียบหน้าต่างสถานะของแต่ละเชน

ตารางแสดงหน้าต่างสถานะที่เผยแพร่, ประวัติแบบไม่ต้องใช้คีย์, ช่วงของ log และชุดข้อมูล Data API ที่ประกาศไว้จากสแนปช็อตสาธารณะ สำหรับการส่งคำขอในขณะนี้ โปรดอ่าน [GET /v1/chains](https://api.blockvectra.com/v1/chains) และ [GET /v1/status](https://api.blockvectra.com/v1/status) ใหม่อีกครั้ง

นักพัฒนาและ AI Agent ควรตรวจสอบช่วงสถานะและช่วงการสืบค้น log แยกกัน ค่าช่วงสถานะที่เป็น null ไม่ได้หมายความว่าครอบคลุมข้อมูลประวัติทั้งหมด (archive) ประวัติสาธารณะจะใช้ได้เฉพาะกับเมธอดสาธารณะที่ประกาศไว้เท่านั้น

| เชน | Slug ของเชน | ช่วงสถานะที่ต้องยืนยันตัวตน: state_window_blocks (บล็อก) | ประวัติแบบไม่ต้องใช้คีย์: public.history_blocks (บล็อก) | ช่วงการสืบค้น log ที่ต้องยืนยันตัวตน: max_logs_block_range (บล็อก) | ชุดข้อมูล Data API ที่ประกาศไว้ |
| --- | --- | --- | --- | --- | --- |
| Arbitrum One | `arb_mainnet` | 5,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](https://api.blockvectra.com/v1/chains) · เวลาที่สุ่มเก็บข้อมูล (UTC): 2026-10-10

[GET /v1/status](https://api.blockvectra.com/v1/status) · เวลาที่สุ่มเก็บข้อมูล (UTC): 2026-10-10

## เลือกแท็กบล็อก

ใช้ `latest` สำหรับค่าปัจจุบัน สำหรับการเปรียบเทียบย้อนหลัง ให้อ่าน `eth_blockNumber` หนึ่งครั้งและแปลงหมายเลขบล็อกที่เลือกเป็นจำนวนเลขฐานสิบหก เช่น `0x18efa2f` กำหนดตัวเลขนั้นให้คงที่สำหรับทุกการเรียกในการเปรียบเทียบ; การเรียก `latest` ซ้ำๆ อาจอ้างอิงถึงบล็อกที่แตกต่างกัน

สำหรับการอ่านสถานะ แท็ก `earliest`, `safe` และ `finalized` จะส่งกลับ `-32011` ภายใต้นโยบายหน้าต่างสถานะ ให้เลือกหมายเลขบล็อกที่ชัดเจนภายในหน้าต่างที่ประกาศไว้แทน การใช้รูปแบบแฮชของบล็อกไม่ใช่วิธีการรับประวัติเพิ่มเติม: การอ่านสถานะแบบไม่ต้องใช้คีย์จะปฏิเสธรูปแบบนี้ และคำขอที่มีการยืนยันตัวตนยังคงขึ้นอยู่กับสถานะที่พร้อมใช้งาน

หมายเลขบล็อกอาจอ้างอิงถึงบล็อกที่แตกต่างกันได้หากเกิดการจัดระเบียบสายโซ่ใหม่ (reorganization) บันทึกแฮชของบล็อกด้วย `eth_getBlockByNumber` หากคุณต้องการระบุบล็อกของผลลัพธ์ หมายเลขที่อยู่ภายในหน้าต่างยังต้องการเชนที่ซิงค์สมบูรณ์และสัญญาที่มีอยู่จริง ณ ความสูงของบล็อกนั้นด้วย

## การอ่านสัญญาด้วยบล็อกคงที่

บน Ethereum นั้น WETH ที่ `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` เปิดเผยฟังก์ชัน `decimals()` ด้วย selector `0x313ce567` การเรียกแบบไม่ต้องใช้คีย์ที่สุ่มเก็บตัวอย่างเมื่อ 2026-10-08 (UTC) ที่บล็อก `0x18efa2f` ส่งคืน HTTP 200 พร้อมผลลัพธ์นี้:

คำขอไปยัง `public.url` ของเชน:

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "eth_call",
  "params": [
    { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x313ce567" },
    "0x18efa2f"
  ]
}
```

การตอบกลับ:

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "0x0000000000000000000000000000000000000000000000000000000000000012"
}
```

จำนวนเต็มที่เข้ารหัส ABI คือ 18 ผลลัพธ์นี้คือค่า decimals ไม่ใช่ยอดคงเหลือ และไม่ได้เป็นเครื่องยืนยันความพร้อมใช้งานที่ระดับความสูงบล็อกอื่นๆ บล็อกคงที่นั้นจะหลุดออกจากหน้าต่างที่จำกัดขอบเขตตามกาลเวลา; โปรดใช้บล็อกล่าสุดเมื่อรันตัวอย่างต่อไปนี้ในภายหลัง

บันทึกตัวอย่างนี้เป็น `historical-state.mjs` และรันด้วยคำสั่ง `node historical-state.mjs` โดยใช้ Node.js 24 หรือใหม่กว่า พร้อมทั้งตั้งค่าตัวแปรสภาพแวดล้อม `BLOCKVECTRA_API_KEY` สคริปต์นี้จะใช้ endpoint ที่มีการยืนยันตัวตน, ใช้สัญญาและ calldata เดียวกัน และเปรียบเทียบ `latest`, บล็อกล่าสุดคงที่หนึ่งบล็อก และบล็อกที่อยู่นอกหน้าต่างที่มีการยืนยันตัวตนที่เผยแพร่ไว้ แต่ละผลลัพธ์จะรวมสถานะ HTTP จริงและเนื้อหา JSON-RPC; การตอบกลับ HTTP 200 ยังคงสามารถมีข้อผิดพลาดอยู่ภายในได้ สคริปต์จะหยุดทำงานเมื่อได้รับการตอบกลับที่ไม่คาดคิดแทนที่จะถือว่าเป็นการอ่านที่สำเร็จ

```js
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 ในการอ่านแบบไม่ต้องใช้คีย์ ให้นำ URL โดยตรงมาจาก `public.url`, ละเว้นคีย์ และเลือกบล็อกที่อยู่ภายใน `public.history_blocks` เช่นเดียวกับหน้าต่างสถานะ การเปลี่ยนโหมดการยืนยันตัวตนอาจเปลี่ยนประวัติที่ได้รับอนุญาตได้ แม้จะเป็นสัญญาและ calldata เดียวกันก็ตาม

## วินิจฉัยข้อผิดพลาดอยู่นอกหน้าต่าง

บน endpoint แบบไม่ต้องใช้คีย์เดียวกัน การเรียกที่สุ่มเก็บตัวอย่างเมื่อ 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` นี่คือความล้มเหลวของประวัติสาธารณะ; โดย endpoint ที่มีการยืนยันตัวตนจะมีหน้าต่างสถานะของตนเอง

ใช้ฟิลด์เหล่านี้จาก [รายการข้อผิดพลาด state\_window](https://docs.blockvectra.com/en/errors/#state_window) เพื่อระบุความล้มเหลวแทนที่จะพึ่งพาตัวเลขหน้าต่างที่เฉพาะเจาะจงในข้อความ:

| ฟิลด์                  | ค่าหรือความหมายตามเอกสาร                                                                                                          |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| สถานะ HTTP             | `200`; ตรวจสอบ JSON-RPC `error` แม้ว่า HTTP จะสำเร็จก็ตาม                                                                         |
| `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](https://docs.blockvectra.com/en/errors/#range_not_indexed) จำเป็นต้องใช้ช่วงที่ครอบคลุม; [history\_not\_ready](https://docs.blockvectra.com/en/errors/#history_not_ready) อนุญาตให้ลองใหม่ได้หลังจากการทำดัชนีตามทัน ตรวจสอบ `error.data.reason` ไม่ใช่ดูเพียงรหัสตัวเลขเท่านั้น

สถานะเบื้องหลังอาจไม่พร้อมใช้งานด้วยรหัส `-32000` หรือประวัติบล็อกถูกตัดทอน (pruned) ด้วยรหัส `4444`; โปรดดู [สารบบข้อผิดพลาด](https://docs.blockvectra.com/en/errors/) อย่าลองส่งคำขอสำหรับบล็อกเก่าซ้ำโดยไม่มีการเปลี่ยนแปลง หรือสันนิษฐานว่าหน้าต่างที่ประกาศไว้กว้างกว่าจะรับประกันทุกการตอบกลับ

## เลือกคิวรีถัดไป

สำหรับรายการตรวจสอบภาระงานและการทดสอบด้วยตนเองฉบับสมบูรณ์ โปรดเริ่มต้นที่ [วิธีเลือกผู้ให้บริการ RPC](https://docs.blockvectra.com/en/guides/choose-rpc-provider/)

เมื่อเลือกผู้ให้บริการสำหรับการอ่านสัญญาซ้ำๆ โปรด [เปรียบเทียบงบประมาณรายวันและตามรอบบิลสำหรับการอ่าน EVM](https://docs.blockvectra.com/en/guides/infura-alternative/) ตรวจสอบบล็อกย้อนหลังที่ต้องการก่อน จากนั้นจึงวางแผนการกระจายตัวของทราฟฟิกรายวันและทรูพุตของงาน; การที่พอดีกับงบประมาณเครดิตไม่ได้เป็นเครื่องยืนยันความครอบคลุมของสถานะ

เมื่อเปรียบเทียบผู้ให้บริการสำหรับการอ่านข้อมูลย้อนหลัง อันดับแรกให้ยืนยันว่าทั้งสองรายสามารถให้บริการบล็อกเป้าหมายได้ การ [เปรียบเทียบค่าบริการส่วนเกินของคำขอแบบ full](https://docs.blockvectra.com/en/guides/chainstack-alternative/) จะเปรียบเทียบราคา RU ส่วนเกินกับต้นทุนตามเมธอด, แยกโควตาที่รวมมาให้ออกจากปริมาณการใช้งานส่วนเกิน ตลอดจนอธิบายระดับการเรียกเก็บเงินแบบ full เทียบกับ archive

สำหรับบล็อก, ธุรกรรม, การโอน หรือชุดข้อมูลอื่นๆ ที่ทำดัชนีก่อนหน้านี้ โปรดตรวจสอบชุดข้อมูล Data API ที่ประกาศในตารางและ [ข้อมูลอ้างอิง Data API](https://docs.blockvectra.com/en/api/data/) บันทึกข้อมูลที่ทำดัชนีไม่ได้ให้บริการการประมวลผลสัญญาย้อนหลังตามใจชอบ หรือหมายความว่าทุกเชนจะมียอดคงเหลือย้อนหลัง

* [ข้อมูลอ้างอิงเมธอด eth\_call](https://docs.blockvectra.com/en/api/json-rpc/methods/eth_call/) สำหรับพารามิเตอร์การเรียกและการถอดรหัสค่าส่งกลับ
* [ช่วงบล็อก eth\_getLogs และคิวรีแบบแบ่งส่วน](https://docs.blockvectra.com/en/guides/getlogs-block-range/) สำหรับประวัติ log เหตุการณ์
* [การตั้งค่า RPC แบบกำหนดเองในกระเป๋าเงิน](https://docs.blockvectra.com/en/guides/wallet-custom-rpc/) สำหรับการเชื่อมต่อกระเป๋าเงินและคีย์เฉพาะ
* [เชนที่รองรับ](https://docs.blockvectra.com/en/chains/) สำหรับความพร้อมใช้งานของเครือข่าย และ [ราคา CU](https://docs.blockvectra.com/en/guides/reading-cu-pricing/) สำหรับต้นทุนของแต่ละเมธอด
