From 0282c3608d8cf9e9fc2561a8f993ba2bc823f397 Mon Sep 17 00:00:00 2001 From: Philippe Castonguay Date: Mon, 8 Jul 2019 12:41:55 -0400 Subject: [PATCH] Using extcodehash instead of extcodesize for less gas (#1802) * Using extcodehash instead of extcodesize for less gas `extcodehash` uses less gas then `extcodesize`. You can tell which address is a contract by the hash (see EIP-1052). * Fix * Add explainer * Update Address.sol * add changelog entry --- CHANGELOG.md | 5 +++++ contracts/utils/Address.sol | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11bb59529..71e201f6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ ### New features: * `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773)) +### Improvements: + * `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) + +### Bugfixes + ## 2.3.0 (2019-05-27) ### New features: diff --git a/contracts/utils/Address.sol b/contracts/utils/Address.sol index acaca9b72..b52a768e7 100644 --- a/contracts/utils/Address.sol +++ b/contracts/utils/Address.sol @@ -18,11 +18,15 @@ library Address { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. - - uint256 size; + + // According to EIP-1052, 0x0 is the value returned for not-yet created accounts + // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned + // for accounts without code, i.e. `keccak256('')` + bytes32 codehash; + bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly - assembly { size := extcodesize(account) } - return size > 0; + assembly { codehash := extcodehash(account) } + return (codehash != 0x0 && codehash != accountHash); } /**