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 CALL、STATICCALL、DELEGATECALL.
当合约 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)
我正在做审计智能合约,有人喜欢使用这样的初始化函数:
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 CALL、STATICCALL、DELEGATECALL.
当合约 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)