Alert Source Discuss
🚧 Stagnant Standards Track: Core

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

摘要

添加两个操作码 NONREENTRANTREENTRANT,用于设置和清除合约的重入状态。调用 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 操作码。

NONREENTRANTREENTRANT 都是幂等的;也就是说,当合约已经具有不可重入状态时调用 NONREENTRANT 是空操作,REENTRANT 也是如此。

不可重入标志的范围仅限于当前事务。也就是说,不可重入标志在每个事务结束时清除。如果存在回滚(REVERT 或异常停止),合约的不可重入标志将恢复到调用前的状态。

NONREENTRANTREENTRANT 的成本都设置为 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.