You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenZeppelin的Initializable合约中_initializing与isTopLevelCall作用是什么?

可升级合约Initializable逻辑设计疑问解答

首先给出问题语境下的完整合约代码:

abstract contract Initializable {
    bool private _initialized;
    bool private _initializing;

    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

contract UpgradebleTest1 is Initializable {
    uint public x;

    function initialize(uint _x) public initializer {
        x = _x;
    }
}

为什么不能仅用_initialized做状态控制

仅用_initialized确实可以实现禁止重复初始化的基础能力,但完全无法处理初始化流程中嵌套调用其他带initializer修饰符函数的场景,这也是_initializing和isTopLevelCall存在的核心意义。

可升级合约的常规开发规范中,父子合约通常都会给各自的初始化函数加上initializer修饰符,子合约初始化时需要先调用父合约的初始化函数,如果只保留_initialized变量,流程会直接报错:

  1. 调用子合约initialize,触发修饰符检查,此时_initialized为false,校验通过
  2. 修饰符立刻将_initialized设为true
  3. 子合约初始化逻辑中调用父合约的initialize,触发父合约的initializer修饰符检查,发现_initialized已经为true,直接回滚,初始化失败

_initializing与isTopLevelCall的作用

  • _initializing用来标记当前正处于初始化执行流程中
  • isTopLevelCall用来判断当前触发修饰符的调用是不是最顶层的初始化调用(而非初始化过程中嵌套的内部调用)

我们走一遍正常的嵌套初始化流程就能清晰理解逻辑:

  1. 外部调用子合约initialize,触发修饰符,此时_initializing为false、_initialized为false,通过require校验
  2. isTopLevelCall判断为true,将_initializing设为true、_initialized设为true
  3. 进入子合约初始化逻辑,调用父合约的initialize
  4. 父合约的initializer修饰符触发,此时_initializing为true,直接通过require校验
  5. 父合约的isTopLevelCall判断为false,不会修改任何状态变量
  6. 父合约初始化逻辑执行完成,回到子合约逻辑继续执行
  7. 子合约所有逻辑执行完成,回到修饰符的后置逻辑,因为isTopLevelCall为true,将_initializing设为false
  8. 整个初始化流程结束,后续任何调用带initializer修饰符的函数,都会因为_initializing为false、_initialized为true被require拦截,避免重复初始化

如果你的业务场景中初始化逻辑完全没有嵌套调用其他带initializer修饰符的函数,仅用_initialized确实可以正常运行,但通用的可升级合约框架需要覆盖所有常规开发场景,因此这两个变量是必不可少的设计。


内容的提问来源于stack exchange,提问作者Cengo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 06:24:05