【问题标题】:Solidity: Why use Initialize function instead of constructor?Solidity:为什么使用 Initialize 函数而不是构造函数?
【发布时间】:2022-12-18 15:19:54
【问题描述】:
我正在做审计智能合约,有人喜欢使用这样的初始化函数:
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
}
你能解释一下为什么不使用构造函数吗?
【问题讨论】:
标签:
architecture
state
ethereum
solidity
smartcontracts
【解决方案1】:
您作为示例编写的初始化是错误的,因为它可能被所有者多次调用,初始化器(以及构造函数)的目的是在使用合同之前作为第一个函数被调用,并且永远不会被调用第二次回来
然而,当一个合约使用一个代理人发表
为什么?
在以太坊中,主要有三种类型的合约调用:定期通话,静态调用, 和代表电话.
签约时一个做一个称呼合同乙通过调用foo(),函数执行依赖合约乙的存储,并且 msg.sender 设置为 contract一个.
这是因为契约一个调用了函数foo(),这样msg.sender就是合约一个的地址和msg.value 将是与该函数调用一起发送的 ETH。在该函数调用期间对状态所做的更改只会影响合约乙.
但是,当使用代表电话, 函数foo() 将在合同中被调用乙 但在合同的范围内 一个.这意味着合同的逻辑乙将被使用,但函数foo()所做的任何状态更改都会影响合约的存储一个.而且,msg.sender 将指向首先拨打电话的 EOA。
我们该如何处理构造函数逻辑?合约的构造函数在合约部署期间自动调用。
但是当代理人正在发挥作用,因为构造函数只会更改实施合约的存储(乙合约),而不是存储代理人合同(合约甲),这是最重要的。
因此,需要一个额外的步骤。我们需要更改常规函数中的构造函数。此函数通常称为初始化或初始化,一旦两个合约都已发布,将在代理合约上调用此函数,以保存代理合约上的所有状态更改(合约A)而不是实施(合约乙)
【解决方案2】:
openzeppelin docs explains:
构造函数警告
在 Solidity 中,构造函数中的代码或全局变量的一部分
变量声明不是已部署合约运行时的一部分
字节码。这段代码只执行一次,当合约实例
已部署。因此,逻辑中的代码
合约的构造函数永远不会在
代理的状态。换句话说,代理完全无视
构造函数的存在。就好像他们不在那里一样
代理。
不过问题很容易解决。逻辑合约应该移动
构造函数中的代码到常规的“初始化程序”函数,以及
每当代理链接到此逻辑时调用此函数
合同。需要特别注意这个初始化器
函数,以便它只能被调用一次,这是其中之一
一般编程中构造函数的属性。