【问题标题】:Why are _initializing and isTopLevelCall variables used in Initializable contract of Openzeppelin?为什么在 Openzeppelin 的 Initializable 合约中使用 _initializing 和 isTopLevelCall 变量?
【发布时间】:2022-01-08 09:10:15
【问题描述】:

这是代理模式上下文中的抽象合约:

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;
    }
}

我不明白 _initializing 和 isTopLevelCall 的必要性。仅使用 _initialized 进行控制还不够吗?

谢谢,

【问题讨论】:

    标签: solidity proxy-pattern openzeppelin


    【解决方案1】:
    abstract contract Initializable {
            bool private _initialized;
        
            modifier initializer() {
                require(!_initialized, "Initializable: co...");
                _;
                _initialized = true;
            }
        }
        
    contract UpgradebleTestParent is Initializable {
        uint public x;
    
        function initialize(uint _x) internal initializer {
            x = _x;
        }
    }
    
    contract UpgradebleTestMain is UpgradebleTestParent {
        function init(uint _x) public initializer {
            initialize(_x);
        }
    }
    

    如果是如上,它会执行相同的逻辑,但_initialized = true;会被不必要地执行两次,对吧?但是,它似乎比前一个具有更多变量和相关附加指令的更便宜?不是吗?

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

    _initializingisTopLevelCall 组合允许使用 initializer 修饰符进行链式调用:

    contract UpgradebleTest1 is Initializable {
        uint public x;
    
        function initialize(uint _x) public initializer {
            internalInit(_x);
        }
    
        function internalInit(uint _x) internal initializer {
            x = _x;
        }
    }
    

    如果没有 _initializingisTopLevelCall 检查,initializer 修饰符将在第一次调用 (initialize()) 时传递,但在第二次调用 (internalInit()) 时失败。

    modifier initializer() {
        require(!_initialized, "Initializable: contract is already initialized");
        _initialized = true;
    }
    

    【讨论】:

    • 谢谢,现在我明白了。还有一个问题...
    猜你喜欢
    • 2022-07-07
    • 1970-01-01
    • 2021-10-18
    • 2021-08-24
    • 2019-04-20
    • 2021-08-14
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多