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.