In openzeppelin's Initializable.sol
library(v4.7.0), there is a modifier initializer()
that checks if a function has already been initialized. In the require statement, it checks the value of _initialized
which I understand. But in addition, it also verifies whether address(this)
is a contract or not through AddressUpgradeable.isContract(address(this)
. Why is this needed? See code and questions below.
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
address(this)
would ever not be a contract? Wouldn't address(this)
always refer to the instance of the smart contract?(!AddressUpgradeable.isContract(address(this)) && _initialized == 1)
will return true? Because if _initialized==1
, it means the function has been initialized. Then why would we still allow this extra condition to pass?
Thank you!1. In what condition,
address(this)
would ever not be a contract?
The OpenZeppelin isContract()
function checks if code
property of the address is non-empty (GitHub).
The code
is still empty while executing a constructor. For example the below code emits NotContract
even though it's effectively executed from a contract address.
pragma solidity ^0.8;
contract Caller {
event IsContract();
event NotContract();
constructor(Target target) {
if (target.isCallerContract()) {
emit IsContract();
} else {
emit NotContract();
}
}
}
contract Target {
function isCallerContract() external view returns (bool) {
return msg.sender.code.length != 0;
}
}
In what condition
(!AddressUpgradeable.isContract(address(this)) && _initialized == 1)
will return true?
Constructor calling 2 functions that both have the initializer
modifier. Or the same function two times (from within the constructor).
During the second function call, _initialized
is already 1
.