智能合约状态变量的存储体现

  • SpikeDu
  • 更新于 2024-05-06 14:39
  • 阅读 1131

智能合约状态变量的存储体现

存储规则

智能合约的所有状态变量 - 或持久性变量 - 都驻留在合约的存储中。合约的存储是一个大型数组,组织成大小为32字节(256位)的槽,每个槽由一个唯一的索引标识,范围从0到$2^{256}-1$。对于每个给定的状态变量,存储槽索引必须以确定性的方式计算,以确保对存储数据的一致访问。事实上,这种存储槽中状态变量的布局由编译器确定,编译器考虑源代码中变量的声明顺序(Solidity 编译器为例)。

固定大小的变量类型。基本类型,如uint(32字节)、地址(20字节)和布尔值(1字节)以连续的方式存储在32字节的槽中,从槽0x0开始。值得注意的是,需要少于32字节的多个连续项被打包到单个存储槽中以节省空间,根据以下规则进行打包:

  • 存储槽中的第一项始终与到最低有效字节对齐。
  • 固定大小的类型仅使用所需的字节来存储它们。
  • 如果变量不适合存储槽的剩余部分,则将其存储在下一个存储槽中。

动态大小的变量类型。动态类型,如数组和映射,始终存储在新的槽中(基槽),它们的元素根据以下规则存储:

  • 基槽存储数组的长度,或者在映射的情况下,它被留空。
  • 每个数组元素(具有索引:INDEX)存储在槽keccak256(BASE)+INDEX中。
  • 映射的每个元素(具有键:KEY)存储在通过连接KEY和BASE并将结果值用作keccak256函数的输入计算得到的槽中(即,keccak256(KEY.BASE))。

image.png

注意

状态变量在存储中的位置是通过声明状态变量来分配空间的(占坑的)。

通过简单合约举例:

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

 struct Values {  
        uint8 a;   
        address b;  
        bytes4 c;  
    }      

contract Test { 

    Values value;        
    uint8 balance;
    bytes4 data;
    address addr;
    uint8[] uint8Array;
    mapping(address => uint256) isMapping;  

     constructor(){
        balance = 8;
        addr = 0x358AA13c52544ECCEF6B0ADD0f801012ADAD5eE3; 
        uint8Array.push(1);
        uint8Array.push(2);
        isMapping [addr] = 123;
    }

}

Values结构体总体大小为25字节大小,第一个声明Values value;占用 Slot 0 这个坑,哪怕没对value进行赋值。

balance占用8字节,因此无法完全存储在slot 0 剩余大小的空间中,因此balance开始存储在slot 1的低位。data占用4字节,存储在slot 1中,而addr占用20字节,也存储在slot 1中。在构造函数中,被赋值的只有balanceaddr

slot1 在remix调试显示结果是:

image.png

可以看到两个被赋值的没有紧挨在一起存储,因为中间4字节被data声明给占坑了。

规则中数组和映射基槽都占用一整个32字节的 slot 作为基槽。

uint8Array的基槽就是 slot 2,keccak256(BASE)哈希计算出要存储的slot位置,将元素按keccak256(BASE)+INDEX要求存入。

image.png

在mapping中,keccak256(KEY.BASE)在EVM中的实现是通过执行keccak256操作码来完成的。这个操作码会消耗堆栈中的两个元素:stack(0)中的值表示要读取的内存起始位置,stack(1)中的值表示要读取字节的大小。

具体来说,memory(0)中缓存的是addr的值,而memory(1)中缓存的是基槽slot 3的值。然后,EVM会读取这两个值连接起来的64字节数据(memory(0)的32字节 + memory(1)的32字节),并对连接后的值进行哈希计算。

image.png

执行完后,isMapping [addr] = 123在storage中的体现是:

image.png

如果有任何错误,请指正。

点赞 0
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
SpikeDu
SpikeDu
0xf0F0...Ba88
江湖只有他的大名,没有他的介绍。