EIP-7705: NONREENTRANT 和 REENTRANT 操作码
用于将合约标记为不可重入的操作码
Authors | Charles Cooper (@charles-cooper) |
---|---|
Created | 2024-05-09 |
Discussion Link | https://ethereum-magicians.org/t/eip-7705-nonreentrant-opcodes/19957 |
摘要
添加两个操作码 NONREENTRANT
和 REENTRANT
,用于设置和清除合约的重入状态。调用 NONREENTRANT
后,在调用 REENTRANT
之前,不能 CALL
(或 STATICCALL
,或 DELEGATECALL
)合约。
动机
重入攻击导致了 EVM 链上大量用户资金被盗,包括著名的“DAO 黑客事件”。然而,由于在应用程序代码中防止重入攻击的成本,开发人员通常选择不进行重入保护。随着瞬态存储 (EIP-1153) 的出现,这种成本有所下降,但仍然不够便宜,以至于默认情况下使用它是“不费脑筋的”。本 EIP 提出了操作码,使保护应用程序代码免受重入攻击的成本更低。
规范
本文档中的关键词“必须(MUST)”,“禁止(MUST NOT)”,“必需(REQUIRED)”,“应该(SHALL)”,“不应该(SHALL NOT)”,“推荐(RECOMMENDED)”,“不推荐(NOT RECOMMENDED)”,“可以(MAY)”和“可选(OPTIONAL)”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。
引入了两个新的操作码,NONREENTRANT
(0xF6) 和 REENTRANT
(0xF7),它们设置和清除合约的不可重入标志。调用 NONREENTRANT
的效果是,在调用 REENTRANT
之前,合约不能再将执行上下文转移到它(通过任何 *CALL
操作码)。CALL
一个设置了不可重入标志的合约等同于执行单个 REVERT
操作码。
NONREENTRANT
和 REENTRANT
都是幂等的;也就是说,当合约已经具有不可重入状态时调用 NONREENTRANT
是空操作,REENTRANT
也是如此。
不可重入标志的范围仅限于当前事务。也就是说,不可重入标志在每个事务结束时清除。如果存在回滚(REVERT
或异常停止),合约的不可重入标志将恢复到调用前的状态。
NONREENTRANT
和 REENTRANT
的成本都设置为 5 (G_mid
)。
原理
将当前值推送到调用堆栈的计算成本(用于处理回滚)已在 *CALL
操作码的开销成本中计算在内。
可以考虑另一种设计,即仅引入一个操作码。这个操作码 NONREENTRANT
将采用单个堆栈项,并根据其值设置不可重入标志。可以根据反馈考虑这种替代设计。
向后兼容性
未发现向后兼容性问题。
测试用例
参考实现
安全考虑
待定
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
Charles Cooper (@charles-cooper), "EIP-7705: NONREENTRANT 和 REENTRANT 操作码 [DRAFT]," Ethereum Improvement Proposals, no. 7705, May 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7705.