3

I was reading through the source code for Openzeppelin's CountersUpgradeable library v4.3.0 and realised that the arithmetic operation in the increment / decrement functions is wrapped by an unchecked block. As I understand it, the unchecked block would allow for overflow / underflow situations so isn't this a bad idea?

2 Answers 2

1

tl;dr, the size of uint256 - 1 (the largest uint256, and therefore the number you'd have to reach to overflow) is so large that if we design a uint that starts at 0 and has to be incremented by 1 at a time on the blockchain, you can't get there even if you write an infinite loop powered by a supernova running at maximum efficiency.

Therefore, overflow checks on a +1 incrementing uint256 value are effectively a waste of gas.


more detail:

If you look at the history of this particular unchecked block being added, this was to bring the 0.8 code in line with the 0.7 code. We can see this comment in the 0.7 version of the code, explaining why they didn't use safemath for incrementing back then:

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */

see the old version of the file for this comment yourself: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/90ed1af972299070f51bf4665a85da56ac4d355e/contracts/utils/Counters.sol

Using an unchecked block there matches the previous code where safemath wasn't used there. Overflows on a uint256 aren't a thing, is basically it, and it's cheaper to do unchecked math.

(sadly, they removed this explanatory note, it's a reasonable question one would naturally have looking at this file.)

Why is it not possible to overflow if incrementing by one? More OZ: https://forum.openzeppelin.com/t/counters-sol-increment-does-not-need-overflow-protection/1375

It is not possible to overflow a 256 bit integer with increments of one because of the following: Paraphrasing > https://security.stackexchange.com/a/82412: 15 overflowing 256-bit counters will be impossible until computers are built from something other than matter and occupy something other than space.

(I highly recommend clicking through to that link, btw, it's as entertaining as it is educational.)

3

It's cheaper to use unchecked blocks and check for overflows and underflows manually than let Solidity do it. Refer to Is the modulo operation cheaper in unchecked arithmetic? for more details.

2
  • Thanks! I'm still wondering why gas savings has been prioritised over SafeMath operations in the contract in question. This contract is an optional extension on the standard OpenZeppelin contract suite to add auto increment token ID to an ERC 721 contract. Expecting the calling contract to manually check before invoking the counter seems like an anti-pattern?
    – navpal
    Aug 19, 2021 at 0:28
  • To be frank I don't know, I am not part of the OpenZeppelin team. You might want to ask this question on forum.openzeppelin.com. Aug 19, 2021 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.