Solidity:为什么使用初始化函数而不是构造函数?

GGG*_*205 3 architecture state ethereum solidity smartcontracts

我正在做审计智能合约,有人更喜欢使用这样的初始化函数:

 bool private isInit=false;
 string private hello;
 
 function init(string _hello) public onlyOwner {
   hello = _hello;
   isInit = true;
 } 

 function doSomething() public {
   require(isInit, "Wait for initialize");
   ...doSomething
 }
Run Code Online (Sandbox Code Playgroud)

你能解释一下为什么没有使用构造函数吗?

小智 17

作为示例编写的初始化是错误的,因为它可能被所有者多次调用,初始化程序(以及构造函数)的目的是在使用合约之前作为第一个函数调用,并且永远不会被调用第二次回来

\n

但是,当发布使用代理的合约时,将使用初始化而不是构造函数

\n

为什么?

\n

在以太坊中,合约调用主要分为三种类型:常规 CALLSTATICCALLDELEGATECALL

\n

当合约A通过调用来对合约B进行CALL时,函数执行依赖于合约B \xe2\x80\x99s 存储,并且 msg.sender 设置为合约Afoo()

\n

这是因为合约A调用了函数foo(),因此 将会msg.sender是合约A \xe2\x80\x99s 地址,并且msg.value将是与该函数调用一起发送的 ETH。在该函数调用期间对状态所做的更改只能影响合约B

\n

调用示例

\n

但是,当使用DELEGATECALL进行相同的调用时,将在合约B上但在合约A的上下文中foo()调用该函数。这意味着将使用合约B的逻辑,但该函数所做的任何状态更改都会影响合约A的存储。而且,还会指出最初拨打电话的 EOA。 foo()msg.sender

\n

在此输入图像描述

\n

我们如何处理构造函数逻辑?Contract\xe2\x80\x99s 构造函数在合约部署期间自动调用。

\n

但是当代理发挥作用时,这不再可能,因为构造函数只会更改实现合约\xe2\x80\x99s存储(合约B) ,而不是代理合约(合约A)的存储,这是很重要。

\n

因此,需要额外的步骤。我们需要更改常规函数中的构造函数。该函数通常称为initialize或init,一旦两个合约都已发布,就会在代理合约上调用该函数,以便保存代理合约(合约A)而不是实现(合约B)上的所有状态更改。

\n