Estimate Gas

Tổng quan

Trước khi submit một Transaction lên Ethereum Blockchain, ta có thể đo lường trước lượng gas hao phí (Gas Limit).

Lưu ý:

  • Gas Limit được ước lượng bởi Estimate Gas là không chính xác, tuy nhiên nó vẫn mang giá trị tham khảo và cho ra con số gần đúng

  • Trên thực tế Gas Limit cần để thực hiện thường cao hơn, vì thế sau khi estimate gas nên thêm một khoảng 10% hoặc cao hơn

  • Cùng một Transaction với nội dung như nhau thì Gas Limit được Estimate ở Mainnet hay Testnet là đều như nhau

  • So với các Transaction thực hiện những việc cơ bản như chuyển Eth trên blockchain thì các Transaction tương tác với SmartContract thường bị Estimate sai lệch nhiều hơn

Tuy nhiên đôi lúc khó tránh khỏi trường hợp cho dẫu đã Estimate Gas và thêm một khoảng hơn 10% vào nhưng Transaction vẫn fail do không đủ Gas. Trong trường hợp này thì cách duy nhất là phải tiếp tục thiết lập lại Gas Limit và submit lại Transaction.

Cách thực hiện:

Để estimate một Transaction tương tác với một Smart Contract, ta tạo một request tới Ethereum Node với method là eth_estimateGas cùng với các params như sau

  • from: địa chỉ của account thực hiện Transaction

  • to: địa chỉ của Smart Contract

  • data: chứa các thông tin về fuction, params, ... cần tương tác

Tất cả các param đều phải ở dạng Hex.

Ví dụ:
{
    "jsonrpc": "2.0",
    "method": "eth_estimateGas",
    "params": [
        {
        "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", //sender
        "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",   //receiver
        "gas": "0x76c0",               //optional
        "gasPrice": "0x9184e72a000",   //optional
        "value": "0x0",                //optional
        "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
        }
    ],
    "id": 1
}

Xác định data

Data được xác định bởi function và các tham số được truyền vào nó. Ví dụ Smart Contract sau:

Nếu muốn gọi function baz với parameter là 69true thì data bao gồm:

  • 0xcdcd77c0: Method ID, là 4 bytes đầu tiên của Keccak Hash của function dưới định dạng ASCII là baz(uint32,bool)

  • 0x0000000000000000000000000000000000000000000000000000000000000045: đối số đầu tiên với giá trị 69 đã được padded đến 32 bytes

  • 0x0000000000000000000000000000000000000000000000000000000000000001: đối số thứ hai với giá trị true đã được padded đến 32 bytes

Nối lại các giá trị trên, ta có data như sau:

Tuy nhiên cách xác định data trên chỉ đúng với elementary types, còn với kiểu dữ liệu là fixed-size array typenon-fixed-size types thì cần phải pass thêm lenghpointer.

Chi tiết hơn tham khảo tại : https://solidity.readthedocs.io/en/v0.6.10/abi-spec.html#types

Nếu muốn gọi function barvới parameter là "even" (string là non-fixed-size type) thì data bao gồm:

  • 0x74030531: Method ID, là 4 bytes đầu tiên của Keccak Hash của function dưới định dạng ASCII là bar(string)

  • 0000000000000000000000000000000000000000000000000000000000000020: pointer chỉ định số lượng 32 bytes

  • 0000000000000000000000000000000000000000000000000000000000000004: Length của param này, "even" có 4 ký tự nên sử dụng 4 bytes, khai báo giá trị 4 dưới dạng byte sau đó padded đến 32 bytes

  • 6576656e00000000000000000000000000000000000000000000000000000000:

    Giá trị của param này, thể hiện giá trị string là "even" dưới dạng bytes, sau đó được padded đến 32 bytes

Tuy function bar chỉ có 1 param nhưng khai báo lại rắc rối hơn rất nhiều.

Nối lại các giá trị trên, ta có data như sau:

Lưu ý về kiểu dữ liệu của parameter

Do hạn chế khi khai báo data với kiểu dữ liệu dạng fixed-size array typenon-fixed-size types nên ta hạn chế tối đa việc sử dụng các kiểu dữ liệu này.

Khuyến khích sử dụng elementary type hết mức có thể.

Trong ví dụ trên hướng dẫn cách gọi 1 function sử dụng elementary types và 1 function sử dụng non-fixed-size types, có thể thấy rằng việc khai báo một param kiểu non-fixed-size types (và cả fixed-size array type cũng như thế) là phức tạp và rắc rối hơn.

Tuy nhiên sẽ còn phức tạp hơn nếu như param có lẫn lộn các kiểu dữ liệu với nhau, ví dụ như sử dụng int (elementary types) và string (non-fixed-size types) cùng một lúc. Khi đó sẽ phải chỉ pointer và length cho cả tất cả param (không phải từng param), và thứ tự param được truyền vào cũng sẽ thay đổi.

Do đó, việc khai báo data sẽ trở nên cực kỳ phức tạp và ngay cả một số các thư viện lớn cũng không hỗ trợ Estimate Gas nếu sử dụng lẫn lộn các kiểu dữ liệu.

Trong hình bên dưới, pointer giờ đây phải chỉ định size là 64 bytes vì dùng cho cả hai param là string và uint. Tiếp theo đó là uint256 mặc dù được khai báo sau string trong function nhưng lại truyền vào trước. Còn string được khai báo đầu tiên trong function nhưng lại truyền vào cuối cùng khi tạo data và kèm theo trước đó là length

Thực hiện bằng thư viện của các ngôn ngữ lập trình khác nhau

Tuỳ theo các thư viện của từng ngôn ngữ lập trình khác nhau có cách thực thi Estimate Gas khác nhau, nhưng đều thực hiện một cùng nguyên tắc chung.

Last updated

Was this helpful?