编辑
2024-09-06
Web3技术栈
00
请注意,本文编写于 149 天前,最后修改于 149 天前,其中某些信息可能已经过时。

目录

EVM 存储结构
状态变量如何存储
结构体
映射(map)
数组
定长数组
可变长度素组
字节数组和字符串

EVM 存储结构

image.png

  1. non-volatile (不容易丢失的)存储在code和storage 里的数据
  2. volatile(容易丢失的) 存储在stack, args, memory里的话数据

各个存储位置的含义

  • Code: 专门存储只能合约的二进制源码的空间;
  • Storage: 合约持久化存储数据的地方;Storage 是一个巨大的map, 一共22562^{256}个插槽,每个插槽有32byte;
  • Stack 及所说的运行栈,用来保存EVM 的输入输出,可以免费使用,没有gas消耗,用来保存函数的局部变量,数量被限制在16个,stack的最大深度为1024,其中每个单元是32bytes;
  • Args 也叫calldata, 是一段只读的可寻址的保存函数调用参数的空间,与栈不同的地方是,如果要使用calldata 里面的数据,必须手动指定偏移量和读取的字节数。
  • Memory 一个简单的字节数组,用于在运行期间存储数据,将参数传递给内部函数。基于32byte 进行寻址和扩展。

状态变量如何存储

  • 对于大小在32字节以内的变量(常量),以其定义的顺序作为它的索引值存储。
  • 对于连续较小的值,可能被优化存储在同一个位置

合约中前四个状态变量都是 uint64 类型的,则四个状态变量的值会被打包成一个 32 字节的值存储在 0 位置。

结构体

对于代下载32字节以内的结构体同样也是顺序存储。

例如结构体变量索引定义在位置 0,结构体内部有两个成员,则这两个成员的依序为 0 和 1

映射(map)

map 存储位置是通过 keccak256 (bytes32(key) + bytes32(position) ) 计算得到的,position 表示 key 对应 storage 类型变量存储的位置。

数组

定长数组

同上,只要在 32 字节以内也是顺序存储,不过在编译时编译器会进行边界检查防止越界。

可变长度素组

由于可变长度数组长度不定,一般在编译可变长度数组时候会提前预留存储空间,所以就会使用状态变量的位置存储数组的长度。 具体的数据地址会通过keccak256(bytes32(position))算出数组首地址,再加数组长度偏移量获得具体的元素。

理论的最大值是225612^{256}-1

字节数组和字符串

  1. 对于定长字节数组则是同定长数组一样;
  2. 对于可变字节数组和字符串,会在存储值位置补0一直到32字节,并用补0的最后一个字节存储字符串的编码长度。

当节数组和字符串长度大于31字节时

  1. 变量位置存储编码长度,并且编码长度公式更换为编码长度 = 字符数 * 2 + 1
  2. 真实存储值第一个位置通过公式 keccak256(bytes32(position)) 获取,剩余值在获取到的位置顺序存储,同样在最后存储位置补0到32字节。

本文作者:Ramondy

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!