【Solidity Yul Assembly】1.5 | Storage of Arrays and Mappings

  • 0xE
  • 发布于 2024-08-20 10:54
  • 阅读 906

数组与映射是如何存放在“存储槽”的?

数组

固定长度的数组

对于固定长度的数组,处理方式相对简单。

contract StorageComplex {
    uint256[3] fixedArray;

    constructor() {
        fixedArray = [99, 999, 9999];
    }

    function fixedArrayView(uint256 index) external view returns (uint256 ret) {
        assembly {
            ret := sload(add(fixedArray.slot, index))
        }
    }
}

uint256[3] fixedArray; 就相当于声明了三个 uint256 类型的变量,这些变量依次占据从槽 0 开始的存储位置。

动态长度数组

动态长度的数组处理起来稍微复杂一些。

contract StorageBasics {
    uint256[] bigArray;
    uint8[] smallArray;

    constructor() {
        bigArray = [10, 20, 30];
        smallArray = [1, 2, 3];
    }

    function bigArrayLength() external view returns (uint256 ret) {
        assembly {
            ret := sload(bigArray.slot)
        }
    } // returns 3
}

可以看到槽 0 存放的数据是 3, 表示数组 bigArray 的当前长度。那么,数组中的元素存放在哪里呢? 计算方法为:keccak256(slot) + index, 即“存放长度的槽的哈希”就是开始存放元素的存储槽的位置,然后从这个位置开始依次存放元素。

function readBigArrayLocation(uint256 index) external view returns (uint256 ret) {
    uint256 slot;
    assembly {
        slot := bigArray.slot
    }
    bytes32 location = keccak256(abi.encode(slot));
    assembly {
        ret := sload(add(location, index))
    }
}

但是,对于非 uint256 类型的动态数组,几个元素会共用一个槽。

function smallArrayLength() external view returns (uint256 ret) {
    assembly {
        ret := sload(smallArray.slot)
    }
} // returns 3

function readSmallArrayLocation(uint256 index) external view returns (bytes32 ret) {
    uint256 slot;
    assembly {
        slot := smallArray.slot
    }
    bytes32 location = keccak256(abi.encode(slot));
    assembly {
        ret := sload(add(location, index))
    }
} // input 0 returns 0x0000000000000000000000000000000000000000000000000000000000030201

映射(Mapping)

单层映射

映射的存储方式与动态数组相似。不同之处在于,动态数组存储槽的位置是 keccak256(slot),然后加上索引;而映射则是将 slotkey 连接后再做哈希处理,即 keccak256(key, slot)


contract StorageComplex {
    mapping(uint256 => uint256) public myMapping;
    constructor() {
        myMapping[10] = 5;
        myMapping[11] = 6;
    }
    function getMapping(uint256 key) external view returns (uint256 ret) {
        uint256 slot;
        assembly {
            slot := myMapping.slot
        }

        bytes32 location = keccak256(abi....

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享

0 条评论

请先 登录 后评论
0xE
0xE
0x59f6...a17e
17年进入币圈,Web3 开发者。刨根问底探链上真相,品味坎坷悟 Web3 人生。有工作机会可加v:__0xE__