Skip to content

Latest commit

 

History

History
55 lines (38 loc) · 2.23 KB

readme.md

File metadata and controls

55 lines (38 loc) · 2.23 KB

03 位图与位运算符

运行

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

forge test --contracts 03_Bitmap/Bitmap.T.sol --gas-report

功能简述

我们知道在区块链上,存储是非常昂贵的,在一些前沿的项目中,会用一些 hack 的方法来降低 gas,今天讲的这种方法,就常见于一些头部项目的源码中。

如 uint8 二进制表示为 00000000,其中每一位有 0、1 两种情况,我们默认为 1 时则为 true,0 为 false,此时可以达到将 bool 值以位的形式来进行管理。

DemoCode

下面分别用 bool 数组和 位运算 来管理相同的数据。

contract Bitmap {
    bool[8] implementationWithBool;
    uint8 implementationWithBitmap;

    function setDataWithBoolArray(bool[8] memory data) external {
        implementationWithBool = data;
    }

    function setDataWithBitmap(uint8 data) external {
        implementationWithBitmap = data;
    }

    function readWithBoolArray(uint8 index) external returns (bool) {
        return implementationWithBool[index];
    }

    function readWithBitmap(uint indexFromRight) external returns (bool) {
        uint256 bitAtIndex = implementationWithBitmap & (1 << indexFromRight);
        return bitAtIndex > 0;
    }
}

readWithBitmap 函数里的1 << indexFromRight代表位移操作,将数值1向左移动indexFromRight位,右侧空出的位用0填充。例如,若indexFromRight2,则1 << 2结果为100

&表示对implementationWithBitmap(1 << indexFromRight)两个数值的每一位进行AND操作。只有当两个数值在某一位上都是1时,结果的那一位才为1,否则为0。这种操作常用于检查某个特定位是否被设置为1

以下是 2 种情况下,写入变量消耗的 gas 差异对比。gas 优化建议如下:

  1. 结合实际情况下,建议优先使用 位运算符 进行部分变量管理。
关键字 gas 消耗 节省 结果
位运算符 22366 13363(≈37%) ✅ 建议
普通变量 35729