Interfaces make your Solidity contracts upgradeable
This blog post talks about two problems common to all Ethereum smart contracts — upgradeability and block gas limit. The idea presented here builds upon this excellent blog post by Elena Dimitrova of Colony. Please read it before proceeding further.
The EternalStorage idea presented by Elena works very well because you can have newer versions of your contract talk to the same EternalStorage. However, upgrading the organisation requires upgrading the parent contract as well. This is due to the fact that the Parent contract (reproduced below) is coded to a specific implementation of the Organisation contract.
Shortcomings of the original solution
The “upgradeOrganisation” function doesn’t work since any new instance of organisation will have the exact same blueprint as the original organisation. The bytecode of the Organisation contract was deployed along with the Parent contract, so the Parent contract knows of only that specific implementation of the Organisation contract. This implies that in order to upgrade the contract, you need to upgrade the Parent contract as well. In the above implementation, the Parent contract is not upgradeable but it can be easily made so by storing the organisation mapping in the EternalStorage as well. Redeploying the Parent contract would obviously change the contract address with which your users interact. Hence, this upgrade is not transparent to the users.
This approach also does not address the block gas limit issue during deployment since all components need to be deployed in the same transaction.
An alternative solution is to create an Organisation interface and code the Parent to the interface instead.
The Parent contract can then be deployed independent of the Organisation contract. Hence, these two contracts can be deployed in separate transactions, each with a lower gas requirement than the gas required for deploying the entire set of contracts. This alleviates the block gas limit issue.
Newer implementations of the Organisation contract can be instantiated and passed on to the modified “upgradeOrganisation” function to retain the original data. The Parent contract does not need to be redeployed in order to upgrade an organisation. This upgrade procedure is transparent to the users of the contract.
A side-effect of this separation is that the Parent contract can no longer instantiate the Organisation contract. The owners or the admins of the contracts are responsible for instantiating the organisation and using Parent to register or upgrade it. This seems to be a fair tradeoff for the benefits it provides — transparent upgradeability and lower gas requirement per block.
While there are a few other approaches to make your contracts upgradeable, this one is simple to understand and easy to implement, and addresses both upgradeability and block gas limit issues. We have used this solution in an internal app at my organisation.
The updated code is embedded below. To see how these contracts are used with Truffle, see this GitHub repo.