EIP-3855: PUSH0 指令
引入一个新的指令,将常量值 0 推送到堆栈上
Authors | Alex Beregszaszi (@axic), Hugo De la cruz (@hugo-dc), Paweł Bylica (@chfast) |
---|---|
Created | 2021-02-19 |
摘要
引入 PUSH0
(0x5f
) 指令,该指令将常量值 0 推送到堆栈上。
动机
许多指令期望偏移量作为输入,在许多情况下这些偏移量为零。一个很好的例子是 CALL
的返回数据参数,如果合约倾向于使用 RETURNDATA*
,则这些参数设置为零。这只是一个例子,但是合约需要推送零值的原因还有很多。它们今天可以通过 PUSH1 0
来实现,这在运行时花费 3 个 gas,并被编码为两个字节,这意味着 2 * 200
gas 的部署成本。
由于总成本的原因,许多人试图使用各种其他指令来实现相同的效果。常见的例子包括 PC
、MSIZE
、CALLDATASIZE
、RETURNDATASIZE
、CODESIZE
、CALLVALUE
和 SELFBALANCE
。其中一些仅花费 2 个 gas 并且是一个字节长,但是它们的值可能取决于上下文。
我们对主网进行了分析(区块范围 8,567,259…8,582,058 和 12,205,970…12,817,405),并且执行的所有 PUSH*
指令中约有 11.5% 推送零值。
此更改的主要动机包括:
- 减少合约代码大小。
- 降低合约(误)使用各种指令作为优化措施的风险。重新定价/更改这些指令可能更具风险。
- 减少使用
DUP
指令来复制零的需要。
为了使“浪费”更具说服力,在现有帐户中,有 340,557,331 字节浪费在 PUSH1 00
指令上,这意味着花费了 68,111,466,200 gas 来部署它们。实际上,许多这些帐户与其他帐户共享相同的字节码,因此它们在客户端中的总存储大小较低,但是无论如何都必须支付部署时间成本。
2) 的一个例子是更改 RETURNDATASIZE
的行为,使其不能保证在调用帧的开头为零。
规范
在 0x5f
处引入指令 PUSH0
。它没有立即数据,不会从堆栈中弹出任何项目,并将一个值为 0 的项目放置到堆栈上。此指令的成本为 2 gas(又名 base
)。
理由
Gas 成本
base
gas 成本用于将常量值放置到堆栈上的指令,例如 ADDRESS
、ORIGIN
等。
操作码
0x5f
意味着它与其余的 PUSH
实现位于“连续”空间中,并且可能可以共享实现。
向后兼容性
此 EIP 引入了一个以前不存在的新操作码。已部署的使用此操作码的合约可能会在此 EIP 之后更改其行为。
测试用例
5F
– 成功执行,堆栈由单个项目组成,设置为零5F5F..5F
(1024 times) – 成功执行,堆栈由 1024 个项目组成,全部设置为零5F5F..5F
(1025 times) – 由于堆栈溢出而中止执行
安全注意事项
作者不知道对安全的任何影响。请注意,jumpdest-analysis 不受影响,因为 PUSH0
没有立即数据字节。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Alex Beregszaszi (@axic), Hugo De la cruz (@hugo-dc), Paweł Bylica (@chfast), "EIP-3855: PUSH0 指令," Ethereum Improvement Proposals, no. 3855, February 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3855.