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

本文详细解释了智能合约中状态变量如何在存储中组织,包括固定大小和动态大小类型的存储规则,以及keccak256哈希函数在数组和映射中的应用。通过实例展示了变量如何分配和占据存储槽,以及EVM中的实际操作过程。
摘要由CSDN通过智能技术生成

存储规则

智能合约的所有状态变量 - 或持久性变量 - 都驻留在合约的存储中。合约的存储是一个大型数组,组织成大小为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))。

注意

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

通过简单合约举例:

// 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调试显示结果是:

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

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

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

在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字节),并对连接后的值进行哈希计算。

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

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

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值