节约gas小妙招 / 学习智能合约#63

把节约gas的几个方法测试了下,蛮有效的。以前看起来有些多余的操作其实是另有深意啊。比如常见的语句uint _arr = arr[i],直接写arr[i]不是更直观么,为什么非要定义一个变量呢?!现在终于揭晓了谜团:原来是为了节约gas啊!

案例集 中把这些方法都总结了,我也测试了下,还是很实用嘀!

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// gas golf
contract GasGolf {
    // start 56530 gas 
    //public -> external 最小化权限 56530 gas
    //变量memory -> calldata  54104 gas
    //多个条件变短 53816 gas
    // total -> _total 加载状态变量到内存变量 52291 gas 
    // nums.length -> len 数组长度缓存到内存 52232 gas
    // nums[i] -> num 缓存多次使用的数组元素到内存 51581 gas
    //i+=1 -> ++i 51023 gas

    uint public total;

    // start - not gas optimized [2, 10, 30, 55, 56, 62, 52, 2, 16]
    function sum1(uint[] memory nums) external {
        for (uint i = 0; i < nums.length; i += 1) {
            bool isEven = nums[i] % 2 == 0;
            bool isLessThan99 = nums[i] < 99;
            if (isEven && isLessThan99) {
                total += nums[i];
            }
        }
    }

    // gas optimized
    function sum2(uint[] calldata nums) external {
        uint _total = total;
        uint len = nums.length;

        for (uint i = 0; i < len; ) {
            uint num = nums[i];
            if (num % 2 == 0 && num < 99) {
                _total += num;
            }
            unchecked {
                ++i;
            }
        }

        total = _total;
    }
}

测试合约如上,大家也可以尝试着去做。节约gas的方法可以总结如下

  1. 最小化权限控制,尽量用external, private, internal, 尽量不用public
  2. 变量类型优先使用calldata而不是memory
  3. 加载状态变量到内存变量
  4. 多个条件判断使用短路方式
  5. 在循环中使用 ++i,而不是i+=1, i++
  6. 数组长度缓存到内存
  7. 缓存多次使用的数组元素到内存