全面掌握Solidity智能合约开发

2024年09月25日更新 796 人订阅
原价: ¥ 46 限时优惠
专栏简介 跟我学 Solidity :开发环境 跟我学 Solidity:关于变量 跟我学 Solidity : 变量的存储 跟我学 Solidity :引用变量 跟我学 Solidity :函数 跟我学 Solidity :合约的创建和继承 跟我学 Solidity :工厂模式 用Web3.js构建第一个Dapp 跟我学Solidity:事件 Solidity 中 immutable (不可变量)与constant(常量) [译] Solidity 0.6.x更新:继承 解析 Solidity 0.6 新引入的 try/catch 特性 探究新的 Solidity 0.8 版本 探索以太坊合约委托调用(DelegateCall) 停止使用Solidity的transfer() 使用工厂提高智能合约安全性 Solidity 怎样写出最节省Gas的智能合约[译] Solidity 优化 - 编写 O(1) 复杂度的可迭代映射 Solidity 优化 - 控制 gas 成本 Solidity 优化 - 减少智能合约的 gas 消耗的8种方法 Solidity 优化 - 如何维护排序列表 Solidity 优化:打包变量优化 gas 使用 Solidity 瞬态存储操作码 在 Solidity中使用值数组以降低 gas 消耗 Gas 优化:Solidity 中的使用动态值数组 计算Solidity 函数的Gas 消耗 Solidity 技巧:如何减少字节码大小及节省 gas 一些简单的 Gas 优化基础 "Stack Too Deep(堆栈太深)" 解决方案 智能合约Gas 优化的几个技术 合约实践:避免区块Gas限制导致问题 如何缩减合约以规避合约大小限制 Solidity 类特性 无需gas代币和ERC20-Permit还任重而道远 智能合约实现白名单的3个机制 Solidity智能合约安全:防止重入攻击的4种方法 Solidity 十大常见安全问题 [译]更好Solidity合约调试工具: console.log 智能合约开发的最佳实践 - 强烈推荐 全面理解智能合约升级 Solidity可升级代理模式: 透明代理与UUPS代理 使用OpenZeppelin编写可升级的智能合约 实战:调整NFT智能合约,减少70%的铸币Gas成本 Solidity 优化 - 隐藏的 Gas 成本 Gas 技巧:Solidity 中利用位图大幅节省Gas费 Solidity Gas 优化 - 理解不同变量 Gas 差异 关于Solidity 事件,我希望早一点了解到这些 Solidity 编码规范推荐标准 深入了解 Solidity bytes OpenZeppelin Contracts 5.0 版本发布 Solidity Gas优化:高效的智能合约策略 智能合约安全的新最低测试标准:Fuzz / Invariant Test 智能合约的白名单技术 模糊测试利器 - Echidna 简介 智能合约设计模式:代理 离线授权 NFT EIP-4494:ERC721 -Permit

Gas 优化:Solidity 中的使用动态值数组

  • aisiji
  • 发布于 2021-12-08 22:39
  • 阅读 7605

在 Solidity 中,动态值数组是否比引用数组效率更高吗?

在 Solidity 中,动态值数组是否比引用数组效率更高吗?

Photo by Nick Kwan on Unsplash

背景

在 Datona 实验室的 Solidity 智能数据访问合约(S-DAC)模板的开发和测试过程中,我们经常需要处理一些像用户ID这样数据小但未知长度的数据。理想情况下,这些数据存储在一个小数值的动态值数组中。

在这篇文章的例子中,我们研究了在 Solidity 中使用动态值数组是否比引用数组或类似解决方案在处理这些小数值时更高效。

讨论

当我们有一个由已知的小数值的小数组(长度小)组成的数据时,我们可以在 Solidity 中使用一个数值数组(Value Arrays),在这篇文章中,我们提供并测量了 Solidity 数值数组。得出的结论是,在多数情况下使用数值数组都可以减少存储空间和gas消耗。

得出这个结论是因为Solidity在以太坊虚拟机(EVM)上运行时有 非常大的256位(32字节)机器字长。基于这个特点,再加上处理引用数组时的高gas消耗,让我们考虑使用数值数组。

既然我们可以为固定值数组操作提供自己的库,同样是否也适用于动态值数组呢?

让我们比较一下动态值数组与固定长度值数组以及 Solidity 自己的固定长度数组和动态数组。

我们也将比较两个结构体,一个结构体包含一个数组长度和一个固定数组,另一个结构体包含一个数值数组。

可能的动态值数组

在 Solidity 中,只有 storage 类型有动态数组。memory 类型的数组必须有固定长度,并且不允许使用push()来附加元素。

我们以 Solidity 库形式为动态值数组提供代码,我们能提供push()(和pop())同时用于 storagememory 数组。

动态值数组需要记录并操作数组的当前长度。在下面的代码中,我们将数组长度在存储在256位(32字节)机器码值的最高位。

动态值数组

下面是一些与 Solidity 可用类型匹配的动态值数组:

Dynamic Value Arrays(动态值数组)

Type           Type Name   Description

uint128[](1)   uint128d1   one 128bit element value
uint64[](3)    uint64d3    three 64bit element values
uint32[](7)    uint32d7    seven 32bit element values
uint16[](15)   uint16d15   fifteen 16bit element values
uint8[](31)    uint8d31    thirty-one 8bit element values

上述我提出的类型名称,它们在会本文中使用,但你可能会有一个更好的命名方式。

下面我们将详细地研究uint8d31

更多动态值数组

很明显,有更多可能的数值数组。假设我们保留最高位的256位来存最大的动态数组长度,X(位数的值)乘以Y(元素个数)必须小于或者等于256减去容纳数组长度的位数(L):

More Dynamic Value Arrays

Type           Type Name  Len  Description

uintX[](Y)     uintXdY     L   X * Y <= 256 - L
uint255[](1)   uint255d1   1   one 248bit element value
uint126[](2)   uint126a2   2   two 124bit element values
uint84[](3)    uint84d3    2   three 82bit element values
uint63[](4)    uint63d4    3   four 62bit element values
uint50[](5)    uint50d5    3   five 51bit element values
uint42[](6)    uint42d6    3   six 42bit element values
uint36[](7)    uint36d7    3   seven 36bit element values
uint31[](8)    uint31d8    4   eight 31bit element values
uint28[](9)    uint28d9    4   nine 28bit element values
uint25[](10)   uint25d10   4   ten 25bit element values
uint22[](11)   uint22d11   4   eleven 22bit element values
uint21[](12)   uint21d12   4   twelve 21bit element values
uint19[](13)   uint19d13   4   thirteen 19bit element values
uint18[](14)   uint18d14   4   fourteen 18bit element values
uint16[](15)   uint16d15   4   as above
uint15[](16)   uint15d16   5   sixteen 15bit element values
uint14[](17)   uint14d17   5   seventeen 14bit element values
uint13[](19)   uint13d19   5   nineteen 13bit element values
uint12[](20)   uint12d20   5   twenty 12bit element values
uint11[](22)   uint11d22   5   twenty-two 11bit element values
uint10[](25)   uint10d25   5   twenty-five 10bit element values
uint9[](27)    uint9d27    5   twenty-seven 9bit element values
uint8[](31)    uint8d31    5   as above
uint7[](35)    uint7d35    6   thirty-five 7bit element values
uint6[](41)    uint6d41    6   forty-one 6bit element values
uint5[](50)    uint5d50    6   fifty 5bit element values
uint4[](62)    uint4d62    6   sixty-two 4bit element values
uint3[](83)    uint3d83    7   eighty-three 3bit element values
uint2[](124)   uint2d124   7   one-hundred & twenty-four 2bit EVs
uint1[](248)   uint1d248   8   two-hundred & forty-eight 1bit EVs

不同的项目需要特定的数组类型,并且同一个项目可能需要多种数组类型。例如,uint8d31用于用户ID,uint5d50用于用户角色。

注意uint1d248数值数组。它让我们可以有效地将多达248个1位的元素(代表布尔值)编码到1个 EVM 字中。而Solidity相同作用的 bool[248] ,在内存中消耗多 248 倍的空间,在存储(storage)中则多8倍。

动态值数组实现

下面是一个可导入库文件,为动态值数组类型uint8d31提供了getset函数:


// uint8d31.sol
library uint8d31 { // provides the equ...

剩余50%的内容订阅专栏后可查看

点赞 1
收藏 3
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论