如何编写一个可升级的智能合约

区块链信任基础的数据不可修改的特性,让它传统应用程序有一个很大的不同的地方是一经发布于区块链上就无法修改(不能直接在原有的合约上直接修改再重新发布)。

写在前面

阅读本文前,你应该对以太坊、智能合约及Solidity语言有所了解,如果你还不了解,建议你先看《以太坊是什么》

当智能合约出现bug

一方面正式由于智能合约的不可修改的特性,因为只要规则确定之后,没人能够修改它,大家才能够信任它。但另一方面,如果规则的实现有Bug, 可能会造成代币被盗,或是调用消耗大量的gas。这时就需要我们去修复错误。

我们知道一个智能合约包含两部分: 代码逻辑和数据,而代码逻辑又是最容易出问题的部分, 如在实现如下合约时,由于手抖在写addTen()时,10写成了11。

pragma solidity ^0.4.18;

contract MyContract {
    mapping (address => uint256) public balanceOf;

    function setBlance(address _address,uint256 v) public {
        balanceOf[_address] = v;
    }

    function addTen(address addr) public returns (uint){
        return balanceOf[addr] + 11;
    }
}

假如我们在部署之后发现了这个问题,想要修复这个bug的话,只好重新部署合约,可是这时会有一个尴尬的问题,原来的合约已经有很多人使用,如果部署新的合约,老合约的数据将会丢失。

数据合约及控制合约

那么如何解决上面的问题了,一个解决方案是分离合约中的数据,使用一个单独的合约来存储数据(下文称数据合约),使用一个单独的合约写业务逻辑(下文称控制合约)。
我们来看看代码如何实现。

pragma solidity ^0.4.18;

contract DataContract {
    mapping (address => uint256) public balanceOf;

    function setBlance(address _address,uint256 v) public {
        balanceOf[_address] = v;
    }
}

contract ControlContract {

    DataContract dataContract;

    function ControlContract(address _dataContractAddr) public {
        dataContract = DataContract(_dataContractAddr);
    }

    function addTen(address addr) public returns (uint){
        return dataContract.balanceOf(addr) + 11;
    }
}

现在我们有两个合约DataContract 专门用来存数据,ControlContract用来处理逻辑,并利用DataContract来读写数据。通过这样的设计,可以在更新控制合约后保持数据合约不变,这样就不会丢失数据,也不用迁移数据。

top Created with Sketch.