# จำลองธุรกรรมก่อนส่ง: การทดสอบรันธุรกรรมแบบ Dry-run ด้วย eth_simulateV1

> Source: https://docs.blockvectra.com/th/guides/simulate-transactions/

ก่อนที่จะบรอดแคสต์ธุรกรรมไปยังเครือข่ายบล็อกเชน การทดสอบรันแบบ dry-run ช่วยให้นักพัฒนาสามารถตรวจสอบผลลัพธ์การดำเนินการ ตรวจสอบการเปลี่ยนสถานะของสัญญา และสังเกต event log ได้ล่วงหน้า ซึ่งช่วยหลีกเลี่ยงค่าธรรมเนียม gas ที่ไม่จำเป็นจากการที่สัญญาเกิด revert

Ethereum execution layer มีวิธีหลายวิธีในการประเมินธุรกรรมก่อนส่ง:

* `eth_call`: ดำเนินการเรียกข้อความแบบอ่านอย่างเดียว (read-only) รายการเดียว โดยไม่มีการคงสถานะระหว่างการเรียกที่ต่อเนื่องกัน
* `eth_estimateGas`: คำนวณขีดจำกัด gas (gas limit) ที่จำเป็นสำหรับการดำเนินการ แต่ไม่ได้แสดงการเปลี่ยนสถานะตามลำดับของหลายธุรกรรมหรือ event log แบบเต็ม
* `eth_simulateV1`: กำหนดไว้ในข้อกำหนดมาตรฐานของ Ethereum Execution APIs เมธอดนี้ช่วยให้สามารถจำลองหลายธุรกรรมตามลำดับข้ามบล็อกได้ สะสมการเปลี่ยนแปลงสถานะระหว่างธุรกรรม ตลอดจนรองรับการแทนที่พารามิเตอร์ของบล็อกและสถานะของบัญชี

## เชนที่รองรับและนโยบายเมธอด

ความสามารถของเครือข่ายจะเผยแพร่แบบไดนามิกผ่าน `GET /v1/chains` ให้อ่าน `methods.allow` จากการตอบกลับนั้นเพื่อดูว่าเชนใดอนุญาต `eth_simulateV1`; เชนที่ไม่มีเมธอดนี้ระบุไว้จะปฏิเสธคำขอด้วยข้อผิดพลาด JSON-RPC `-32601` (`method not available`, ไม่คิดค่าบริการ)

### เงื่อนไขสถานะของโหนด

`eth_simulateV1` เป็นเมธอดการสืบค้นสถานะ:

* **Sync gate (`-32010`)**: เมื่อโหนดของเชนเป้าหมายกำลังซิงค์และยังไม่พร้อม การเรียกจะส่งคืน `-32010` (`node is syncing`, ไม่คิดค่าบริการ)
* **หน้าต่างสถานะ (`-32011`)**: บน Robinhood Chain คำขอที่ระบุบล็อกที่เก่ากว่า `state_window_blocks` ของเชน (`GET /v1/chains`) หรือระบุแท็กบล็อก `safe`, `finalized` หรือ `earliest` จะส่งคืน `-32011` (ไม่คิดค่าบริการ) โดยแท็กบล็อกเริ่มต้นคือ `latest`

## โครงสร้างคำขอและตัวอย่างพื้นฐาน

ตามข้อกำหนดของ execution layer ([คำนิยาม eth\_simulateV1 บน Ethereum Execution APIs](https://ethereum.github.io/execution-apis/api/methods/eth_simulateV1)) `eth_simulateV1` รับพารามิเตอร์ตามตำแหน่งสองตัว:

1. **เพย์โหลดออบเจกต์**:
   * `blockStateCalls` (อาร์เรย์ที่ต้องระบุ): อาร์เรย์ของออบเจกต์บล็อกจำลอง แต่ละออบเจกต์ประกอบด้วยอาร์เรย์ของการเรียกธุรกรรม `calls`, การแทนที่ส่วนหัวของบล็อกที่ไม่บังคับ `blockOverrides` และการแทนที่สถานะบัญชีที่ไม่บังคับ `stateOverrides`
   * `validation` (บูลีนที่ไม่บังคับ, ค่าเริ่มต้น `false`): เมื่อเป็น `false` จะทำงานเหมือนกับ `eth_call`; เมื่อเป็น `true` จะรันการตรวจสอบความถูกต้องทั้งหมดของ EVM ยกเว้นการตรวจสอบลายเซ็น
   * `traceTransfers` (บูลีนที่ไม่บังคับ): เมื่อเป็น `true` จะส่งคืน event log สำหรับการโอนโทเค็นพื้นเมือง
2. **แท็กบล็อก** (สตริงที่ไม่บังคับ, ค่าเริ่มต้น `'latest'`): หมายเลขบล็อก, แฮชของบล็อก หรือแท็กบล็อก

### ตัวอย่างพื้นฐาน: การทดสอบรันการโอน ERC-20 แบบ dry-run

ตัวอย่างต่อไปนี้เป็นการทดสอบรันการเรียก `transfer(address,uint256)` ของ ERC-20 บน Robinhood Chain แบบ dry-run โดยแทนที่ `$BLOCKVECTRA_API_KEY` ด้วย API key จริงของคุณ:

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

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_simulateV1",
    "params": [
      {
        "blockStateCalls": [
          {
            "calls": [
              {
                "from": "0x1111111111111111111111111111111111111111",
                "to": "0x2222222222222222222222222222222222222222",
                "data": "0xa9059cbb00000000000000000000000033333333333333333333333333333333333333330000000000000000000000000000000000000000000000000de0b6b3a7640000",
                "value": "0x0"
              }
            ]
          }
        ]
      },
      "latest"
    ]
  }'
```


  **TypeScript (viem)**

```ts
import { createPublicClient, http } from "viem";

const apiKey = process.env.BLOCKVECTRA_API_KEY!;
const client = createPublicClient({
  transport: http(`https://api.blockvectra.com/v1/robinhood_mainnet/${apiKey}`),
});

// Call eth_simulateV1 directly via viem's client.request
const simulationResult = await client.request({
  method: "eth_simulateV1" as any,
  params: [
    {
      blockStateCalls: [
        {
          calls: [
            {
              from: "0x1111111111111111111111111111111111111111",
              to: "0x2222222222222222222222222222222222222222",
              data: "0xa9059cbb00000000000000000000000033333333333333333333333333333333333333330000000000000000000000000000000000000000000000000de0b6b3a7640000",
              value: "0x0",
            },
          ],
        },
      ],
    },
    "latest",
  ],
});

console.log(simulationResult);
```


### การตรวจสอบโครงสร้างการตอบกลับ

ตามข้อกำหนด execution ของ Ethereum ฟิลด์ `result` จะมีอาร์เรย์ของผลลัพธ์บล็อกจำลองตามสคีมาต่อไปนี้:

#### ฟิลด์ระดับบล็อก

* `number`: หมายเลขบล็อกของบล็อกจำลอง (สตริงฐานสิบหก)
* `hash`: แฮชของบล็อกจำลอง (สตริงฐานสิบหก 32 ไบต์)
* `parentHash`: แฮชของบล็อกแม่
* `timestamp`: เวลาประทับของบล็อก (สตริงฐานสิบหก)
* `gasLimit`: ขีดจำกัด gas ของบล็อก
* `gasUsed`: ปริมาณ gas รวมที่ใช้ไปในการเรียกจำลองทั้งหมดในบล็อกนี้
* `baseFeePerGas`: ค่าธรรมเนียมพื้นฐานต่อหน่วย gas สำหรับบล็อกนี้
* `miner`: แอดเดรส Coinbase ที่รับค่าธรรมเนียมบล็อก
* `calls`: อาร์เรย์ของผลลัพธ์การดำเนินการสำหรับการเรียกจำลองแต่ละรายการ

#### ฟิลด์ระดับการเรียก (รายการในอาร์เรย์ `calls`)

* `status`: สถานะการเรียกในรูปแบบสตริงฐานสิบหก โดย `0x1` ระบุว่าสำเร็จ ขณะที่ `0x0` ระบุว่าล้มเหลวหรือเกิด revert
* `gasUsed`: ปริมาณ gas จริงที่ใช้ไปในการเรียกนี้ (สตริงฐานสิบหก)
* `maxUsedGas` (ไม่บังคับ): ปริมาณ gas สูงสุดที่ใช้ระหว่างการดำเนินการก่อนการคืนเงิน gas
* `returnData`: ข้อมูลที่ส่งคืนซึ่งเข้ารหัสฐานสิบหก ในการโอน ERC-20 ที่สำเร็จ ฟิลด์นี้จะมีบูลีน `true`; หากเกิด revert จะมี error selector หรือข้อมูล revert
* `logs`: อาร์เรย์ของ event log ที่ส่งออกมาจากการเรียก เมื่อสำเร็จ จะประกอบด้วย event log เช่น `Transfer`:
  * `address`: แอดเดรสสัญญาที่ส่ง event ออกมา
  * `topics`: อาร์เรย์ของแฮช topic ขนาด 32 ไบต์ (`topics[0]` คือแฮชลายเซ็นของ event เช่น ลายเซ็นของ event `Transfer`)
  * `data`: ข้อมูล event ที่ไม่ได้ทำดัชนีซึ่งเข้ารหัสฐานสิบหก
  * `blockNumber`, `blockHash`, `transactionHash`, `transactionIndex`, `logIndex`, `removed`
* `error` (มีอยู่เมื่อล้มเหลว): ออบเจกต์ที่ประกอบด้วย `code` (`3` สำหรับ revert, `-32015` สำหรับข้อผิดพลาดของ VM) และ `message` (เช่น `execution reverted`)

## การกำหนดราคาและค่าน้ำหนัก CU

BlockVectra วัดปริมาณการใช้งานเป็น Compute Units (CU) ค่าน้ำหนักสำหรับแต่ละเมธอด JSON-RPC จะเผยแพร่แบบไดนามิกผ่าน `GET /v1/plans`:

**น้ำหนัก CU ต่อการเรียก**

| เมธอด | CU ต่อการเรียก |
| --- | --- |
| `eth_simulateV1` | 20 |
| `eth_call` | 15 |
| `eth_estimateGas` | 20 |

สำหรับสูตรการแปลงหน่วยและรายละเอียดการเติมเงิน โปรดไปที่ [หน้าราคา](https://blockvectra.com/en/pricing/)

คำขอที่ถูกปฏิเสธ — รวมถึงโหนดกำลังซิงค์ (`-32010`), อยู่นอกหน้าต่างสถานะ (`-32011`) หรือเมธอดไม่พร้อมใช้งาน (`-32601`) — จะไม่คิดค่าบริการ ดูที่ [คำขอใดบ้างที่ไม่คิดค่าบริการ](https://docs.blockvectra.com/en/guides/billing-rules/) สำหรับกฎการเรียกเก็บเงินฉบับสมบูรณ์

## การใช้งานร่วมกับ AI Agent และ MCP

AI Agent อัตโนมัติสามารถเรียกใช้ `eth_simulateV1` ได้โดยตรงผ่านเซิร์ฟเวอร์ Model Context Protocol (MCP) ของ BlockVectra

เครื่องมือ `rpc_call` ที่ต้องใช้คีย์ช่วยให้สามารถเรียกใช้เมธอด JSON-RPC บนเชนที่รองรับได้ โดยต้องกำหนดค่า API key ใน HTTP header ของไคลเอนต์ MCP (`x-api-key: {api_key}` หรือ `Authorization: Bearer {api_key}`) และห้ามส่งคีย์ภายในพารามิเตอร์ของเครื่องมือหรือพร้อมท์การสนทนาโดยเด็ดขาด

ตัวอย่างเพย์โหลดการเรียกใช้เครื่องมือ `rpc_call` บน Robinhood Chain:

```json
{
  "chain": "robinhood_mainnet",
  "method": "eth_simulateV1",
  "params": [
    {
      "blockStateCalls": [
        {
          "calls": [
            {
              "from": "0x1111111111111111111111111111111111111111",
              "to": "0x2222222222222222222222222222222222222222",
              "data": "0xa9059cbb00000000000000000000000033333333333333333333333333333333333333330000000000000000000000000000000000000000000000000de0b6b3a7640000",
              "value": "0x0"
            }
          ]
        }
      ]
    },
    "latest"
  ]
}
```

Agent สามารถตรวจสอบ `status === "0x1"` เพื่อยืนยันความถูกต้องของการโต้ตอบกับสัญญาและประเมินปริมาณการใช้ gas ก่อนส่งธุรกรรมดิบ ดูคำแนะนำในการตั้งค่าและการใช้งานได้ที่ [คู่มือการเชื่อมต่อ AI Agent](https://docs.blockvectra.com/en/guides/ai-agents/)

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

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