Solidity:为什么使用 Initialize 函数而不是构造函数?

Solidity: Why use Initialize function instead of constructor?

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

 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
 }

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

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

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

为什么?

在以太坊中,合约调用主要分为三种:regular CALLSTATICCALLDELEGATECALL.

当合约 A 通过调用 [=10= 进行 CALL 以合约 B ],函数执行依赖合约B的存储,msg.sender设置为合约A.

这是因为合约A调用了函数foo(),所以msg.sender就是合约A 的地址和 msg.value 将是与该函数调用一起发送的 ETH。在该函数调用期间对状态所做的更改只能影响合同 B.

但是,当使用 DELEGATECALL 进行相同的调用时,将在合约 B 上调用函数 foo() 但在合同上下文中 A。这意味着将使用合约 B 的逻辑,但是函数 foo() 所做的任何状态更改都会影响合约 A[=77 的存储=].而且,msg.sender 将指向首先发出呼叫的 EOA。

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

但是当代理在起作用时,这不再可能,因为构造函数只会更改实施合同的存储(合约B),不是proxy合约的存储(合同 A),这是最重要的合同。

因此,需要一个额外的步骤。我们需要更改常规函数中的构造函数。这个函数通常被称为initialize或init,一旦两个合约都被发布,这个函数将在代理合约上被调用,以保存代理合约上的所有状态变化(合约A ) 而不是执行 (合同 B)