Advice on testing upgradeability in ZOS

Hi,

We have developed our smart contracts using ZeppelinOS and are working on our test suite to test all the functions of the contracts. We have the functionality now pretty much all tested but are now planning to write some automated tests for the upgrading process. Can anyone advise the best way to go about this or point me towards a good example or two of how to provide good test coverage of the upgrading process?

Thanks in advance
Rick

2 Likes

Hey @roy.batty!
Circle USDC use similar upgradability technique and they have tests for that. Take a look.

2 Likes

Thanks @ylv-io. I have looked at the Centre/Circle tests before but I don’t believe they are using ZeppelinOS? It looks like they completed their development before a lot of the current tooling was available?

For example in the Circle ProxyPositiveTests.js the tests will actually create the FiatTokenProxy contract which inherits from the AdminUpgradeabilityProxy contract. The test will then call the initialize function directly. For the upgrade process itself the tests then call the ‘upgradeTo’ function in the proxy contract directly…

So I am just wondering now with the current ZeppelinOS tooling and abstractions whether the methods of testing the upgradeability would follow a different pattern?

Cheers
Rick

Hey @roy.batty! We wrote this post a few months ago on how to test real-world upgrades, by locally forking the main chain to run the upgrades and test them on a secure environment.

Alternatively, we also provide a TestHelper method for setting up your zOS project in a testing environment, and instantiate as many upgradeable instances as you want.

2 Likes

Thanks @spalladino! I will definitely check out this article and try out the steps outlined… Are there any github repos with an example project using these methods?

Can I make another suggestion for this article? It seems the currently the article outlines the method for attempting to update the contract but doing it incorrectly by changing the storage layout. I think it could be beneficial to then show how to then fix this issue and re-deploy and show that all is good with the world again. What do you think?

Thanks
Rick

3 Likes

Hey @roy.batty.
You are right that Centre/Circle tests don’t use ZeppelinOS and the current methods of ZeppelinOS would be different to test upgradability. I am not aware of any repo which have a sample code for test upgradeability. Except zos itself.
Regarding an article on upgradability. Tutorial-kit guides you via upgrading contract. There is a tutorial on it by @Dennison. It is a bit outdated but should provide a good idea how it works.
Is there any more questions left?

2 Likes

Hi @spalladino, thanks for your link to your testing article…

I seem to be having a problem when I try to follow the instructions to try and follow along though…

I get to the part where I create an instance of the CustomERC20 contract on rinkeby but when I then go into truffle console to query it I get some errors… see below:

$ npx zos create CustomERC20 --init initialize --args 'MyToken','MYT','8','10000000000','0xB63Db20Db1eD74204C6cfF8e623b40010dbF08Ae' --network rinkeby
Using session with sender address 0xED609586F5bE1ADc8d3f9f5a7cEA8Dab45a42A53
Creating proxy to logic contract 0x907f62b9b71b63e6d61b33780beac49ada9371d4 and initializing by calling initialize with: 
 - name (string): "MyToken"
 - symbol (string): "MYT"
 - decimals (uint8): "8"
 - initialSupply (uint256): "10000000000"
 - initialHolder (address): "0xB63Db20Db1eD74204C6cfF8e623b40010dbF08Ae"
Instance created at 0x079103a68544db3a0f13762b3e2211d9d69b8e6b
0x079103a68544db3a0f13762b3e2211d9d69b8e6b
Updated zos.rinkeby.json

$ npx truffle console --network rinkeby                                                         
truffle(rinkeby)> const erc20 = await CustomERC20.at('0x079103a68544db3a0f13762b3e2211d9d69b8e6b')
undefined
truffle(rinkeby)> erc20.name()
Error: overflow (operation="setValue", fault="overflow", details="Number can only safely store up to 53 bits")

Would you know what is causing that issue? I tried to follow exactly the same steps you have in the article…

Cheers
Rick

2 Likes

Thanks @ylv-io. I’ll work my way through those links. It would be really great to eventually have some sample code which can help to outline a working project. But I’m sure that will come in time!

Cheers
Rick

3 Likes

@roy.batty any chance you are still using a truffle version between 5.0.13 and 5.0.19, and haven’t cleaned out artifacts and recompiled your contracts? That looks an awful lot like a messed up ABI, where web3 is trying to cast the result of name to a number instead of a string.

2 Likes

Good idea! We’ll probably update this article to the latest versions of zOS in the upcoming months, and we can add that section when we do so. Thanks!

2 Likes

Great, thanks! Looking forward to the new docs!

1 Like

@spalladino - I think you may have been correct. Something was up with my versions somewhere, I blitzed the directory and started again… I don’t get that issue anymore… Thanks!

2 Likes

I did get another issue later on though when I try to push the udpated contract back to the rinkeby network:

$ npx zos push                                                                        
Compiling contracts with Truffle...

Compiling your contracts...
===========================
> Compiling ./contracts/CustomERC20.sol
> Compiling openzeppelin-eth/contracts/math/SafeMath.sol
> Compiling openzeppelin-eth/contracts/token/ERC20/ERC20.sol
> Compiling openzeppelin-eth/contracts/token/ERC20/ERC20Burnable.sol
> Compiling openzeppelin-eth/contracts/token/ERC20/ERC20Detailed.sol
> Compiling openzeppelin-eth/contracts/token/ERC20/IERC20.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to .../zos-upgrade-test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang

Using session with network rinkeby-test, sender address 0xED609586F5bE1ADc8d3f9f5a7cEA8Dab45a42A53, timeout 3600 seconds
Deploying openzeppelin-eth contracts
Deploying new Package...
Failed deployment of dependency openzeppelin-eth with error: Returned error: Exceeds block gas limit

Should I have to change some other settings somewhere?

1 Like

Hi @roy.batty

Sorry that you are having issues.

Can you share your hash of the failed transaction?

Also what is in your truffle-config.js for your rinkeby-test network?

1 Like

Hi @abcoathup, I think there is no tx has if there is a block gas limit error?

My truffle-config.js is:

const HDWalletProvider = require('truffle-hdwallet-provider');
const mnemonic = 'tooth paper ...';
const infuraToken = 'bf9c...';

module.exports = {
  networks: {
    rinkeby: {
      provider: new HDWalletProvider(mnemonic, 'https://rinkeby.infura.io/v3/' + infuraToken, 1, 5),
      network_id: 4
    },
    "rinkeby-test": {
      host: 'localhost',
      port: 9545,
      network_id: "1004",
      gasPrice: 10e9,
      gas: 10000000000
    }
  }
}
1 Like

Hi @roy.batty, I was able to run npx zos push (though I need to redo the process tomorrow, as I need to change my admin account).

My network settings in my truffle-config.js are as follows:

    "rinkeby-test": {
        host: 'localhost',
        port: 9545,
        network_id: 1004,
        gasPrice: 10e9,
        gas: '50000'
    },
    rinkeby: {
      provider: new HDWalletProvider(mnemonic, 'https://rinkeby.infura.io/v3/' + infuraToken, 0, 5),
      network_id: 4
    }  

Your gas level is higher than ganache gas limit 6,721,975. I don’t know if this is the issue?


As an aside, suggest if you haven’t already, move any secrets out of the truffle-config.js to avoid the risk of them getting committed accidently.
e.g. Use .env and then add .env to .gitignore.

truffle-config.js:

// truffle-config.js
require('dotenv').config();

const HDWalletProvider = require('truffle-hdwallet-provider');

const infuraToken = process.env.INFURA_API_KEY;

const mnemonic = process.env.DEV_MNEMONIC;

.env file:

INFURA_API_KEY="PUT KEY HERE"
DEV_MNEMONIC="12 word seed phrase ..."
1 Like

Thanks @abcoathup… I updated my configs and started again… everything seems to work fine now as according to the article. The contract is successfully updated and the contract storage is also correctly corrupted :slight_smile:

1 Like