如何編寫一個可升級的智能合約

如何編寫一個可升級的智能合約app

區塊鏈信任基礎的數據不可修改的特性,讓它傳統應用程序有一個很大的不一樣的地方是一經發佈於區塊鏈上就沒法修改(不能直接在原有的合約上直接修改再從新發布)。學習

寫在前面
閱讀本文前,你應該對以太坊、智能合約及Solidity語言有所瞭解,若是你還不瞭解,建議你先看以太坊是什麼區塊鏈

當智能合約出現bug
一方面正式因爲智能合約的不可修改的特性,由於只要規則肯定以後,沒人可以修改它,你們纔可以信任它。但另外一方面,若是規則的實現有Bug, 可能會形成代幣被盜,或是調用消耗大量的gas。這時就須要咱們去修復錯誤。測試

咱們知道一個智能合約包含兩部分: 代碼邏輯和數據,而代碼邏輯又是最容易出問題的部分, 如在實現以下合約時,因爲手抖在寫addTen()時,10寫成了11。ui

pragma solidity ^0.4.18;設計

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

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

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

}
假如咱們在部署以後發現了這個問題,想要修復這個bug的話,只好從新部署合約,但是這時會有一個尷尬的問題,原來的合約已經有不少人使用,若是部署新的合約,老合約的數據將會丟失。orm

數據合約及控制合約
那麼如何解決上面的問題了,一個解決方案是分離合約中的數據,使用一個單獨的合約來存儲數據(下文稱數據合約),使用一個單獨的合約寫業務邏輯(下文稱控制合約)。
咱們來看看代碼如何實現。部署

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來讀寫數據。經過這樣的設計,能夠在更新控制合約後保持數據合約不變,這樣就不會丟失數據,也不用遷移數據。

讀寫控制
經過DataContract咱們能夠單獨更新合約邏輯,不過你也許發現了一個新的問題,DataContract的數據不單單能夠被ControlContract讀寫,還能夠被其餘的合約讀寫,所以須要對DataContract添加讀寫控制。咱們給DataContract添加一個mapping, 用來控制哪些地址能夠訪問數據,同時添加了修飾器及設置訪問的方法,代碼以下:

pragma solidity ^0.4.18;

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

function DataContract() public {
    accessAllowed[msg.sender] = true;
}

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

modifier platform() {
    require(accessAllowed[msg.sender] == true);
    _;
}

function allowAccess(address _addr) platform public {
    accessAllowed[_addr] = true;
}

function denyAccess(address _addr) platform public {
    accessAllowed[_addr] = false;
}

}

...
訂閱個人小專欄可參看合約的完整代碼。

部署方法以下:

先部署DataContract合約
使用DataContract合約地址做爲部署ControlContract合約的參數
用ControlContract合約地址做爲參數調用DataContract合約的allowAccess方法。
若是須要更新控制合約(如修復了addTen)則從新執行第2-3步,同時對老的控制合約執行denyAccess()。
更多
當咱們在實現數據合約時,它包含的邏輯應該越少越好,而且應該是嚴格測試過的,由於一旦數據合約部署以後,就無法更改。
大多數狀況下,和用戶交互的是DApp, 所以當控制合約升級以後,須要升級DApp,使之關聯新的控制合約。

儘管合約能夠經過本文的方式升級,但咱們依然要謹慎升級,由於升級表示你能夠重寫邏輯,會下降用戶對你的信任度。
本文介紹升級方法更多的是一種思路,實際項目中可能會對應多個控制合約及數據合約。

歡迎來個人知識星球討論區塊鏈技術。

深刻淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客。

相關文章
相關標籤/搜索