在北京时间4月15日下午18:00左右(具体是以太坊网络区块高度达到#12244000时),以太坊的柏林(Berlin)硬分叉晋级将会产生,这次晋级将归入4个新的EIP改善提案,而其中两个(EIP-2929和EIP-2930)将会影响买卖的gas本钱计算。

本文解说了在这次硬分叉晋级前后的gas本钱计算,这将怎么随EIP-2929而产生改变,以及怎么运用EIP-2930引进的拜访列表功能,原文作者是Nomic Labs软件开发者Franco Victorio。

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

注:文章篇幅较长,以下是其中的一些要点:

柏林硬分叉改变了一些opcode操作码的gas本钱。假如你在dapp或智能合约中有一个硬编码的gas值,它们或许会停止工作。假如产生这种状况,并且智能合约是不行晋级的,则用户将需要运用拜访列表(EIP-2930)来启用它。

拜访列表可用于稍稍下降gas本钱,但在某些状况下,它们实际上会添加gas耗费总量。

geth包括了一个新的RPC办法(eth\u createAccessList)来简化拜访列表的创立。

1

柏林硬分叉前的gas本钱

EVM履行的每个opcode操作码都有一个相关的gas本钱。关于大多数操作码而言,这个本钱是固定的:PUSH1总是耗费3个单位的gas,MUL则耗费5个单位的gas,等等。而关于其他操作码来说,它是可变的:例如,SHA3操作码的本钱取决于其输入的大小。

咱们将要点评论SLOAD和SSTORE操作码,因为它们是受柏林硬分叉影响最大的操作码。咱们稍后将评论那些以地址为目标的操作码,就像一切的 EXT*和CALL*操作码,因为它们的gas本钱也会产生变化。

柏林硬分叉之前的SLOAD

假如没有EIP-2929,SLOAD的本钱很简单:它总是会耗费800 gas。柏林硬分叉之前的SSTORE

就gas而言,SSTORE或许是最复杂的操作码,因为它的本钱取决于存储slot的当前值、新值以及它是否曾经被修改过。咱们将只剖析一些场景以取得基本的理解。假如你想了解更多,请阅读本文结尾链接的eip。

假如slot的的值从0更改为1(或任何非零值),则本钱为20000;

假如slot的的值从1更改为2(或任何其他非零值),则本钱为5000;

假如slot的的值从1(或任何非零值)更改为0,则本钱也为5000,但在买卖结束时你将取得gas退款。这篇文章中,咱们不会具体评论退款,因为它们不受柏林硬分叉的影响;

假如曾经在同一业务中修改了该值,则一切后续sstore的本钱为800;

这儿的细节有些枯燥,重要的一点是,SSTORE是非常昂贵的,其本钱取决于几个要素。

2

实施EIP-2929之后的gas本钱

EIP-2929改变了一切这些值,但在此之前,咱们需要先谈谈这个EIP引进的一个重要概念:已拜访地址和已拜访存储密钥。

假如地址或存储密钥曾经在买卖期间被“运用”,则该地址或存储密钥就被视为已拜访。例如,当你调用另一个合约时,该合约的地址会被标记为已拜访。类似地,当你SLOAD或SSTORE某些slot时,它将被视为在买卖的其余部分已被拜访。不管是哪个操作码做的:假如一个SLOAD读取了一个slot,那么它将被认为对接下来的SLOAD以及SSTORE都是已拜访的。

这儿需要留意的一点是,存储密钥位于某个地址的“内部”。正如EIP所解说的:

“履行业务时,保护一组accessed_addresses: Set[Address] 和 accessed_storage_keys: Set[Tuple[Address, Bytes32]]”

也便是说,当咱们说一个存储slot被拜访时,咱们实际上是说一对(address, storageKey)被拜访了。

话虽如此,咱们还是来谈谈新的gas本钱吧。

柏林硬分叉之后的SLOAD

在柏林硬分叉之前,SLOAD的固定本钱是800 gas,现在,这取决于是否已拜访了存储slot。假如未拜访,则本钱为2100 gas,假如已拜访,则本钱为100 gas。因而,假如slot在已拜访的存储密钥列表中,则一次SLOAD的本钱会下降2000 gas。

柏林硬分叉之后的SSTORE

让咱们在布置EIP-2929的环境下回顾一下之前的SSTORE示例:

假如slot的值从0更改为1(或任何非零值),则本钱为:22100(假如未拜访存储密钥),20000(假如已拜访存储密钥);

假如slot的值从1更改为2(或任何其他非零值),则本钱为:5000(假如未拜访存储密钥),2900(假如已拜访存储密钥);

假如slot的值从1(或任何非零值)更改为0,则本钱与上一项相同,然后加上退款;

假如曾经在同一买卖中修改了该值,则一切后续SSTORE的本钱为100;

如你所见,假如要修改的slot曾经被拜访过,那么第一次SSTORE的本钱将下降2100 gas。

下面的表总结了目前为止一切改变的值:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

请留意,在最终一行中,议论是否拜访了slot是没有意义的,因为假如它曾经被写入过,则标明其也被拜访过。

3

EIP-2930

咱们在文章开头提到的另一个EIP便是EIP-2930,这个改善提案添加了一种新类型的业务,该业务能够在业务负载中包括拜访列表。这意味着你能够在业务开端履行之前预先声明哪些地址和slot应被视为是已拜访的。例如,一个未拜访slot的SLOAD本钱为2100,可是假如该slot包括在业务的拜访列表中,则相同的操作码本钱就为100。

可是,假如当地址或存储密钥已被拜访时,gas本钱改变低了,这是否意味着咱们能够将一切内容添加到业务的拜访列表中并下降gas本钱呢?不完全是这样,因为你还需要为添加的每个地址和每个存储密钥付出gas。

让咱们看一个例子,假定咱们正在向合约A发送一笔买卖,拜访列表或许如下所示:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

假如咱们用这个拜访列表发送了一笔买卖,并且第一个运用0x0 slot的操作码是SLOAD,则它将花费100 gas(而不是2100 gas),这就下降了2000 gas的耗费量。但业务拜访列表中包括的每个存储密钥的本钱为1900 gas,所以咱们只省了100 gas。(假如拜访该slot的第一个操作码是SSTORE,那么咱们将节约2100 gas,这意味着假如考虑到存储密钥的本钱,咱们总共将节约200 gas。)

这是否意味着咱们在运用带有拜访列表的买卖时总是能节约gas耗费?并非如此,因为咱们还要为拜访列表中的地址付出gas本钱(在咱们的示例中是"<address of A>")

已拜访地址

以上,咱们只评论了SLOAD和SSTORE操作码,但这些并不是柏林硬分叉之后仅有改变的操作码。例如,原先调用操作码的固定本钱为700 gas。可是在实施EIP-2929之后,假如地址不在拜访列表中,则开销便是2600 gas,但假如是在已拜访列表中,则开销便是100 gas。并且,与已拜访存储密钥相同,之前拜访该地址的操作码并不重要(例如,假如先调用EXTCODESIZE,则该操作码将花费2600 gas,运用相同地址的任何后续EXTCODESIZE、CALL、STATICCALL将花费100 gas)。

这是怎么受到拜访列表买卖的影响的?例如,假如咱们将一笔买卖发送至合约A,而该合约调用另一个合约B,那么咱们能够包括如下拜访列表:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

咱们有必要付出2400 gas的费用才干将这个拜访列表包括在买卖中,可是第一个运用B地址的操作码将花费100 gas(而不是2600gas)。所以咱们这样做就节约了100 gas,假如B以某种办法运用它的存储,并且咱们知道它将运用哪些密钥,那么咱们还能够将它们包括在拜访列表中,并为每个密钥节约100/200的gas(取决于第一个操作码是SLOAD还是SSTORE)。

但咱们为什么要谈另一个合约呢?咱们调用的合约怎么了?咱们为什么不这样做?

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

咱们能够这样做,但这是不值得的,因为EIP-2929指定了被调用的合约地址(即tx.to)总是包括在accessed_addresses列表中,因而这只会白白浪费2400 gas。

让咱们再次剖析上一节的示例:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

这实际上是浪费,除非咱们包括多个存储密钥。假如咱们假定一个SLOAD总是首先运用一个存储密钥,那么咱们至少需要24个存储密钥才干完成收支平衡。

明显,剖析并创立这样的一个拜访列表是没有意义的。走运的是,咱们有更好的办法。

4

eth_createAccessList RPC办法

Geth(从1.10.2版别开端)包括了一个新的eth\u createAccessList RPC办法,其能够用来生成拜访列表。它的用法类似于eth_estimateGas,但它不是用于估算gas,而是回来如下内容:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

也便是说,它为你供给了该买卖将运用的地址和存储密钥的列表,以及假如包括拜访列表,则会耗费的gas。(并且,与eth_estimateGas相同,这是一种估计值,在实际进行买卖时,列表或许会更改。)

我想,随着时间的推移,咱们会发现履行此操作的正确办法是什么,而我的伪代码猜测是:

以太坊今日将完成柏林硬分叉升级,这些知识点你需要了解

5

激活合约

有必要要指出的是,拜访列表的主要意图不是运用gas,正如EIP所解说的:

“EIP-2929所引进的是减轻合约损坏危险,因为买卖可预先指定和付出买卖方案拜访的帐户和存储slot。因而,在实际履行中,SLOAD和EXT*操作码只需要100 gas,这现已足够低了,它不仅可防止因该EIP而导致的损坏,还能够“激活”因为EIP 1884而卡住的任何合约。”

这意味着,假如一个合约对履行某些操作的本钱做出假定,那么gas本钱的添加或许会导致它无法工作。例如,一个合约调用另一个合约(例如someOtherContract.someFunctionhttps://bicoin8.com/wp-content/uploads/2023/04/202304211cHpE0.jpggas: 34500}())因为它假定某个函数正好运用34500 gas,那么它就会中断,但假如在业务中包括适当的拜访列表,那么合约将再次工作。

假如你想自己测试这些EIP,你能够仿制这个repo,它有几个可运用Hardhat和geth履行的示例。有关阐明,请查看README文件。

相关材料:

1、EIP-2929‌和EIP-2930‌

2、EIP-2930依赖于柏林硬分叉的另一组成部分:EIP-2718‌;

3、EIP-2929引用了大量EIP-2200‌的内容,所以假如你想更深化地了解gas本钱,你应该从EIP-2200开端;

4、有关比较gas运用量变化的更复杂示例‌;

视野开拓

阶级斗争的状态是确定劳动力价值的因素之一。劳动力可以通过阶级斗争来提高工资和改善生活条件。相反,有组织的资产阶级反击可能会降低劳动力的价值。-《马克思与《资本论》》

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注