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

Allow Initializable versions greater than 256 #4460

Conversation

ernestognw
Copy link
Member

@ernestognw ernestognw commented Jul 14, 2023

Fixes LIB-828
Fixes #3924

A greater initialized was proposed for #3924, which is implemented within this PR. Also, the EIP-7201 for Namespaced storage is used here to reduce the risk of storage collisions in upgradeable contracts that are also initializable. In this way, the Initializable variables are placed at a storage location that's guaranteed not to clash.

PR Checklist

  • Tests
  • Documentation
  • Changeset entry (run npx changeset add)

@changeset-bot
Copy link

changeset-bot bot commented Jul 14, 2023

🦋 Changeset detected

Latest commit: 5935090

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
openzeppelin-solidity Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ernestognw ernestognw requested a review from a team July 14, 2023 21:24
@ernestognw
Copy link
Member Author

Bumping pragma to 0.8.20 on Initializable to support NatSpec in structs.

Also, keeping it as a draft at the moment because I suspect we may require a test for storage collisions on storage slot 0.

@@ -89,17 +102,20 @@ abstract contract Initializable {
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
if (!(isTopLevelCall && _initialized < 1) && !(address(this).code.length == 0 && _initialized == 1)) {
// solhint-disable-next-line var-name-mixedcase
Copy link
Member Author

Choose a reason for hiding this comment

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

There are several of these for the $ storage variable. We either keep this rule or wait on protofire/solhint#453 to be merged if that's the case.

@frangio
Copy link
Contributor

frangio commented Jul 14, 2023

I like this but before reviewing I'll let @Amxx comment whether he thinks this is a good idea.

// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();

if ($._initializing) {
revert AlreadyInitialized();
Copy link
Collaborator

Choose a reason for hiding this comment

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

That is not changed by this PR, but I'm wondering if that is the right error to trigger.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree with you but we may decide on this once we decide to tackle #3950 as well

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.

We discussed offline that we should not include #3950 in this PR because it breaks a pattern that we use for testing contracts with initializers, as described in #3344.

@ernestognw ernestognw marked this pull request as ready for review July 28, 2023 02:19
@ernestognw
Copy link
Member Author

The storage layout checks are failing as expected

@ernestognw ernestognw requested review from frangio and Amxx July 28, 2023 02:19
@Amxx Amxx mentioned this pull request Jul 31, 2023
@frangio
Copy link
Contributor

frangio commented Jul 31, 2023

Closed accidentally.

@frangio frangio reopened this Jul 31, 2023
@ernestognw
Copy link
Member Author

Closed accidentally.

reinitialize(2)

@@ -213,7 +213,7 @@ contract('Initializable', function () {
it('old and new patterns in good sequence', async function () {
const ok = await DisableOk.new();
await expectEvent.inConstruction(ok, 'Initialized', { version: '1' });
await expectEvent.inConstruction(ok, 'Initialized', { version: '255' });
await expectEvent.inConstruction(ok, 'Initialized', { version: (2n ** 64n - 1n).toString() }); // MAX_UINT64
Copy link
Collaborator

@Amxx Amxx Aug 1, 2023

Choose a reason for hiding this comment

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

we should consider generalizing this syntax if possible. The issue is that web3.utils.toBN does not support native bigints.

please, ethers.js + chai matchers.

Copy link
Member Author

Choose a reason for hiding this comment

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

I used web3.utils.toBN(1).shln(64).subn(1).toString() instead because I think we've previously agreed on a similar one in the ERC2771Forwarder (but for uint48), does this work?

@Amxx
Copy link
Collaborator

Amxx commented Aug 1, 2023

LGTM. Do we wait on the linter rule or do we merge like this and come back to it later?

@ernestognw
Copy link
Member Author

LGTM. Do we wait on the linter rule or do we merge like this and come back to it later?

I'd rather not wait on them, I'm sure we'll revisit after starting with the transpiler work

Co-authored-by: Francisco <fg@frang.io>
@frangio frangio self-requested a review August 7, 2023 16:05
@frangio frangio merged commit 70578bb into OpenZeppelin:master Aug 7, 2023
13 of 14 checks passed
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.

Allow reinitializer versions greater than 256
3 participants