博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
智能合约从入门到精通:Solidity语法之内存变量的布局和状态变量的存储模型...
阅读量:5993 次
发布时间:2019-06-20

本文共 2094 字,大约阅读时间需要 6 分钟。

简介:在前面我们已经讲过Solidity语言的一些语法内容,在矩阵元JUICE开放平台的JIDE开发时,一定要注意Layout in Memory和Layout of State Variables in Storage,即内存变量的布局和状态变量的存储模型。内存变量的布局(Layout in Memory)

Solidity预留了3个32字节大小的槽位:

  • 0-64:哈希方法的暂存空间(scratch space)

  • 64-96:当前已分配内存大小(也称空闲内存指针(free memory pointer))

暂存空间可在语句之间使用(如在内联编译时使用)

Solidity总是在空闲内存指针所在位置创建一个新对象,且对应的内存永远不会被释放(也许未来会改变这种做法)。

有一些在Solidity中的操作需要超过64字节的临时空间,这样就会超过预留的暂存空间。他们就将会分配到空闲内存指针所在的地方,但由于他们自身的特点,生命周期相对较短,且指针本身不能更新,内存也许会,也许不会被清零(zerod out)。因此,大家不应该认为空闲的内存一定已经是清零(zeroed out)的。

状态变量的存储模型(Layout of State Variables in Storage)

大小固定的变量(除了映射,变长数组以外的所有类型)在存储(storage)中是依次连续从位置0开始排列的。如果多个变量占用的大小少于32字节,会尽可能的打包到单个storage槽位里,具体规则如下:

  • 在storage槽中第一项是按低位对齐存储(lower-order aligned)(译者注:意味着是大端序了,因为是按书写顺序。)。

  • 基本类型存储时仅占用其实际需要的字节。

  • 如果基本类型不能放入某个槽位余下的空间,它将被放入下一个槽位。

  • 结构体和数组总是使用一个全新的槽位,并占用整个槽(但在结构体内或数组内的每个项仍遵从上述规则)

优化建议

当使用的元素占用少于32字节,你的合约的gas使用也许更高。这是因为EVM每次操作32字节。因此,如果元素比这小,EVM需要更多操作来从32字节减少到需要的大小。 因为编译器会将多个元素打包到一个storage槽位,这样就可以将多次读或写组合进一次操作中,只有在这时,通过缩减变量大小来优化存储结构才有意义。当操作函数参数和memory的变量时,因为编译器不会这样优化,所以没有上述的意义。

最后,为了方便EVM进行优化,尝试有意识排序storage的变量和结构体的成员,从而让他们能打包得更紧密。比如,按这样的顺序定义,uint128, uint128, uint256,而不是uint128, uint256, uint128。因为后一种会占用三个槽位。

非固定大小

结构体和数组里的元素按它们给定的顺序存储。

由于它们不可预知的大小。映射和变长数组类型,使用Keccak-256哈希运算来找真正数据存储的起始位置。这些起始位置往往是完整的堆栈槽。

映射和动态数组根据上述规则在位置p占用一个未满的槽位(对映射里嵌套映射,数组中嵌套数组的情况则递归应用上述规则)。对一个动态数组,位置p这个槽位存储数组的元素个数(字节数组和字符串例外,见下文)。而对于映射,这个槽位没有填充任何数据(但这是必要的,因为两个挨着的映射将会得到不同的哈希值)。数组的原始数据位置是keccak256(p);而映射类型的某个键k,它的数据存储位置则是keccak256(k . p),其中的.表示连接符号。如果定位到的值以是一个非基本类型,则继续运用上述规则,是基于keccak256(k . p)的新的偏移offset。

bytes和string占用的字节大小如果足够小,会把其自身长度和原始数据存在当前的槽位。具体来说,如果数据最多31位长,高位存数据(左对齐),低位存储长度lenght * 2。如果再长一点,主槽位就只存lenght * 2 + 1。原始数据按普通规则存储在keccak256(slot)

所以对于接下来的代码片段:

pragma solidity ^0.4.4;contract C {    struct s { uint a; uint b; }    uint x;    mapping(uint => mapping(uint => s)) data;}复制代码

按上面的代码来看,结构体从位置0开始,这里定义了一个结构体,但并没有对应的结构体变量,故不占用空间。uint x实际是uint256,单个占32字节,占用槽位0,所以映射data将从槽位1开始。 data[4][9].b的位置在keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1 有人在这里尝试直接读取区块链的存储值,https://github.com/ethereum/solidity/issues/1550

参考内容:https://open.juzix.net/doc

智能合约开发教程视频:

转载地址:http://hfalx.baihongyu.com/

你可能感兴趣的文章
【论文:麦克风阵列增强】Signal Enhancement Using Beamforming and Nonstationarity with Applications to Speech...
查看>>
用3个步骤实现响应式网页设计
查看>>
python - requests从excel中获取测试用例数据
查看>>
CF821E 【Okabe and El Psy Kongroo】
查看>>
CC2640R2F&TI-RTOS 拿到 TI CC2640R2F 开发板 第四件事就是 修改第三件事信号量超时改为 事件 超时,并增加 事件控制 ,用于控制LED 闪烁时间或者关闭...
查看>>
数组去重的方法
查看>>
20155229实验二 《Java面向对象程序设计》实验报告
查看>>
单循环链表
查看>>
个人代码库の自定义后缀名
查看>>
数据结构和算法
查看>>
2018 年力扣高频算法面试题汇总-难题记录-鸡蛋掉落
查看>>
RAC5——11gR2以后GI进程的变化
查看>>
C# 由UTF-8 BOM头引发的两个问题(C#去BOM头)
查看>>
mysql 日期函数总结
查看>>
webservice 发布到外网的时候
查看>>
菜鸟修炼C语言小设计之——通讯录(二)
查看>>
Linux 常用命令
查看>>
openstack grizzly版cloud控制节点安装
查看>>
Spring事务管理4-----声明式事务管理(2)
查看>>
开发要注意的事项
查看>>