gas优化必须掌握的知识点

在以太坊等区块链网络中,Gas是执行智能合约操作所需支付的费用,Gas优化能够降低交易成本并提升合约执行效率。这篇文章主要讲述5个方面总结常用的优化方法。

在以太坊等区块链网络中,Gas 是执行智能合约操作所需支付的费用,Gas 优化能够降低交易成本并提升合约执行效率。下面我来5个方面总结常用的 Solidity 智能合约中 Gas 优化的方法:

变量和数据类型方面

  • 选用合适的数据类型 优先采用占用空间小的数据类型。例如,数值范围较小就使用 uint8 而不是 uint256
  • 状态变量的打包 solidity 里每个存储槽(slot)大小为32字节,把多个小的状态变量组合到一个存储槽可节省 gas。
    // 不推荐
    uint8 a;
    uint8 b;
    // 推荐
    struct Packed {
        uint8 a;
        uint8 b;
    }
    Packed packed;
    # 函数和控制结构方面
    - **避免重复计算**
    把重复计算的结果存储在局部变量中,防止重复执行相同的计算。
     ```solidity
    // 不推荐
    function calculateSum() public view returns (uint256) {
        return (1 + 2 + 3) + (1 + 2 + 3);
    }
    // 推荐
    function calculateSum() public view returns (uint256) {
        uint256 temp = 1 + 2 + 3;
        return temp + temp;
    }
  • 减少循环次数 | 减少计算 在循环中尽量减少不必要的操作,避免无限循环。 循环中还可以把 array.length 用一个变量代替,减少计算量;同样如果循环体中多次用到 array[i] 也可用变量代替
    // 不推荐
    for (uint256 i = 0; i < array.length; i++) {
    if (array[i] == 0) {
        continue;
    }
    // 处理逻辑
    }
    // 推荐
    let len = array.length;
    for (uint256 i = 0; i < len; i++) {
    let item = array[i];
    if (item != 0) {
        // 处理逻辑
    }
    }
  • 短路求值 使用逻辑运算符 && 和 || 时,利用短路求值特性减少不必要的计算

    if (condition1 && condition2) {
        // 执行代码
    }

    若 condition1 为 false,则不会再计算 condition2

    存储和内存使用方面

    • 减少存储读写 存储操作(SSTORE 和 SLOAD)消耗的 Gas 较多,尽量减少对状态变量的读写操作。可先把状态变量的值读取到局部变量,在局部变量上进行操作,最后再写回状态变量。
      // 不推荐
      function updateValue() public {
          stateVariable = stateVariable + 1;
      }
      // 推荐
      function updateValue() public {
          uint256 temp = stateVariable;
          temp = temp + 1;
          stateVariable = temp;
      }
    • 内存的合理使用 内存操作(MSTORE 和 MLOAD)消耗的 Gas 相对较少,但也要避免不必要的内存分配和复制。

合约设计和继承方面

  • 合约的拆分 把大型合约拆分成多个小合约,通过合约间的调用实现功能,这样可减少单个合约的复杂度和 Gas 消耗。
  • 避免深度继承 继承层次过深会增加合约的复杂度和 Gas 消耗,尽量保持继承层次简洁。

事件和日志方面

  • 使用事件记录数据 事件用于记录合约状态的变化,存储在日志中,不消耗存储 Gas。需要记录数据时,优先使用事件。

    contract EventExample {
        event ValueUpdated(uint256 newValue);
    
        function updateValue(uint256 _newValue) public {
            // 触发事件
            emit ValueUpdated(_newValue);
        }
    }

外部调用和库方面

  • 减少外部调用 外部调用(如 calldelegatecall)消耗的 Gas 较多,尽量减少不必要的外部调用。
  • 使用库 把常用的功能封装到库中,通过库函数调用可减少代码的重复,降低 Gas 消耗。
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
mengbuluo222
mengbuluo222
前端开发求职中... 8年+开发经验,拥有丰富的开发经验,擅长VUE、React开发。