智能合约变量储存机制详解
摘要: 智能合约在以太坊广泛运用,与之相关的变量存储机制需要我们进一步研究。
前言
在以太坊上,我们可以通过部署智能合约来实现我们需要的功能,合约代码中我们往往需要定义一些变量,这就涉及到了智能合约变量的存储机制。
对此,知道创宇区块链安全实验室 根据 Solidity 所有的变量命名类型对智能合约的存储机制进行了分析研究。
存储机制
每个在以太坊虚拟机(EVM)中运行的智能合约的状态都在链上永久地存储着。
这些值存储在一个巨大的数组中,数组的长度为 2^256,下标从零开始且每一个数组能够储存 32 字节( 256 个比特)长度的值。并且存储是稀疏的,并没有那么密集。
Solidity 的数据变量类型分为两类
-
值类型- value type -
引用类型- reference type
值类型
-
布尔型 (bool) 2bit (0/1)
-
整型 (int/uint ) 根据关键字的不同表示不同长度,int8 表示 8bits 有符号数
-
定长浮点型 (fixed/ufixed) Solidity 还没有完全支持定长浮点型。可以声明定长浮点型的变量,但不能给它们赋值或把它们赋值给其他变量 -
地址类型 (adress) 160bits -
地址类型成员变量 (balance,transfer....) -
balance uint 256 (256bits) transfer () -
uint256 (256bits) -
定长字节数组 (byte[1]/bytes[1]) 定义数组时定义长度
引用类型
-
不定长字节数组类型 (bytes[]/byte[],string,uint[]....) -
结构体 (struct) -
映射 (mapping)
简单分析
pragma solidity ^0.4.25;
优化存储原则:
如果下一个变量长度和上一个变量长度加起来不超过 256bits,它们就会存储在同一个插槽里。
-
各个类型的存储长度 -
存储顺序从后往前 -
存储优化原则 -
byte.length==bytes1.length==8bits
数组类型
定长数组
变长数组
}
We1c0me_t0_th3_w0_
rd1d_o7_bl0ck6hain
字符串类型
pragma solidity ^0.4.25;
contract TEST{
pragma solidity ^0.4.25;
contract TEST{
pragma solidity ^0.4.25;
contract TEST{
pragma solidity ^0.4.25;
结构体类型
pragma solidity ^0.4.25;
-
a,b slot0
-
c slot1
-
d slot2
如果 d 超出了 32 字节,那么此时x=x=keccak_256(2)
pragma solidity ^0.4.25;
映射类型
pragma solidity ^0.4.25;
计算的规则是这样的,x=keccak_256(key+slot)
-
key 表映射类型的关键字 -
slot 代表定义映射类型变量对应的插槽
pragma solidity ^0.4.25;
综合练习
pragma solidity >0.5.0;
uint256[] public array = [401,402,403,405,406];
string str="name value";
}
}
require(age>0 && age <100 ,"bad age");
uint64[3] memory logins;
assert(u.age>0);
}
function addOrder(address user,uint256 orderID) public{
UserInfo storage u = users[user];
assert(u.age>0);
u.orders.push(orderID);
}
function getLogins(address user) public view returns (uint64,uint64,uint64){
UserInfo storage u = users[user];
return (u.lastLogins[0],u.lastLogins[1],u.lastLogins[2]);
}
function getOrders(address user) public view returns (uint256[] memory){
UserInfo storage u = users[user];
return u.orders;
}
}
避免太过冗长,放个图
解题练习
-
address
:String - 要读取的地址 -
position
:Number - 存储中的索引编号 -
defaultBlock
:Number|String - 可选,使用该参数覆盖 web3.eth.defaultBlock 属性值 -
callback
:Function - 可选的回调函数, 其第一个参数为错误对象,第二个参数为结果。
题目一 --Vault
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Vault {
bool public locked;
bytes32 private password;
constructor(bytes32 _password) public {
locked = true;
password = _password;
}
function unlock(bytes32 _password) public {
if (password == _password) {
locked = false;
}
}
}
web3.eth.getStorageAt(contract.address, 1)
题目二 --Lock Box
-
读取私有变量
-
constructor 只在构造的时候执行一次
总结
本篇文章详细讲解了智能合约的优化存储原则,数组类型,字符串类型,结构体类型和映射类型的存储机制。同时提供了基于 python 的计算代码,用以验证机制分析的正确性。
当然,本文涉及的智能合约设计并不复杂,在实际开发过程中远比此复杂,需要经历一些分析,在能找到正确的存储位置。
最后,希望通过本文章可以帮助大家进一步的了解智能合约。
作者:创宇区块链安全实验室;来自链得得内容开放平台“得得号”,本文仅代表作者观点,不代表链得得官方立场凡“得得号”文章,原创性和内容的真实性由投稿人保证,如果稿件因抄袭、作假等行为导致的法律后果,由投稿人本人负责得得号平台发布文章,如有侵权、违规及其他不当言论内容,请广大读者监督,一经证实,平台会立即下线。如遇文章内容问题,请联系微信:chaindd123
评论(0)
Oh! no
您是否确认要删除该条评论吗?