Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update contracts to support Solidity 0.8.x #2442

Merged
merged 18 commits into from
Jan 14, 2021

Conversation

andrekorol
Copy link
Contributor

Fixes #2441

Contracts' solidity version pragmas were updated to support Solidity 0.8.x.

Changes include:

  • Updated explicit type conversions that conform with the new restrictions.
  • Functions that rely on chainid in inline assembly are now view instead of pure.

Important Note: Some tests are still not passing because since 0.8.0 failing assertions and other internal checks like division by zero or arithmetic overflow do not use the invalid opcode, but instead the revert opcode. And I believe that this is something worth discussing how to handle before making any changes to the current test cases.

@frangio
Copy link
Contributor

frangio commented Dec 18, 2020

Thanks @andrekorol! We in fact want to remove all uses of SafeMath from the library now that checked arithmetic is built into Solidity.

We have to discuss whether we want to remove SafeMath entirely, though. It may make sense to deprecate it but still keep the interface for a while for backwards compatibility, and removing the manual checks instead just relying on Solidity's checks. There are some subtleties like the custom error messages that are produced by some of the operations, but that has been reported recently to increase gas cost unnecessarily so I think we will want to remove it.

These changes will mean that Solidity 0.8 support will happen in a new major version of the library. We plan to release a final version of the current major before that happens, so we will merge the migration to Solidity 0.8 into a separate branch.

So I will ask, if you can, to change pragmas to pragma solidity ^0.8.0;, remove uses of SafeMath, and also to resolve conflicts because I merged a related PR that we had pending since before this one.

@andrekorol
Copy link
Contributor Author

@frangio I can make and commit those changes, no problem! I agree with Solidity 0.8 support coming in a new major version of the library, I don't think it makes much sense to have all the changes you mentioned in a new minor version.

@andrekorol
Copy link
Contributor Author

@frangio I've made the necessary changes. Some tests are still not passing because they expect custom error messages instead of just VM Exception while processing transaction: revert.

I still didn't make any change to the tests though, I wanted to confirm if the correct approach would be to change the expected custom error messages to the default VM Exception while processing transaction: revert.

Also, the Strings utility library seems to be broken now, and I'm still not sure why, the only thing changed was the version pragma. I suppose it's something to do with the new restrictions on type conversions...

@andrekorol
Copy link
Contributor Author

andrekorol commented Dec 18, 2020

So, apparently the Strings library wasn't working since solc-0.7 because it was not possible to explicitly convert from uint256 to bytes1.

But with 346fbe2, it's working again.

@andrekorol andrekorol force-pushed the fix/solc-0.8-#2441 branch 2 times, most recently from f82ef07 to d2ca110 Compare December 18, 2020 09:05
@lephleg
Copy link

lephleg commented Dec 21, 2020

Great work, @andrekorol! Thanks for your efforts on this.
Please let me know if you require a spare hand implementing or reviewing anything particular.

@frangio
Copy link
Contributor

frangio commented Dec 21, 2020

I still didn't make any change to the tests though, I wanted to confirm if the correct approach would be to change the expected custom error messages to the default VM Exception while processing transaction: revert.

The test helpers have an expectRevert.unspecified function that you can use.

@frangio frangio changed the base branch from master to solc-0.8 December 21, 2020 21:13
Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @andrekorol. Most of the changes look good.

I'm now having doubts about what we should do regarding the custom revert reasons on subtraction overflow. Maybe we should keep them. What do other people think about this? Should we keep custom revert reasons such as "insufficient balance"?

Can you also change SafeMath to remove our manual checks and rely only on the built in checked arithmetic?

Comment on lines 16 to 17
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
return payable(msg.sender);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Solidity changed the type of msg.sender we should change the return type of our _msgSender function accordingly, instead of casting it here.

Comment on lines 99 to 101
function _getChainId() private view returns (uint256 chainId) {
chainId = block.chainid;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this function now and just use the built in.

Comment on lines 25 to 27
function getChainId() external view returns (uint256 chainId) {
chainId = block.chainid;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Comment on lines 17 to 19
function getChainId() external view returns (uint256 chainId) {
chainId = block.chainid;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@thegostep
Copy link

Should we keep custom revert reasons such as "insufficient balance"?

I generally prefer explicit revert messages now that it is convenient to test for them with waffle.

@aaronovz1
Copy link

Should we keep custom revert reasons such as "insufficient balance"?

I generally prefer explicit revert messages now that it is convenient to test for them with waffle.

Would custom messages undo the gas savings from using built in arithmetic checker? This is the best part of 0.8 IMO - we wouldn't want to lose that benefit.

@frangio
Copy link
Contributor

frangio commented Dec 21, 2020

We have to run some tests and measure the impact. I don't know if there is any special magic in the built in arithmetic checker that would make it more efficient than manual checks.

@andrekorol
Copy link
Contributor Author

Great work, @andrekorol! Thanks for your efforts on this.
Please let me know if you require a spare hand implementing or reviewing anything particular.

@lephleg Help would be appreciated in fixing tests that are failing under coverage (solidity-coverage/ganache) 😄

@andrekorol
Copy link
Contributor Author

andrekorol commented Dec 24, 2020

Should we keep custom revert reasons such as "insufficient balance"?

One way to retain custom revert reasons would be to keep functions with different signatures like sub(uint256 a, uint256 b) and sub(uint256 a, uint256 b, string memory errorMessage), where in the one with the errorMessage, manual checks are performed as before, and the actual operation is performed inside an unchecked block.

@lephleg
Copy link

lephleg commented Dec 24, 2020

@lephleg Help would be appreciated in fixing tests that are failing under coverage (solidity-coverage/ganache) 😄

At first glance it seems there's a memory leak introduced in node. I wouldn't allocate more before ensuring there's nothing sketchy in the changes. Tricky one, I'll give it a shot with clear head tomorrow.

@axic
Copy link
Contributor

axic commented Dec 24, 2020

Can you also change SafeMath to remove our manual checks and rely only on the built in checked arithmetic?

@frangio does it actually make sense to keep SafeMath as a weird wrapper? It adds no benefit, and the "special error message" versions are removed in this PR.

Perhaps it is better biting the bullet by removing it, and that could trigger users to review the new semantics and use them properly (checked vs. unchecked). And also be aware of the gas implications.

@andrekorol
Copy link
Contributor Author

andrekorol commented Dec 25, 2020

Can you also change SafeMath to remove our manual checks and rely only on the built in checked arithmetic?

@frangio does it actually make sense to keep SafeMath as a weird wrapper? It adds no benefit, and the "special error message" versions are removed in this PR.

Perhaps it is better biting the bullet by removing it, and that could trigger users to review the new semantics and use them properly (checked vs. unchecked). And also be aware of the gas implications.

@axic, as I've said in the comment above, it's possible to revert those changes that removed the "special error messages" and have SafeMath overload functions with two different signatures. One would be just that weird wrapper, and the other would perform the manual checks with custom error messages. The actual arithmetic operation would be wrapped in an unchecked block to avoid wasting gas with double-checking.

@hantuzun
Copy link

hantuzun commented Dec 28, 2020

Removing SafeMath is tedious but a straightforward refactoring, but its benefit to the ecosystem would worth the effort. I'm against keeping it as a wrapper.

Edit: Happy holidays and thank you for the work going on in this PR ✨

@@ -208,7 +208,7 @@ function shouldBehaveLikeERC1155 ([minter, firstTokenHolder, secondTokenHolder,
});

it('reverts when transferring more than balance', async function () {
await expectRevert(
await expectRevert.unspecified(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should OpenZeppelin/openzeppelin-test-helpers#149 be implemented, tests like these would not lose precision as much as in this current PR.

@andrekorol
Copy link
Contributor Author

@hantuzun Thanks, happy holidays to you as well!!

Should I remove SafeMath and the related tests, including cases like the one @axic mentioned on his last review?

@axic
Copy link
Contributor

axic commented Dec 30, 2020

Just to be clear, I am not part of OpenZeppelin, so my suggestions are only suggestions, not an official review 😃

@andrekorol
Copy link
Contributor Author

No problem, thanks for the review anyway!

@andrekorol
Copy link
Contributor Author

@frangio is there a consensus on whether SafeMath should be removed?

Do you think setting up a poll before making any further changes is a good idea?

Copy link
Collaborator

@Amxx Amxx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good to me.

I was expecting a change of the proxies, using the new fallback (bytes calldata _input) external [payable] returns (bytes memory _output) signature, but considering the assembly part is in the _delegate internal function, It might do more harm then good to embrace this change.

@Amxx
Copy link
Collaborator

Amxx commented Jan 5, 2021

My grain of salt:
I think the current version of SafeMath is usefull, and we should be kept in the codebase. Its just a wrapper around the solidity built-in op, so it should be optimized trivially ... and it makes old code more easily portable to 0.8.

Also, it can be used to force/enable safemath inside unchecked {} blocks:

contract Test {
    uint256 constant internal x = 0;
    uint256 constant internal y = 1;
    function a() public pure returns(uint256) { return x - y; } // revert
    function b() public pure returns(uint256) { unchecked { return x - y; } } // overflow
    function c() public pure returns(uint256) { return SafeMath.sub(x, y); } // revert
    function d() public pure returns(uint256) { unchecked { return SafeMath.sub(x, y); } } // revert
}
```

@Amxx
Copy link
Collaborator

Amxx commented Jan 5, 2021

Note for the future: Some "low level" functions, such as Array::findUpperBound or String::toString could probably benefit from using unchecked to reduce gas cost.

@frangio
Copy link
Contributor

frangio commented Jan 8, 2021

Let's keep SafeMath in this PR and discuss its removal separately. I've created an issue dedicated to it, please participate! Go to #2465.

We have to take a look at what's causing the coverage job to fail. Otherwise the PR seems good to go. Thanks for working on this @andrekorol!

@andrekorol
Copy link
Contributor Author

It was my pleasure!

I think the coverage job failing has something to do with trufflesuite/ganache/issues/515.

It should be fixed in ganache@3.0.0-internal.0, but I'll take a closer look at it to see if that's really the case.

@andrekorol
Copy link
Contributor Author

andrekorol commented Jan 9, 2021

Initially, coverage was failing due to an out of memory error, which could be solved by either updating Node's version here to any version >= 14:

or by increasing the heap memory as I did in 6a30dcc.

Now the coverage job is failing because of six different test cases that are not passing. Two of them (domain separator) I assume to be related to that chainId issue.

@frangio
Copy link
Contributor

frangio commented Jan 12, 2021

I think you have debugged it correctly, it's likely to be the chainId issue.

Something else we will have to do afterwards is review all of the expectRevert.unspecified in tests and add back the revert reasons. We will be able to bring them back with the functionality we're adding in #2462.

Thank you everyone! Please remember this is going in the solc-0.8 branch, and we will do our best to release it as soon as possible as version 4.0 of the library. We are now preparing 3.4 as the last release of the 3.x line.

@frangio
Copy link
Contributor

frangio commented Jan 12, 2021

A correction: while doing a last review of the changes in this PR I found that the chain id issue in Ganache already had a workaround and it was being removed here. It fixed the coverage for me locally and hopefully the CI will agree.

@frangio frangio merged commit 974c534 into OpenZeppelin:solc-0.8 Jan 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for Solidity 0.8.x
8 participants