Oz upgrade command and the initialize function - does the latter get called by default

Does the oz upgrade command look for an initialize function and calls it by default?
I am asking because I just used oz upgrade and when I selected I want to call a function and selected my initialize function - it failed.
However, when I oz upgrade without selecting to call initiialize the upgrade went through
I didnt change the initizialize function in my contract one single bit between the first deployment via oz create where I did select to call initialize and the oz upgrade where I also selected to initialize (and the tx reverted).


I asked because maybe my first oz upgrade in the above pictures is always failing due to the initializer modifier already throwing from my suspected OZ CLI default call to initizialize.

Btw I tried to call initialize after oz upgrade was completed successful in the second attempt in the pic above, and I got the same error.

So my assumption that the error is due to oz CLI calling initialize by default when using oz upgrade seem to be correct

If it is that way, I think this should be made more explicit at the command line that initialize is already being called in the background.

:computer: Environment

oz --version 2.5.3
├── @openzeppelin/contracts@2.3.0

├── @openzeppelin/upgrades@2.5.3

├── @truffle/hdwallet-provider@1.0.22

└── dotenv@8.2.0

1 Like

No functions are automatically called - the reason why calling initialize fails is because you’ve already initialized your instance (before the upgrade). The initialize function can only be called once during the whole lifetime of the contract (similar to a constructor).

If you were to modify your contract in a way that required e.g. initialization of new variables, you’d need to include a second initialize function (this is typically called a ‘migration’) to perform this task. We’ve found this is very ad-hoc for each project though, and have not come up with a generalized pattern for writing these yet.

That said, it is unfortunate that the CLI detected your transaction would revert, but didn’t give you a revert reason string, that would’ve pointed you in the right direction. Would you mind opening an issue in the SDK repo (https://github.com/OpenZeppelin/openzeppelin-sdk) asking for this feature? Thanks!

2 Likes

Ah ok! That is a gotcha! I think this could be made more clear in the docs. I read them quite well, and I think the particular point that you cannot call the initialize function again between upgrades and you can only call it once in the proxy's lifetime (is how I would think of it) was not very explicitly mentioned. Thank you very much for clarifying and I will open the issue in the SDK repo. BTW my suggestions are just tips. I already fell in love with the SDK and I think you guys have done and keep on doing an outstanding work for developers in the Ethereum community.

2 Likes

Hi @gitpusha,

Thank you for all your feedback.

Issues and PRs to improve the documentation are very welcome.
Specifically if the initializers documentation could be improved.
https://docs.openzeppelin.com/sdk/2.5/writing-contracts#initializers

One thing to note is that an upgrade function should be protected from being called more than once. A guard could look as follows:

contract MyContract is Initializable {
    uint256 private _value;
    bool private _upgraded;

    function initialize(uint256 value) public initializer {
        _value = value;
    }

    function upgrade(uint256 value) public {
        require(!_upgraded, "MyContract: already upgraded");
        _upgraded = true;
        _value = value;
    }

    function getValue() public view returns (uint256) {
        return _value;
    }
}
1 Like

Hi @gitpusha (and for future community members reading this)

As per: Error: Cannot find module 'create-hash'

Looking at your packages installed, you currently have @openzeppelin/contracts rather than @openzeppelin/contracts-ethereum-package :

https://docs.openzeppelin.com/sdk/2.5/linking
Make sure you install @openzeppelin/contracts-ethereum-package and not the vanilla @openzeppelin/contracts . The latter is set up for general usage, while @openzeppelin/contracts-ethereum-package is tailored for being used with the OpenZeppelin SDK. This means that its contracts are already set up to be upgradeable.

Though use version 2.2.3 due to OpenZeppelin/openzeppelin-contracts-ethereum-package#70

oz link @openzeppelin/contracts-ethereum-package@2.2.3