Bạn có thể đã xem qua một số mẹo Solidity để cải thiện kỹ năng viết mã của mình nhằm tiết kiệm xăng, nhưng hôm nay tôi muốn tập trung nhiều hơn vào cách hiểu Máy ảo Ethereum có thể giúp bạn tiết kiệm chi phí gas một cách hiệu quả cho các hợp đồng thông minh của mình.

Vì chúng ta sẽ đi sâu vào Ethereum nên tôi sẽ để lại ở đây đoạn trích trong Sách vàng trong đó chỉ rõ chi phí gas của các opcode và trong suốt bài viết, chúng ta sẽ đề cập đến chúng.



Mẹo số 1: Truy cập lạnh VS truy cập ấm

Gcoldload: 2100 xăng

Gwarmaccess: 100 gas

Ở đó, chúng tôi có OPCODES đầu tiên, cái đầu tiên chỉ định chi phí để truy cập một biến lần đầu tiên (hoặc truy cập nguội) trong khi cái thứ hai chỉ định chi phí để truy cập vào biến lần thứ hai trở lên (quyền truy cập ấm áp) ). Như bạn có thể thấy sự khác biệt về giá là khá lớn, vì vậy hiểu được điều này có thể tạo ra sự khác biệt lớn về chi phí giao dịch hợp đồng thông minh của bạn. Hãy xem một ví dụ.





Việc lưu vào bộ nhớ đệm dữ liệu bên trong một hàm trong Solidity có thể giúp giảm mức sử dụng gas, ngay cả khi hàm đó cần nhiều dòng mã hơn. Trong trường hợp này, bằng cách chuyển đổi vị trí của mảng và thay vì sử dụng mảng đó từ bộ nhớ và do đó truy cập ngẫu nhiên vào mảng đó mỗi lần trong vòng lặp, nó sẽ lưu trữ mảng đó trong bộ nhớ ở nơi rẻ hơn để truy cập vào mảng đó.

Mẹo số 2: Giá trị 0 so với khác 0 và hoàn tiền gas

Gsset = 20.000 xăng

Rsclear = {chiết khấu trên giá thực hiện}

Việc thay đổi giá trị từ 0 thành khác 0 trên chuỗi khối Ethereum rất tốn kém như chúng ta thấy về giá của Gsset, nhưng việc thay đổi giá trị từ khác 0 thành 0, có thể giúp bạn hoàn lại giá trị gas theo mã opcode Rsclear. Để không tận dụng khoản hoàn trả, quy định rằng bạn chỉ có thể được hoàn lại tối đa 20% tổng chi phí giao dịch.

Bạn có thể tìm thấy tình huống như vậy trong một tình huống rất phổ biến trên blockchain, đó là cập nhật số dư địa chỉ trong hợp đồng thông minh. Chúng ta hãy xem một ví dụ về mỗi:





  • Trong ví dụ đầu tiên, hợp đồng ZeroToNonZero, khác 0 đến khác 0 (5.000 gas*) + 0 đến khác 0 (20.000 gas) = ​​25.000 gas

  • Trong ví dụ thứ hai, hợp đồng NonZeroToZero, Non-zero đến 0 (5.000 gas*) + 0 đến khác 0 (20.000 gas) — Hoàn tiền (4.800 gas) = ​​21.200 gas

*2.100 (Gcolssload) + 2.900 (Gsreset) = 5.000 gas

Mẹo số 3: Thứ tự của các biến trạng thái rất quan trọng

Bộ lưu trữ giống như một cấu trúc dữ liệu khóa-giá trị chứa các giá trị biến trạng thái của hợp đồng thông minh Solidity.

Bạn có thể coi việc lưu trữ như một mảng sẽ giúp hình dung điều này. Mỗi không gian trong “mảng” lưu trữ này được gọi là một vị trí và chứa 32 byte (256 bit) dữ liệu và mỗi biến trạng thái được khai báo trong hợp đồng thông minh sẽ chiếm một vị trí tùy thuộc vào vị trí khai báo và loại của nó.

Không phải tất cả các loại dữ liệu đều chiếm hết 32 byte của mỗi vị trí vì có một số loại dữ liệu (bool, uint8, address…) chiếm ít hơn thế.

Mẹo ở đây là nếu hai/ba biến trở lên có kích thước 32 byte trở xuống, trình biên dịch của Solidity sẽ cố gắng gói chúng lại với nhau trong một khe duy nhất, nhưng các biến này cần được xác định cạnh nhau.





Ở đây chúng tôi đang sử dụng các loại dữ liệu bool (1 byte), địa chỉ (20 byte) và uint256 (32 byte). Vì vậy, khi biết kích thước của các biến này, bạn có thể dễ dàng hiểu rằng trong ví dụ đầu tiên trong hợp đồng TwoSlots vì chúng ta có bool và địa chỉ cùng nhau (1 + 20 = 21 byte, nhỏ hơn 32 byte) nên chúng sẽ chiếm một vị trí. Trong hợp đồng ThreeSlots vì bool và uint256 không thể ở cùng một vị trí (1 + 32 = 33 byte, lớn hơn dung lượng của vị trí) nên tổng cộng chúng tôi sẽ sử dụng ba vị trí.

Bây giờ, tại sao điều này lại quan trọng?

Mã hoạt động SLOAD tốn 2100 gas và được sử dụng để đọc từ các khe lưu trữ, vì vậy nếu bạn có thể lưu trữ các biến trong ít khe cắm hơn thì cuối cùng bạn sẽ tiết kiệm được một ít gas.

Mẹo số 4: uint256 rẻ hơn uint8

Chúng ta đã tìm hiểu ở mẹo số 3 rằng uint256 (256 bit = 32 byte) chỉ chiếm một vị trí và chúng ta cũng đã biết rằng uint8 nhỏ hơn 32 byte. Vì vậy, mặc dù khá đơn giản là 8 bit nhỏ hơn 256 bit, nhưng tại sao uint256 rẻ hơn?

Để hiểu điều đó, điều quan trọng là phải biết rằng nếu một biến không tự lấp đầy toàn bộ vị trí và nếu vị trí này không được lấp đầy bởi bất kỳ biến nào khác thì EVM sẽ lấp đầy phần còn lại của các bit còn lại bằng “0” để có thể thao tác nó.

Việc bổ sung “0” do EVM thực hiện này sẽ tốn gas, nghĩa là để tiết kiệm gas giao dịch, tốt hơn nên sử dụng uint256 thay vì uint8.

__________________

Hy vọng rằng, khi tìm hiểu về những mẹo này để giảm chi phí gas trong hợp đồng thông minh của bạn, bạn cũng đã học được một chút về cách hoạt động của EVM.

__________________

Twitter @TheBlockChainer để tìm thêm thông tin cập nhật hàng ngày về Hợp đồng thông minh, Bảo mật Web3, Solidity, Hợp đồng thông minh kiểm tra, v.v.

__________________