Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-1087: SSTORE操作的网络 gas 计量

Authors Nick Johnson (@arachnid)
Created 2018-05-17
Discussion Link https://ethereum-magicians.org/t/eip-net-storage-gas-metering-for-the-evm/383

摘要

本 EIP 提议更改 EVM SSTORE 操作的 gas 收费方式,以减少在不必要的情况下过多的 gas 成本,并为合约存储启用新的用例。

动机

目前,SSTORE (0x55) 操作的收费方式如下:

  • 将插槽从 0 设置为非 0 时,收取 20,000 gas
  • 对于任何其他更改,收取 5,000 gas
  • 当插槽从非 0 设置为 0 时,退还 10,000 gas。退款在交易结束时申请。

在单个更新被应用到交易中的存储值的情况下,这些 gas 成本已被确定为公平地反映了操作所消耗的资源。但是,对于执行多次更新的操作序列,这会导致过高的 gas 成本。

以下是一些例子来说明这个问题:

  • 如果一个具有空存储的合约将插槽 0 设置为 1,然后再设置回 0,则将被收取 20000 + 5000 - 10000 = 15000 gas,尽管此操作序列不需要任何磁盘写入。
  • 一个具有空存储的合约将插槽 0 递增 5 次,将被收取 20000 + 5 * 5000 = 45000 gas,尽管此操作序列所需的磁盘活动并不比单次写入多,而单次写入的收费为 20000 gas。
  • 从账户 A 到账户 B 的余额转移,然后从 B 转移到 C,所有账户都具有非零的起始和结束余额,将花费 5000 * 4 = 20000 gas。

解决此问题还将启用当前成本过高的新用例,其中一系列操作不会导致交易结束时存储的净变化。例如,用于防止重入的互斥锁,或在对同一合约的多次调用之间传递的上下文信息。一个这样的例子是 approveAndCall 操作,它允许在单个交易中发送到合约并调用合约,而无需为新的 token 标准更新该合约。

规范

EVM 进行了以下更改:

  • 为每个交易维护一个“脏图”,跟踪当前交易中已修改的所有合约中的所有存储插槽。脏图的作用域与存储更新的方式相同,这意味着对稍后恢复的调用中对脏图的更改不会被保留。
  • 当使用已包含的值写入存储插槽时,将扣除 200 gas。
  • 当第一次更改存储插槽的值时,该插槽将被标记为脏。如果该插槽先前设置为 0,则扣除 20000 gas;否则,扣除 5000 gas。
  • 当写入已在脏图中的存储插槽时,将扣除 200 gas。
  • 在交易结束时,对于脏图中的每个插槽:
    • 如果该插槽在交易前为 0 且现在为 0,则退还 19800 gas。
    • 如果该插槽在交易前为非零值且其值未更改,则退还 4800 gas。
    • 如果该插槽在交易前为非零值且现在为 0,则退还 15000 gas。

在这些更改之后,仅对存储插槽进行单个更改的交易将保留其现有成本。但是,进行多次更改的合约将看到显着降低的成本。重复动机部分中的示例:

  • 如果一个具有空存储的合约将插槽 0 设置为 1,然后再设置回 0,则将被收取 20000 + 200 - 19800 = 400 gas,低于 15000。
  • 一个具有空存储的合约将插槽 0 递增 5 次,将被收取 20000 + 5 * 200 = 21000 gas,低于 45000。
  • 从账户 A 到账户 B 的余额转移,然后从 B 转移到 C,所有账户都具有非零的起始和结束余额,将花费 5000 * 3 + 200 - 4800 = 10400 gas,低于 20000。

理由

我们认为,所提出的机制代表了在存储 gas 成本未反映节点承担的实际成本的情况下,降低存储 gas 成本的最简单方法。我们考虑并驳回了几种替代设计:

  • SSTORE 操作收取 200 gas 的固定费用,并在交易结束时对新的或修改后的值收取额外的 19800 / 4800,这更简单,并且消除了对脏图的需求,但是将 gas 消耗的一个重要来源从 EVM 堆栈中移出,并在交易结束时应用,这可能会使调试复杂化,并降低合约限制被调用者 gas 消耗的能力,以及向 EVM 引入一种新机制。
  • 为存储 gas 退款保留单独的退款计数器可以避免退款被限制为消耗 gas 的一半的问题(这里不需要),但是会增加跟踪此值的复杂性。
  • 每次将存储插槽设置回其初始值时都退还 gas 会引入一种新机制(即时退款)并使调用其他合约的合约的 gas 计数复杂化;它还允许合约调用具有负执行成本的可能性。

向后兼容性

此 EIP 需要进行硬分叉才能实施。

对于此更改,任何合约都不应看到 gas 成本的增加,并且许多合约将看到 gas 消耗的减少,因此预计不会出现合约层面的向后兼容性问题。

测试用例

  • 将 x 写入包含 0 的存储插槽,其中 x != 0(20k gas,无退款)
  • 将 y 写入包含 x 的存储插槽,其中 x != y 且 x != 0(5k gas,无退款)
  • 将 0 写入包含 x 的存储插槽,其中 x != 0(5k gas,10k 退款)
  • 将 0 写入已包含零的存储插槽(200 gas,无退款)
  • 将 x 写入已包含 x 的存储插槽,其中 x != 0(200 gas,无退款)
  • 将 x,然后将 y 写入包含 0 的存储插槽,其中 x != y(20200 gas,无退款)
  • 将 x,然后将 y 写入包含 0 的存储插槽,其中 x != y != z 且 x != 0(5200 gas,无退款)
  • 将 x,然后将 0 写入包含 0 的存储插槽,其中 x != 0(20200 gas,19800 退款)
  • 将 x,然后将 y 写入包含 y 的存储插槽,其中 x != y != 0(5200 gas,4800 退款)
  • 在嵌套帧中,将 x 写入包含 0 的存储插槽,然后恢复发生写入的堆栈帧(20200 gas,无退款)
  • 将 x,然后将 y 写入包含 y 的存储插槽,然后恢复发生写入的堆栈帧(5200 gas,无退款)
  • 在嵌套帧中,将 x 写入包含 0 的存储插槽,然后返回,并将 0 写入该插槽(20200 gas,19800 退款)

实施

待定

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Nick Johnson (@arachnid), "EIP-1087: SSTORE操作的网络 gas 计量 [DRAFT]," Ethereum Improvement Proposals, no. 1087, May 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1087.