Skip to content

Latest commit

 

History

History
65 lines (50 loc) · 2.27 KB

File metadata and controls

65 lines (50 loc) · 2.27 KB

11 用 uint 来节省重入保护的 gas

运行

根据Foundry 官方文档配置好运行环境后,于本项目下执行下列命令,即可看到实际 gas 差异对比。

forge test --contracts 11_ReentrancyGuard/ReentrancyGuard.T.sol --gas-report

功能简述

利用modifier 来验证合约的重入调用。设置一个Bool变量,每次调用的时候都验证当前是否为锁定状态。只有未锁定时,才会执行函数调用,函数结束时再次恢复锁的状态,同样,我们也可以用Uint变量来解决重入调用。

DemoCode

下面分别用Bool、Uint01和Uint12(使用默认值0和非0初始化)三种形式解决重入调用,来观察其 gas 差异。

contract ReentrancyGuardBool{
    bool private locked  = false;
    modifier nonReentrant(){
        require(locked == false,"REENTRANCY");
        locked = true;
        _;
        locked = false;
    }
}

contract ReentrancyGuardUint01{
    uint256 private locked = 0;
    modifier nonReentrant(){
        require(locked == 0,"REENTRANCY");
        locked = 1;
        _;
        locked = 0;
    }
}

contract ReentrancyGuardUint12{
    uint256 private locked = 1;
    modifier nonReentrant(){
        require(locked == 1,"REENTRANCY");
        locked = 2;
        _;
        locked = 1;
    }
}

以下是测试后的情况说明,gas 优化建议如下:

因为部署产生的gas是一次性的,开发者一般会关注日常交易产生的gas,所以需要在不考虑部署gas的情况下分开说明:

  1. 使用Bool:EVM将布尔值存储为uint8类型,占用两个字节,因此访问该值实际上更昂贵。这是因为EVM单词长度为32字节,所以需要额外的逻辑来告诉虚拟机解析小于标准大小的值;
  2. 使用Uint01:在每次调用时将 0 更改到非 0 时会产生 ≈ 20k的gas;
  3. 使用Uint12:在每次调用时将非 0 值更改为非 0 值时,只会产生2900的gas。

因为一般重入保护函数是会被多次调用的,所以建议使用Uint12这种方式。

重入保护 gas 消耗 节省 结果
Bool 27757
Uint01 27604 153
Uint12 13908 13849 ✅ 建议