Update initializer modifier to prevent reentrancy during initialization (#3006)

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
This commit is contained in:
Hadrien Croubois
2021-12-10 17:02:35 +01:00
committed by GitHub
parent 0c858e2071
commit 08840b9f8c
5 changed files with 144 additions and 16 deletions

View File

@ -3,6 +3,8 @@
pragma solidity ^0.8.0;
import "../../utils/Address.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
@ -45,7 +47,10 @@ abstract contract Initializable {
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
@ -59,4 +64,17 @@ abstract contract Initializable {
_initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !Address.isContract(address(this));
}
}