今日实时汇率

1 美元(USD)=

7.3042 人民币(CNY)

反向汇率:1 CNY = 0.1369 USD   更新时间:2025-04-20 08:02:31

原文标题:《柏林分叉对 Gas 影响几何?》

撰文:Franco Victorio

翻译:ETH 中文站

柏林硬分叉已于 4 月 14 日在主网上线,引入了四份 EIP 。其中的两份 (EIP-2929 和 EIP-2930) 对交易的 gas 成本有影响。本文将解释部分 gas 成本在柏林前是如何计算的,加入了 EIP-2929 后会如何变化,以及如何使用 EIP-2930 引入的访问列表。

要点速览

柏林硬分叉改变一些操作码的 gas 成本。如果在一个 dapp 或一个智能合约里 gas 费的值是硬编码的,它们可能会中止运行。如果这种情况发生了,且智能合约是不可更新的,消费者将需要用 EIP-2930 的访问列表才能使用那部分的操作码。 访问列表可以用作减少少量的 gas 成本,但实际上它们在一些情况下是会增加总 gas 消耗量的。 geth 增加了一个叫 eth_createAccessList 的新 RPC 方法,用以简化访问列表的创建。

柏林硬分叉前的 gas 成本

EVM 执行的每个操作码都有一笔相关的 gas 成本。它们大多数的成本是固定的:PUSH1 总是消耗 3 个单位的 gas,MUL 消耗 5 个,等等。其他一些是会变化的:比如 SHA3 的操作码成本依赖于它的输入大小。

我们主要讨论操作码 SLOADSSTORE,因为它们是最受柏林硬分叉影响的。我们以后会讨论针对地址的操作码,比如所有的 EXT*CALL* ,因为它们的 gas 成本也改变了。

柏林前 SLOAD 的 gas 成本

在没有 EIP-2929 之前,SLOAD 的 gas 消耗很简单:它总是消耗 800 gas。所以(目前)没有什么可说的。

柏林前 SSTORE 的 gas 成本

在 gas 消耗方面,SSTORE 可能是最复杂的操作码了,因为它的成本取决于像存储 slot 的当前值、新值、以及它是否之前被修改过。我们仅对一些情况进行分析以获得一个基本理解;如果你想了解更多,请阅读文末的 EIP 链接。

如果存储 slot 的值从 0 变成 1 (或任何非 0 的值),gas 消耗量是 20000。 如果存储 slot 的值从 1 变成 2 (或任何其他非 0 的值),gas 消耗量是 5000。 如果存储 slot 的值从 1 (或任何非 0 的值) 变成 0,gas 消耗量也是 5000,但在交易的最后你会获得 1 笔 gas 费返还。本文不会讨论 gas 费返还,因为它们在柏林硬分叉中不受影响。 如果存储 slot 的值在之前相同的交易中被修改了,往后所有 SSTORE 的 gas 消耗量都是 800。

这部分的细节并不有趣,重要的是 SSTORE 很贵,而它的消耗取决于几个因素。

EIP-2929 后的 gas 消耗

EIP-2929 对上述所有操作码的 gas 消耗都有影响。但在深入这些变化前,我们需要先谈谈这份 EIP 引入的一个重要概念:访问过的地址 (accessed addresses) 与访问过的存储密钥 (accessed storage keys)。

如果一个地址或一个存储密钥在之前的交易中被「使用」过,那么它们就会被视为「访问过的」。例如,当你 CALL(调用)一个其他合约,该合约的地址就会被标为「 accessed (访问过的)」。同样地,当你 SLOAD(加载)或 SSTORE(存储)一些 slot 的时候,交易的其他部分也会被视为访问过的。哪个操作码执行它并不重要:如果一个 SLOAD 读取了一个 slot,接下来的 SLOADSSTORE 都会被视为访问过的。

这里值得注意的是,存储密钥是「内置于」一些地址的。就如这份 EIP 所解释:

「在执行交易时,维持一组 accessed_addresses: Set[Address]accessed_storage_keys: Set[Tuple[Address, Bytes32]]

也就是说,当我们说一个存储 slot 被访问了,我们实际上说的一对 (address, storageKey) 被访问了。

接下来谈谈新的 gas 消耗。

柏林后的 SLOAD

在柏林硬分叉之前,SLOAD 固定消耗 800 gas。现在,它取决于该存储 slot 是否被访问过。如果它没有被访问过,gas 消耗是 2100;如果被访问过了,则是 100。因此,如果该 slot 是在访问过的存储密钥列表里的,SLOAD 的 gas 消耗会少于 2000。

柏林后的 SSTORE

让我们在 EIP-2929 语境下重温前面的 SSTORE 例子:

如果存储 slot 的值从 0 变成 1 (或任何非 0 的值),gas 消耗量是:

如果存储密钥没有被访问过,22100 如果被访问过了,20000

如果存储 slot 的值从 1 变成 2 (或任何其他非 0 的值),gas 消耗量是:

如果存储密钥没有被访问过,5000 如果被访问过了,2900

如果存储 slot 的值从 1 (或任何非 0 的值) 变成 0,gas 消耗与上一种情况一样,再加上返还。

如果存储 slot 的值在之前相同的交易中被修改了,往后所有 SSTORE 的 gas 消耗量都是 100。

如你所见,如果 SSTORE 正在修改的 slot 是之前被访问过的,第一个 SSTORE 消耗少于 2100 gas。

总结

下表对上述的值进行了比较: