Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Solidity 优化 - 隐藏的 Gas 成本

Solidity 优化 - 隐藏的 Gas 成本

作者头像
Tiny熊
发布于 2023-01-09 09:46:18
发布于 2023-01-09 09:46:18
8320
举报

译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3]

图文来自:omniscia.io[4]

本文将研究以太坊虚拟机(EVM)的内部工作,以说明如何 "利用 "EVM 的特殊特性,为用户最小化 solidity 智能合约的执行成本。社区发布许多关于 solidity 开发者可以利用的知识来设计和开发更安全、更节省 Gas 的智能合约。

本周我们看一下两种不同类型的优化,这些优化相对简单,可以应用于任何代码库,与我们为客户审计的大多数智能合约有关。第一个优化适用于所有版本的 Solidity。本文讨论的第二个优化只对pragma版本0.8.0以上有效。然而,让我们首先在高层次上阐明如何评估任何 EVM 指令的成本。

评估 EVM 指令成本

最核心的是,在 EVM 区块链上为交易引入 "Gas 成本"和为组装区块引入 "Gas 限制 "的理由是:1)引入额外的收入流,以激励 stakers(以前的矿工)确保和验证网络,以及 2)作为保护措施,防止拒绝服务(DoS)攻击,通过 Gas 上限禁止执行计算昂贵的任务(例如,具有显著限制的 "for "循环,否则会延迟区块创建率的中位数)。

为了在区块构建者补偿和有竞争力的计算系统之间取得余额,EVM 区块链根据网络行为者之间的带宽需求动态地调整其区块 Gas 限制。交易 Gas 成本通常发展缓慢,围绕着一个简单的基础;执行交易的计算成本。在中心化和/或传统的计算环境中,这可能看起来很简单。然而,在区块链生态系统中,由于区块链账本的状态变化在验证去中心化网络上执行的指令的节点网络中传播的方式,它有很大不同。

在这篇文章中,我们说明了 "内存" 的隐性成本如何抬高了 EVM 区块链上其他直接交易类型的成本,以及开发者如何优化他们的 dapps 以减少其 Gas 足迹。

EVM 本地变量的隐藏成本

当声明一个作为语句结果的局部变量时,会产生一个隐藏的 Gas 成本,它与我们声明的局部变量所需的 内存量成比例。当从存储空间读取变量(SLOAD),将它们存储到局部变量(参考 MSTORE 内存扩展[5] 增加了隐藏成本),以及在每次利用时读取它们(MLOAD)时,这种额外成本通常会被抵消。

在处理 EVM 的原始指令时,情况就不是这样了。事实上,区块链上的每笔交易都包含一组不可避免的数据。因此,数据集通过原始的 EVM 指令暴露给所有智能合约,这些指令消耗的 Gas 非常小。这是由于它们不需要额外的内存来读取特殊的数据槽,因为它们已经作为 EVM 的区块创建工作流程的一部分在内存中加载。

这些指令集很重要,他们围绕着交易的上下文数据,如msg.senderblock.timestamp,等等。因此,下面的合约实现事实上是低效的。

Aave v3 的 "Context.sol"中的片段 @ f3e037b

Context 合约是 OpenZeppelin 引入的一个实现,目的是简化合约的开发过程,可以很容易地升级到元交易兼容的合约。然而,到目前为止,它大多被滥用,并导致各种协议(包括 Aave V2 和 Aave V3)的 Gas 增加到不可忽略的程度,这是 Aave V3 的 "IncentivizedERC20 "实现的具体例子:

来自 Aave v3 的 "IncentivizedERC20.sol "的片段 @ f3e037b

在上述函数中,gas 成本包含:_msgSender实现的 msg.sender Gas 成本(操作码 CALLER: 2 gas),以及_msgSender()调用本身(操作码 JUMP: 2gas以及返回变量的内存分配)两次。通过优化上述片段,我们可以将指令的 Gas 成本降低一半:

来自 Aave v3 的 "IncentivizedERC20.sol "的优化片段 @ f3e037b

虽然这种优化本身可能微不足道,但在整个代码库中应用时,它将带来切实的节省。

Solidity 数学上的隐藏成本

隐性 Gas 成本不仅限于 EVM。开发人员需要认识到,Solidity 语言本身在其最新版本semver 8中引入了一些隐性成本,Solidity 默认执行安全算术。鉴于很多应用程序已经对不安全的算术操作进行了安全检查,作为其错误处理工作流程的一部分,内置的安全算术检查变得多余了,因此会产生多余的 Gas 增加。

值得庆幸的是,Solidity 还引入了一种新的代码块声明风格,指示编译器不安全地执行算术操作。unchecked代码块。只要操作被周围的语句和/或条件保证安全执行,就可以巧妙地利用这些代码块来大大减少特定合约的 Gas 成本。作为一个例子,让我们看一下复合CToken实现的_reduceReservesFresh函数的这一段:

来自 Compound 的 "CToken.sol "的片段 @ a3214f6

在条件 reduceAmount > totalReserves 被评估为 false 之后,totalReservesNew 的计算和分配被执行。这意味着执行环境已经保证了 "totalReserves >= reduceAmount "这一特性,因此 "totalReservesNew "的计算可以在一个unchecked 的代码块中进行,因为它被保证能够正常执行。经过优化,上述代码块应该类似于这样:

来自 "CToken.sol "的 Compound @ a3214f6 的优化摘录

另一种避免内置安全算术产生额外 Gas 的方法是在增量操作(++--)期间使用unchecked。通常在for循环和任何0.8.X后的版本中进行操作都有此问题。每一次增量操作都会进行边界检查,当它们完全是多余的。下面提供一个非常简单的例子来说明这一点:

循环的例子片段

由于 Solidity 的固有限制,bar.length被保证适合于uint256变量,这意味着对i变量的每个循环执行安全增量将是多余的。为了优化这样的代码块,我们把增量移到 unchecked的代码块的末尾:

优化后的循环实例片段

结论

EVM 是一个内在复杂的机器,因此已经开发了多种工具来帮助开发者使用高级语言(如 Solidity)在其系统中创建解决方案。然而,在 Solidity 编译器的自由下进行的简化,通常没有很好地转达给开发者社区,因此,程序员最终创造了低效的程序。

欢迎订阅我们的专栏:全面掌握 Solidity 智能合约开发[6] 及 理解 EVM - 探究 Solidity 背后的秘密[7] 学习如何写出高效的合约代码。


本翻译由 Duet Protocol[8] 赞助支持。

原文链接:https://medium.com/@omniscia.io/the-optimizers-guide-to-solidity-pt-3-hidden-gas-costs-3132357440ac

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

翻译小组: https://learnblockchain.cn/people/412

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

omniscia.io: http://omniscia.io/

[5]

内存扩展: https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a0-1-memory-expansion

[6]

全面掌握Solidity智能合约开发: https://learnblockchain.cn/column/1

[7]

理解 EVM - 探究Solidity 背后的秘密: https://learnblockchain.cn/column/22

[8]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

Twitter : https://twitter.com/NUpchain Discord : https://discord.gg/pZxy3CU8mh

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Solidity 优化 - 控制 gas 成本
本系列我们探索和讨论在以太坊独特的 EVM 成本模型下编写高效的 Solidity 代码的数据结构和实现技术。读者应该已经对 Solidity 中的编码以及 EVM 的总体工作方式所有了解。
Tiny熊
2020/11/03
9480
Solidity 优化 - 控制 gas 成本
深入Solidity数据存储位置 - 存储
这是深入 Solidity 数据存储位置[4]系列的另一篇。在今天的文章中,我们将更详细地介绍 EVM 中的一个重要数据位置:存储(Storage)。
Tiny熊
2022/11/07
2.1K0
深入Solidity数据存储位置 - 存储
智能合约Gas 优化的几个技术
每次交易被发送到区块链上,必须支付 Gas 费用。消耗的 Gas 与交易所需的计算量有关,即:EVM 执行交易所需的计算量(如果交易不涉及 EVM,例如简单的以太币转账,Gas 的数量是固定的)。
Tiny熊
2022/11/07
1.4K0
智能合约Gas 优化的几个技术
Foundry教程|如何调试和部署Solidity智能合约
Foundry 是一个 Solidity 框架,用于构建、测试、模糊、调试和部署 Solidity 智能合约。在这个 Foundry 教程中,我们将介绍以下内容。
Tiny熊
2022/11/07
2.2K0
Foundry教程|如何调试和部署Solidity智能合约
深入理解EVM操作码,让你写出更好的智能合约
你的一些编程“好习惯”反而会让你写出低效的智能合约。对于普通编程语言而言,计算机做运算和改变程序的状态顶多只是费点电或者费点时间,但对于 EVM 兼容类的编程语言(例如 Solidity 和 Vyper),执行这些操作都是费钱 的!这些花费的形式是区块链的原生货币(如以太坊的 ETH,Avalanche 的 AVAX 等等...),想象成你是在用原生货币购买计算资源。
Tiny熊
2023/01/09
1.4K0
深入理解EVM操作码,让你写出更好的智能合约
Solidity优化 - 减少智能合约gas消耗的8种方法
我目前正在开发一个 Dapp 项目,该项目的第一个主要开发阶段已经接近尾声。由于交易成本始终是开发人员的大问题,因此,我想使用本文分享一些我的见解。分享我过去几周/几个月来在该领域获得的收获。
Tiny熊
2020/11/11
4K0
Solidity优化 - 减少智能合约gas消耗的8种方法
深入Solidity数据存储位置 - 内存
这是深入 Solidity 数据存储位置[6]系列的另一篇。在今天的文章中,我们将学习 EVM 内存的布局,它的保留空间,空闲内存指针,如何使用memory引用来读写内存,以及使用内存时的常规最佳做法。
Tiny熊
2022/11/07
1.9K0
深入Solidity数据存储位置 - 内存
深入Solidity数据存储位置
文章较长,内容很详细、很深入。但是不要吓到,坐下来,喝杯咖啡或你最喜欢的饮料,慢慢体会。
Tiny熊
2022/11/07
1.1K0
深入Solidity数据存储位置
在 Solidity中使用值数组以降低 gas 消耗
我们Datona Labs在开发和测试Solidity数据访问合约(S-DAC:Smart-Data-Access-Contract)模板过程中,经常需要使用只有很小数值的小数组(数组元素个数少)。在本示例中,研究了使用值数组(Value Array)是否比引用数组(Reference Array)更高效。
Tiny熊
2020/08/27
1.9K0
在 Solidity中使用值数组以降低 gas 消耗
部署Solidity智能合约到Solana
Solana是一个新的区块链,专注于性能。它支持像Ethereum那样的智能合约,他们称之为程序。你可以使用Rust开发[4]这些程序,但现在有一个新的项目,将Solidity编译为Solana程序。换句话说,你现在就可以把你用Solidity写的合约部署到Solana上了。
Tiny熊
2021/12/31
2.2K0
部署Solidity智能合约到Solana
通过调试理解EVM(#4):结束/中止执行的5种指令
在 EVM 中,总共有 5 种方式来结束智能合约的执行。我们将在这篇文章中详细研究它们。让我们现在就开始吧!
Tiny熊
2023/01/09
9860
通过调试理解EVM(#4):结束/中止执行的5种指令
如何调试EVM智能合约 #2 :部署智能合约
在第二部分(本文)中,我们将分析当你在区块链中部署一个智能合约时发生了什么,例如,在点击 remix 中的 "部署 "按钮时。
Tiny熊
2022/11/07
7680
如何调试EVM智能合约 #2 :部署智能合约
智能合约gas评估与优化方法小结
以太坊上存储256 bit数据大约消耗20k Gas、如此换算,仅1 GB存储资源要花费32,000ETH,大约要花费超过1亿美元。且不说当前身为贵族链Gas费很有可能继续水涨船高,放在早些年其Gas消耗也不是一笔小数目。因此,以太坊Gas优化是Dapp开发一直难绕的问题,也是Solidity开发者的必备技能。
davy the bot
2024/04/08
1K0
概述:通过Solidity进行闪电贷(Aave,Dy/Dx,Kollateral)
闪电贷是指借用资产的贷款,在交易结束前就已归还资金(和费用)。此类贷款使你仅需花费很少的费用(在撰写 Aave 时为 0.09%,在 Dy/Dx 中为 0%)即可无担保的使用资金。闪电贷可用于跨 DEX 的套利,Dy/Dx 等协议的头寸清算以及 CDP(Collateralized Debt Positions:抵押债仓)的迁移。
Tiny熊
2020/12/29
2K0
概述:通过Solidity进行闪电贷(Aave,Dy/Dx,Kollateral)
以太坊发展简史
一起来看看以太坊都经历了哪些升级或分叉, 他们都发生的时间在什么时间,加入了哪些特性。
Tiny熊
2019/06/24
2.1K0
解构 Solidity 合约 #3:函数包装器
号外,今天我们的登链社区网站做了一点小更新, 作者们可以关联自己的社交账号,关联后,在文章右侧的作者区域就可以看到点亮的小图标,让更多的小伙伴通过内容交朋友,也欢迎大家关注登链社区的账号。
Tiny熊
2023/01/09
7150
解构 Solidity 合约 #3:函数包装器
跟我学 Solidity :开发环境
Solidity[3]是用于开发以太坊智能合约的最受欢迎的语言之一,因此,作为一个想要成为区块链开发人员的人,我决定学习如何使用 Solidity 开发智能合约。
Tiny熊
2020/12/15
1.7K0
停止使用Solidity的transfer()
由于EIP 1884[4]已经在伊斯坦布尔硬分叉[5]实施,EIP 1884[6]增加了SLOAD操作的 Gas 成本,因此_破坏了一些现有的智能合约_[7]。
Tiny熊
2021/03/16
1.8K0
Solidity 智能合约开发 - 基础
去年读研的时候上的 HKU 的 <COMP7408 Distributed Ledger and Blockchain Technology>,课程中学习了以太坊智能合约的开发,做了一个简单的图书管理 ÐApp,然后毕业设计也选择了基于 Ethereum 做了一个音乐版权应用,详见 Uright - 区块链音乐版权管理ÐApp,对 Solidity 开发有一些基础了解。
pseudoyu
2023/04/11
8010
Solidity 智能合约开发 - 基础
[译]Gas 优化 - 如何优化存储
在Solidity[3](用于以太坊智能合约的编程语言)中,你拥有“内存(memory)”(想像计算机上的RAM)和“存储(storage)”(想像硬盘驱动器)。两者均以32字节的块为操作单位(一个字节大约是一个字母)。在Solidity 中,内存价格便宜(存储或更新值仅需要 3 gas)。存储很昂贵(存储新的值需要20,000 gas,更新值需要 5000 gas)。
Tiny熊
2020/10/23
9820
相关推荐
Solidity 优化 - 控制 gas 成本
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档