http://www.7klian.com

如何利用值数组(Value Array)模式淘汰Solidity的高gas损耗问题

uint1a256值数组

假如我们提供一个回收1元素数组的函数,,则实际上有大概制止利用set()函数的返回值赋值。可是由于此技能利用更多的内存,代码和巨大性,因此否认了利用值数组的大概利益。

让我们看看上面的示例库代码的几个简朴测试:

函数返回后,用户中的数组元素将被变动。

在这里,您可以清楚地看到set()函数的返回值被分派回参数变量。假如缺少赋值,则变量将保持稳定,如require()所测试的那样。

首先,让我们利用Solidity在导入库文件中利用库的范例将函数添加到bytes32范例:

---------------------------------------------

这是这些在EVM存储空间中举办较量的方法:

MoreFixedValueArraysTypeTypeNameDescriptionuintX[Y]uintXaYX*Y<=256uint10[25]uint10a25twenty-five10bitelementvaluesuint7[36]uint7a36thirty-six7bitelementvaluesuint6[42]uint6a42forty-two6bitelementvaluesuint5[51]uint5a51fifty-one5bitelementvaluesuint4[64]uint4a64sixty-four4bitelementvaluesuint1[256]uint1a256two-hundred&fifty-six1bitelementvaluesetcetera

我发起利用如上所示的范例名,这在本文中城市用到,可是您大概会找到一个更好的定名约定。

更多牢靠值数组

import"uint8a32.sol";import"uint16a16.sol";contractMyContract{uintusers;//uint8a32uintroles;//uint16a16...functionsetUser(uintn,uintuser)private{//wantedtodothis:users=users.set(n,user);users=uint8a32.set(users,n,user);}functionsetRole(uintn,uintrole)private{//wantedtodothis:roles=roles.set(n,role);roles=uint16a16.set(roles,n,role);}...}

大概的牢靠值数组

Solidity库合约中不答允存储空间变量。

绝不奇怪,最大的气体耗损是为分包智能合约或库函数提供数组参数。

在这里,与利用uint8 [Y]对比,每个uint8a32 set()函数耗损的气体轮回少几百个。uint8 [32],uint8 [16]和uint8 [4]的耗气体量沟通,因为它们利用沟通数量的EVM存储空间(一个32字节的插槽)。

值数组

还必需鉴戒在正确的变量上利用正确的值数组范例。

牢靠值数组实现

值数组是以值范例生存的数组。这意味着只要在措施文本中碰着变量标记,就会利用该值。

让我们导入该库并测试它:

//uint8a32.sollibraryuint8a32{//providestheequivalentofuint8[32]uintconstantbits=8;uintconstantelements=32;//mustensurethatbits*elements<=256uintconstantrange=1<<bits;uintconstantmax=range-1;//getfunctionfunctionget(uintva,uintindex)internalpurereturns(uint){require(index<elements);return(va>>(bits*index))&max;}//setfunctionfunctionset(uintva,uintindex,uintev)internalpurereturns(uint){require(index<elements);require(value<range);index*=bits;return(va&~(max<<index))|(ev<<index);}}

牢靠值数组

在uint8/byte内存变量上获取和配置的耗气量

内存和存储字节上的get和set的Gas耗损32个变量

请留意,在函数返回之后,函数的users参数将保持稳定,因为它是通过值通报的-为了得到变动后的值,有须要将函数返回值分派给users变量。

librarybytes32lib{uintconstantbits=8;uintconstantelements=32;functionset(bytes32va,uintindex,byteev)internalpurereturns(bytes32){require(index<elements);index=(elements-1-index)*bits;returnbytes32((uint(va)&~(0x0FF<<index))|(uint(uint8(ev))<<index));}}

假如您发明牢靠值数组很有用,那么您还可以思量牢靠多值数组、动态值数组、值行列、值仓库等。

在Solidity呆板字范例256位(32字节)中,我们可以思量以下大概的值数组。

出格有趣的是uint12256值数组。这使得我们可以或许高效地将256个暗示布尔值的1位元素值高效地编码到1个EVM字中。对比之下,Solidity的bool[256]耗损了256倍的内存空间,甚至是8倍的存储空间。

是的,我们可以利用Value Array淘汰存储空间和睦体耗损。

区块链研究尝试室-区块链链下数据存储办理方案

让我们看看一个大概的实现.

实际上,数组凡是是引用范例。这意味着每当在措施文本中碰着变量标记时,城市利用指向数组的指针,不外也有一些破例环境会生成一个副本。在以下代码中,将10位8位uint用户的数组通报给函数setUser,该函数配置users数组中的一个元素:

这是沟通的代码,但数据范例已归并到变量名称中,以办理该问题:

EVM存储空间中的沟通较量:

结论

这个库提供了函数set(),它答允挪用者将bytes32变量中的任何字节配置为任何所需的字节值。按照您的需求,您大概但愿为您利用的其他bytesX范例生成雷同的库。

区块链研究尝试室|详解以太坊虚拟机(EVM)的数据存储机制

contractTestValueArray{functiontest()publicpure{uintusers;users=setUser(users,5,12345);require(users==...);}functionsetUser(uintusers,uintindex,uintev)publicpurereturns(uint){return...;}}

contractTestReferenceArray{functiontest()publicpure{uint8[10]memoryusers;setUser(users,5,123);require(users[5]==123);}functionsetUser(uint8[10]memoryusers,uintindex,uint8ev)publicpure{users[index]=ev;}}

甚至更多的牢靠值数组

FixedValueArraysTypeTypeNameDescriptionuint128[2]uint128a2two128bitelementvaluesuint64[4]uint64a4four64bitelementvaluesuint32[8]uint32a8eight32bitelementvaluesuint16[16]uint16a16sixteen16bitelementvaluesuint8[32]uint8a32thirty-two8bitelementvalues

气体耗损量

假如您的Solidity智能合约利用较小值的小数组(用于用户ID,脚色等),则利用“代价数组”大概会耗损更少的汽油。

我们较量了在EVM内存空间中利用牢靠uint8 []数组与uint8a32值数组的环境: 在uint8/byte内存变量上获取和配置的耗气量 令人惊奇的是。Solidity bytes32值数组 Solidity在bytesX(X=1..32)范例中提供了一个部门值数组。

bytes32值数组

Solidity支持内存中的数组,这些数组大概会挥霍空间阵列,而存储中的数组则会耗损大量的气体来分派和会见阵列。可是Solidity也运行在以太坊虚拟机(EVM)上,它有一个256bits(32字节)的很是大的呆板字。正是后一个特性使我们可以或许思量利用值数组(Value Array)。在字型较小的语言中,譬喻32位(4字节),值数组(Value Array)不太大概实用。

在这里,我们较量了在EVM内存空间中利用牢靠uint8 []数组与uint8a32值数组的环境:

我已经展现了其他大概性,譬喻牢靠多值数组,动态值数组,值行列,值仓库等。

Solidity bytes32值数组

Solidity在bytesX(X=1..32)范例中提供了一个部门值数组。这些存储字节可以利用数组式会见单独读取,譬喻:

我已经提供并丈量了用于写入Solidity bytes32变量的代码,以及用于uintX [Y]值数组的通用库代码。

uint8a32值数组

值数组与引用数组的较量

这些是与某些Solidity可用范例匹配的牢靠值数组:

在Datona Labs的Solidity智能数据会见合约(S-DAC)模板的开拓和测试进程中,我们常常需要利用较小值的小数组。在本文的示例中,我研究了利用值数组(Value Array)是否比引用数组更有效地做到这一点。

通过bool/1bit内存变量获取和配置的耗气体量

引用数组

其他大概性

EVM内存空间中牢靠bool[]数组与uint12256值数组的较量:

但不幸的是,在Solidity v0.7.1中,我们无法利用数组式会见写入单个字节:

下面是一个有用的导入文件,为值数组范例uint8a32提供get和set函数:

本文接头如何利用值数组(Value Array)

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

相关文章阅读