current position:Home>Inside Solidity - Ethereum EVN Slots Store Relationships

Inside Solidity - Ethereum EVN Slots Store Relationships

2022-08-05 04:50:29Zeke Luo

以太坊虚拟机Ethereum Virtual Machine(EVM) Have three kinds of storage area.

  • 存储storage ( 贮存了合约声明中所有的变量)

贮存了合约声明中所有的变量. 虚拟机会为每份合约分别划出一片独立的 存储storage 区域,并在函数相互调用时持久存在,所以其使用开销非常大.

每个账户有一块持久化内存区称为 存储 . 存储是将256位字映射到256位字的键值存储区. 在合约中枚举存储是不可能的,且读存储的相对开销很高,修改存储的开销甚至更高.合约只能读写存储区内属于自己的部分.

  • 内存memory ( 用于暂存数据)

用于暂存数据.其中存储的内容会在函数被调用(包括外部函数)时擦除,所以其使用开销相对较小.

合约会试图为每一次消息调用获取一块被重新擦拭干净的内存实例. 内存是线性的,可按字节级寻址,但读的长度被限制为256位,而写的长度可以是8位或256位.当访问(无论是读还是写)之前从未访问过的内存字(word)时(无论是偏移到该字内的任何位置),内存将按字进行扩展(每个字是256位).扩容也将消耗一定的gas. 随着内存使用量的增长,其费用也会增高(以平方级别)

  • (用于存放小型的局部变量)

用于存放小型的局部变量.使用几乎是免费的,但容量有限.

For most of the data type,Because every time be used will be copied,So you won't be able to specify where stores it.

在数据类型中,The so-called storage place more emphasis on is structure and array. If you passed the class variables in the function call,Assume that their data can be stored in 存储storage 或 内存memory 中,Then they will not be copied.也就是说,When you modify the function of their content,These changes are callers are also visible

EVM 不是基于寄存器的,而是基于栈的,因此所有的计算都在一个被称为 栈(stack) 的区域执行. 栈最大有1024个元素,每个元素长度是一个字(256位).对栈的访问只限于其顶端,限制方式为:允许拷贝最顶端的16个元素中的一个到栈顶,或者是交换栈顶元素和下面16个元素中的一个.所有其他操作都只能取最顶的两个(或一个,或更多,取决于具体的操作)元素,运算后,把结果压入栈顶.当然可以把栈上的元素放到存储或内存中.但是无法只访问栈上指定深度的那个元素,除非先从栈顶移除其他元素

不同数据类型的变量会有各自默认的存储地点:

  • State variables are always there

    存储storage

  • 函数参数默认存放在

    内存memory

  • 结构、数组或映射类型的局部变量,默认会放在

    存储storage

  • 除结构、数组及映射类型之外的局部变量,会储存在栈中

    Because the structure and array belong to引用类型,  映射mappingUnpredictable and dynamic array size,Not between state variables to store them

    引用类型

    Reference types can be modified by a number of different names its value,The value type variable,Each has a copy of the independent.因此,Must ratio type more carefully handle reference type. 目前,Reference types including structure,数组和映射,If you use a reference type,Must be made clear what type of position data storage(空间)里:

    • 内存memory 即数据在内存中,因此数据仅在其生命周期内(函数调用期间)有效.不能用于外部调用.
    • 存储storage 状态变量保存的位置,只要合约存在就一直存储.
    • 调用数据calldata 用来保存函数参数的特殊数据位置,是一个只读位置.

    State variables in the store(storage)中的布局

    Contract of state variables are stored in a compact way to block storage, In addition to the size of a dynamic array and 映射mapping (见下文),Data storage is from position 0 Placed in row 存储storage 中. 对于每个变量,According to its type byte size.

    Storage size less than 32 Bytes of multiple variables will be packaged into a 存储插槽storage slot 中,规则如下:

    • 存储插槽storage slot The first item will be stored in the form of low alignment.
    • Value types using only store their required bytes.
    • 如果  In the remaining space is not enough to store a value type,Then it will be stored in a storage slot understorage slot
    • 结构体(struct)And will always open a new slot array data(But the structure or the elements of the array,Is according to the rules of closely packed).
    • Structure and an array of data or open a new slot.

    对于使用继承的合约,State variables of sorting by theC3The linear combination about the order( Order from the base class began to contract)确定.If the above rules set up,The state variables from different contracts will share a 存储插槽storage slot .

    Members of the structure and array variables will be stored together,Just like when they separate statement

     在使用小于 32 字节的元素(变量)时,合约的 gas 使用量可能会高于使用 32 字节的元素.这是因为 以太坊虚拟机Ethereum Virtual Machine(EVM) 每次操作 32 个字节, 所以如果元素比 32 字节小,以太坊虚拟机Ethereum Virtual Machine(EVM) Must perform additional operations so that would reduce its size to the desired size.

    When we were in the treatment of the state variables,Using the compiler will multiple elements reduced storage size package to a 存储插槽storage slot 中,Maybe it is good,Because you can merge multiple read/write as a single operation.

    If you are not read or write at the same time all the values in a slot,这可能会适得其反. When a value is written to more than one value in storage tank,Must first read the storage tank,Then a merger with the new value,To avoid damage to other data in the same slot,再写入.

    When processing function parameters or 内存memory 中的值时,因为编译器不会打包这些值,So no additional benefits.

    最后,为了允许 以太坊虚拟机Ethereum Virtual Machine(EVM) 对此进行优化,请确保 存储storage 中的变量和 struct Members of the writing order allows them to be tightly packed.

    例如,应该按照 uint128,uint128,uint256 Order to declare the state variables,而不是使用 uint128,uint256,uint128 , Because the former takes only two 存储插槽storage slot,While the latter will occupy three.

    Mapping and dynamic array

    由于 映射mapping Unpredictable and dynamic array size,Not between state variables to store them.相反,Themselves according to the 以上规则 仅占用 32 个字节,Then they contain elements of the stored position actually,则是通过 Keccak-256 Hash calculations to determine the.

    假设 映射mapping Or dynamic array according to the rules of the above storage eventually can be set for a certain position p . 对于动态数组,The number of this slot will be stored in the array elements(字节数组和字符串除外,见下文). 对于 映射mapping ,The slots are not use(为空),But it is still need,To ensure that the two next to each other 映射mapping ,Their content in different position.

    An array of elements from keccak256(p) 开始; Its layout and the size of a static array is the same.One of the elements and then an element,If the element does not exceed the length of16字节,It is possible to Shared storage tank.

    Dynamic array array will recursively apply this rule,例如,如何确定 x[i][j] 元素的位置,其中 x 的类型是 uint24[][],计算方法如下(假设 x`Itself is stored in the tank`p): Tank is located in the keccak256(keccak256(p)+i)+floor(j/floor(256/24)) And can be from the slot data v``Get the element content,使用``(v>>((j%floor(256/24))*24))&type(uint24).max.

    映射mapping 中的键 k The corresponding slot will be located in keccak256(h(k). p) ,其中 . 是连接符, h 是一个函数,According to the type of key:

    • 值类型, h And stored in the memory value fill of values in the same way as the way to32字节.
    • 对于字符串和字节数组, h(k) 只是未填充的数据.

    But if the value of the mapping is a value type,Calculating slot marked the beginning of data location.例如,If the value is a structure type,You must add a corresponding offset with structure members to get to the members.

    例如,Consider the following contract:

    *// SPDX-License-Identifier: GPL-3.0***pragma solidity** >=**0.4.0** <**0.9.0**;
    
    **contract** **C** {
        struct S { uint16 a; uint16 b; uint256 c; }
        uint x;
        mapping(uint => mapping(uint => S)) data;
    }
    

    让我们计算一下 data[4][9].c 的存储位置.The location of the map itself is 1``( 前面有32字节变量 ``x ). 因此 data[4] 存储在 keccak256(uint256(4) . uint256(1))data[4] The type of another map, data[4][9] The data of started in the slot keccak256(uint256(9). keccak256(uint256(4). uint256(1)).

    在结构 S 的成员 c The slot migration is 1,因为 a 和 b``Comes in a slot in the. 最后 ``data[4][9].c The slot position is keccak256(uint256(9) . keccak256(uint256(4) . uint256(1)) + 1. This value is of type uint256,It USES a tank

    Variables in memory layout

    SolidityKeep the four32字节的插槽,字节范围(包括端点)Specific purposes as follows:

    • 0x00 - 0x3f (64 字节): Used for hashing method of temporary space(临时空间)
    • 0x40 - 0x5f (32 字节): 当前分配的内存大小(As the free memory pointer)
    • 0x60 - 0x7f (32 字节): Zero slot

    Temporary storage space can be used between the statement (For example in inline assembly). Zero slot is used as the initial values of an array of dynamic memory,And should never write to(Free memory pointer to the original point 0x80).

    Solidity Always put the new object on the free memory pointer,And the memory will never be released(将来可能会改变).

    Solidity Always occupy memory in the the elements in the array32字节的倍数(对于 bytes1[] 总是这样,但不适用与 bytes 和 string ).

    The dimensional memory array is a pointer to the memory array,The length of the dynamic array is stored in the first slot array,Then the array elements.

    警告:

    SolidityThere are some need to temporary storage area in operation requires more than64个字节, So we can not put into temporary space. They will be placed in the free memory to the location of the,But due to the short service life of,Pointer does not update. Memory can be zero,Also can not return to zero. 因此,Should not expect the free memory pointer to zero memory area.

    尽管使用 msize To reach the absolute zero memory area seems to be a good idea,But the temporary pointer without using such update free memory pointer may produce unexpected results

    With the storage layout in different

    如上所述,In memory of the layout and the in Store is a bit different.下面是一些例子:

    • 数组的不同

    In the array in the storage of the following32字节(1个槽),But in the memory footprint128字节(4个元素,每个32字节).

    uint8[4] a;
    
    • Structure of different

    The following structure in storage occupied 96 (1个槽,每个32字节) ,But in the memory footprint 128 个字节(4 个元素每个 32 字节).

    struct S {
        uint a;
        uint b;
        uint8 c;
        uint8 d;
    }
    

    Call Data布局

    Assume that the function call input data using ABI规范. 其中,ABIFill this specification requires that the parameter with32的倍数 个字节. The provisions of the internal function calls using different.

    Assume that the function call data input parameters using ABI规范 定义的格式. 其中,ABIFill this specification requires that the parameter with32字节的倍数. The provisions of the internal function call is using different.

    Contract constructor parameters directly attached at the end of the contract code,也采用ABI编码. The constructor will by hard-coded offsets rather than through the use of codesize Operation code to access them,Because the data is appended to the code,It could change the

    Data location and assignment

    Data location not only represent data how to preserve,It also affects the valuation behavior:

    • 在  和  Between two assignment(或者从  赋值 ),Will create a separate copy.

      存储storage

      内存memory

      调用数据calldata

    • 从  到  The assignment only create reference, This means that the change of memory variables,Other reference data of all the other same value of the variable memory will follow to change.

      内存memory

      内存memory

    • 从  To a local variable assignment is assigned a reference only.

      存储storage

    • Other to  的赋值,Always be copied. The example of this kind of circumstance, such as the state variables or  The structure type of the members of the local variable assignment,But even if the local variable is a reference,Will make a copy

      存储storage

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity >=0.5.0 <0.9.0;
    
    contract Tiny {
        uint[] x; // x Data storage location is storage, Location can be ignored
    
        // memoryArray Data storage location is memory
        function f(uint[] memory memoryArray) public {
            x = memoryArray; // The entire array copy to storage 中,可行
            uint[] storage y = x;  // 分配一个指针(其中 y Data storage location is storage),可行
            y[7]; // 返回第 8 个元素,可行
            y.pop(); // 通过 y 修改 x,可行
            delete x; // 清除数组,同时修改 y,可行
    
            // The following is not possible;需要在 storage Create an array of new unnamed temporary,
            // 但 storage 是“静态”分配的:
            // y = memoryArray;
            // Below this line is not viable,因为这会“重置”指针,
            // But you can not make it to the appropriate storage location.
            // delete y;
    
            g(x); // 调用 g 函数,At the same time handed over to the right x 的引用
            h(x); // 调用 h 函数,同时在 memory Create a temporary copy of the independent
        }
    
        function g(uint[] storage ) internal pure {}
        function h(uint[] memory) public pure {}
    }
    

copyright notice
author[Zeke Luo],Please bring the original link to reprint, thank you.
https://en.netfreeman.com/2022/217/202208050446128265.html

Random recommended