* Update ReentrancyGuard for Istanbul Hard Fork
Changes:
Added L37, `_guardCounter = 1;`
Rationale:
The planned _Istanbul Hard Fork_ will implement [EIP 2200](e4d4ea348e/EIPS/eip-2200.md), which implements "net gas metering" for `sstore` operations. If the final value of `_guardCounter` is unchanged relative to the original value of it, a gas refund will be applied and charges for changing the value of `_guardCounter` will effectively not exist. This ends up being cheaper than the current implementation ONLY AFTER Istanbul. Before Istanbul, the added line actually ends up costing more gas.
Note that if `_guardCounter` is `0` initially, the initial cost and subsequent refund will both be larger than if `_guardCounter` is `1` initially. Although in both cases, the net gas cost (`gasCost - gasRefund`) are equal, it's better in terms of cost to have both the gas cost and refund smaller, as there is some limit to the percentage of a gas refund that can actually be realized.
* Update CHANGELOG.md
Added note for change to ReentrancyGuard.sol
* Update ReentrancyGuard.sol
* Update CHANGELOG.md
43 lines
1.6 KiB
Solidity
43 lines
1.6 KiB
Solidity
pragma solidity ^0.5.0;
|
|
|
|
/**
|
|
* @dev Contract module that helps prevent reentrant calls to a function.
|
|
*
|
|
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
|
|
* available, which can be applied to functions to make sure there are no nested
|
|
* (reentrant) calls to them.
|
|
*
|
|
* Note that because there is a single `nonReentrant` guard, functions marked as
|
|
* `nonReentrant` may not call one another. This can be worked around by making
|
|
* those functions `private`, and then adding `external` `nonReentrant` entry
|
|
* points to them.
|
|
*
|
|
* _Since v2.5.0:_ this module is now much more gas efficient, given net gas
|
|
* metering changes introduced in the Istanbul hardfork.
|
|
*/
|
|
contract ReentrancyGuard {
|
|
// counter to allow mutex lock with only one SSTORE operation
|
|
uint256 private _guardCounter;
|
|
|
|
constructor () internal {
|
|
// The counter starts at one to prevent changing it from zero to a non-zero
|
|
// value, which is a more expensive operation.
|
|
_guardCounter = 1;
|
|
}
|
|
|
|
/**
|
|
* @dev Prevents a contract from calling itself, directly or indirectly.
|
|
* Calling a `nonReentrant` function from another `nonReentrant`
|
|
* function is not supported. It is possible to prevent this from happening
|
|
* by making the `nonReentrant` function external, and make it call a
|
|
* `private` function that does the actual work.
|
|
*/
|
|
modifier nonReentrant() {
|
|
_guardCounter += 1;
|
|
uint256 localCounter = _guardCounter;
|
|
_;
|
|
require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
|
|
_guardCounter = 1;
|
|
}
|
|
}
|