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在以太坊中,合约调用主要分为三种类型:常规 CALL、STATICCALL和DELEGATECALL。
\n当合约A通过调用来对合约B进行CALL时,函数执行依赖于合约B \xe2\x80\x99s 存储,并且 msg.sender 设置为合约A。foo()
这是因为合约A调用了函数foo(),因此 将会msg.sender是合约A \xe2\x80\x99s 地址,并且msg.value将是与该函数调用一起发送的 ETH。在该函数调用期间对状态所做的更改只能影响合约B。
但是,当使用DELEGATECALL进行相同的调用时,将在合约B上但在合约A的上下文中foo()调用该函数。这意味着将使用合约B的逻辑,但该函数所做的任何状态更改都会影响合约A的存储。而且,还会指出最初拨打电话的 EOA。 foo()msg.sender
我们如何处理构造函数逻辑?Contract\xe2\x80\x99s 构造函数在合约部署期间自动调用。
\n但是当代理发挥作用时,这不再可能,因为构造函数只会更改实现合约\xe2\x80\x99s存储(合约B) ,而不是代理合约(合约A)的存储,这是很重要。
\n因此,需要额外的步骤。我们需要更改常规函数中的构造函数。该函数通常称为initialize或init,一旦两个合约都已发布,就会在代理合约上调用该函数,以便保存代理合约(合约A)而不是实现(合约B)上的所有状态更改。
\n