以太坊奖励你清空存储

本文介绍了以太坊EVM中gas refund的机制,重点讲解了伦敦分叉前后,由于清空链上存储而返还gas的规则变化。伦敦分叉前,将变量设置为默认值可获得15000 gas的退款,但退款上限为交易消耗gas的一半。伦敦分叉后,退款额降至4800 gas,上限为gas消耗的五分之一。文章还探讨了降低gas退款的原因,包括GasToken的出现和区块大小差异的增加。

你知道 EVM 会奖励用户 gas 退款,以补偿清除合约数据占用的链上存储吗?

伦敦分叉后有一些变化。但为了更好地理解它,我们将看看伦敦升级之前的场景,然后我们将看到伦敦升级中提出的变化。

在开始讨论退款之前,我们应该对存储 gas 消耗有一些了解,这将使你更容易理解 gas 的计算。

存储的 Gas 成本

我直接从以太坊黄皮书中复制了一些 gas 数量,让我们看看它们是什么。

1. Gcoldsload2100 - 首次访问冷存储的成本。

2. Gsset20000 - 当存储值从零设置为非零时,SSTORE 操作的支付费用。

3. Gsreset2900 - 当存储值的零值保持不变或设置为零时,SSTORE 操作的支付费用。

4. Rsclear15000 - 当存储值从非零设置为零时,给予的退款(添加到退款计数器中)。

解释:

1. Gcoldsload — 每次你在函数中首次访问任何存储变量时都必须支付费用,第二次或连续访问时费用为 100 gas.

2. Gsset — 每次你将任何变量从零值设置为非零值(布尔类型的情况下从 false 设置为 true)时都需要支付费用。简单来说,你正在更改默认值,节点现在必须跟踪该插槽。

3. Gsreset — 每次你将非零值设置为非零值或零值时都需要支付费用。

4. Rsclear — 无论何时你将任何值设置为其默认值,你都会获得退款。

在我们开始之前,请记住以下几点

  • 无论何时我们将任何值从非零设置为非零或从非零设置为零,我们统称消耗的 gas 为 5000,即加上 GcoldsloadGsreset。
  • 每个交易在执行时都会消耗所有相关的 gas,并且退款是在交易结束时计算的。
  • 每个交易都有一个初始 gas,为 21000。这个 gas 由验证者消耗,以确保交易有效。每个交易都会加上 21000,这是我们无法控制的,因此每个交易都会消耗 21000 + 函数数据所需的 gas。
  • 以下的 gas 计算将隐式地包括 21000 gas。

每当你将某些内容设置为其默认值时,退款就会生效,对于 uint 来说是零,对于布尔值来说是 false 等。为了便于理解,我将以 uint 为例。

伦敦分叉之前

在两种情况下,EVM 会将 gas 退还给用户。首先,如果你调用 selfdestruct 函数,则会从总消耗的 gas 中退还 24000 gas。这很简单,没有什么好说的,因为 selfdestruct 的 gas 退款功能已在 EIP-3529 中删除,并且最近 selfdestruct 方法也被弃用了。

其次,如果你将任何变量设置为其默认值,你将获得 15000 的退款。为什么会这样?将值设置为默认值意味着你正在清除存储,节点不需要跟踪你刚刚清除的特定存储槽。

这是以太坊黄皮书的截图,说明了退款金额。

但是有一种正确的方法来计算和退还 gas。

这是以太坊黄皮书中的参考。

机制: 退款在任何交易结束时给出,并且有最大数量的上限。最大数量是总使用 gas 的一半。

让我们通过 uint 的例子来理解它。当我们把任何非零的 uint 值设置为零时会发生什么?

假设你在一个交易中将一个 uint 变量设置为零,因此总的适用退款将是 15000,但是此交易中消耗的总 gas 是 24000,其中一半是 12000,现在 12000 成为可以退还的最大 gas 量,这意味着交易现在将花费你

24000 — MAXIMUM_GAS_REFUNDABLE = 24000–12000 = 12000 gas。

虽然我们期望获得 15000 gas 的退款,但上限被限制在 12000,因此将金额减少到 12000。如果我们的交易消耗 40000 gas 呢?在这种情况下,40000 的一半是 20000,大于 15000,因此我们将获得 15000 gas 的退款。

这是你仅将一个 uint 变量设置为零的情况,如果我们将多个 uint 变量设置为零会发生什么?例如

contract {

      uint256 count = 1;
      uint256 count2 = 2;
      uint256 count3 = 3;
      uint256 count4 = 3;
      uint256 count5 = 3;
      uint256 count6 = 5;
      uint256 count7 = 6;
      uint256 count8 = 6;

  function setTOzero() external {
     count = 0;
     count2 = 0;
     count3 = 0;
     count4 = 0;
     count5 = 0;
     count6 = 0;
     count7 = 0;
     count8 = 0;
 }

}
//Transaction cost will be 21000+ execution cost //交易成本将是 21000+ 执行成本
//execution cost = 8 * (Gcoldsload +Gsreset) = 8 * 5000 = 40000 //执行成本 = 8 * (Gcoldsload +Gsreset) = 8 * 5000 = 40000
// Transaction cost = 21000 + 40000 = 61000 // 交易成本 = 21000 + 40000 = 61000

无论你的交易成本是多少,都是 EXECUTION_COST+ 21000。现在,退款是根据你设置为默认值的变量数量计算的。在这种情况下,我们将 8 个 uint 变量设置为零,因此可退款金额计数为 15000 * 8 = 1,20,000

等等,如果这是退款金额,那么我们的交易消耗了多少 gas?当你计算要消耗的 gas 时,你将获得大约 61000 的金额。现在,如果在 61000 的交易中退还 1,20,000 gas 会发生什么?矿工最终将为交易付费,这就是引入上限机制的原因。

根据公式,要退还的最大 gas 将是 61000/2 = 30500。因此,消耗的 gas 将是 61000–30500 =30500 而不是 61000 – 1,20,000。现在我认为这对你来说很清楚了,但是在伦敦升级之后,此方法不再有效。如果你想测试这一点,那么你可以在 Remix IDE 中切换到 VM 的 Berlin 版本,并观察一切正常运行。

Gas 退款:伦敦分叉后

在伦敦升级中引入 EIP-3529 之后,这些数字发生了变化。

退款 gas 数量现在减少到 4800,并且可以退还的最大金额是消耗 gas 的五分之一。让我们理解与之前相同的示例。

在第一种情况下,如果我们仅将一个变量设置为零,则交易将消耗 26000。当我们注意到 EIP-3529 中的最大 gas 规则时,它说 TOTAL_GAS_CONSUMED 除以 5,在我们的例子中是 26000/5 等于 5200,这意味着我们有资格在此交易中获得的最大退款为 5200,但是正如 EIP-3529 中提到的,退款金额为 4800。这次,我们将 4800 退还给我们,并且该交易花费 21400 gas(一些额外的 gas)。

让我们来看第二种情况,我们将 8 个变量设置为零。消耗的 gas 仍然是 61000。谈到退款,我们希望总退款为 4800 * 8 =38400,这意味着我们期望的消耗是

61000–38400 = 22600。但是,当你执行此交易时,你将注意到消耗的 gas 为 49000,现在你明白了,要退还的 gas 上限为 61000/5 = 12200,这意味着该交易总共将消耗 61000–12200 ~ 49000

降低 Gas 退款的原因

你可能想知道是什么导致了伦敦升级中 gas 退款的降低。看看我从官方 EIP 网站复制的原因:

最初引入 SSTORESELFDESTRUCT 的 Gas 退款是为了激励应用程序开发人员编写实践“良好状态卫生”的应用程序,清除不再需要的存储槽和合约。但是,这种技术的好处已被证明远低于预期,并且 gas 退款产生了多个意想不到的有害后果:

  • 退款导致了 GasToken 的出现。GasToken 在将 gas 空间从低费用时期转移到高费用时期方面具有优势,但它也对网络产生了不利影响,尤其是在加剧状态大小方面(因为状态槽被有效地用作“电池”来节省 gas)并且效率低下地阻塞了区块链 gas 的使用
  • 退款增加了区块大小的差异。一个区块中实际消耗的 gas 的理论最大量几乎是纸面上 gas 限制的两倍(因为退款为区块中的后续交易增加了 gas 空间,尽管退款上限为交易使用的 gas 的 50%)。这不是致命的,但仍然是不希望的,尤其是在退款可以用于维持 2 倍的使用高峰远长于 EIP-1559 的情况下。

现在,你必须清楚 gas 退款的概念。你在 Remix 上对此进行更多操作,你将更多地了解计算。为什么不尝试执行一些真实的函数?因为我上面写的那些只是示例。你可以尝试查看真实合约中的 gas 消耗,例如当余额即将变为零时 ERC20 的转移函数。让我知道你通过这些实验发现了什么:)

  • 原文链接: decipherclub.com/clear-s...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
decipherclub
decipherclub
江湖只有他的大名,没有他的介绍。