這篇文章主要介紹“怎么在區(qū)塊鏈上開發(fā)可更新的智能合約”,在日常操作中,相信很多人在怎么在區(qū)塊鏈上開發(fā)可更新的智能合約問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么在區(qū)塊鏈上開發(fā)可更新的智能合約”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

在濱湖等地區(qū),都構建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務理念,為客戶提供網(wǎng)站設計、成都網(wǎng)站制作 網(wǎng)站設計制作按需設計,公司網(wǎng)站建設,企業(yè)網(wǎng)站建設,成都品牌網(wǎng)站建設,成都全網(wǎng)營銷推廣,成都外貿(mào)網(wǎng)站制作,濱湖網(wǎng)站建設費用合理。
由于區(qū)塊鏈不可篡改的特性,智能合約一旦部署在區(qū)塊鏈上,其執(zhí)行的邏輯就無法再更改。長期來看,這個重要的特性反而限制了智能合約的彈性和發(fā)展。
接下來要介紹如何設計及部署合約才能讓合約在需要時可以更新。但這里的更新意思不是修改已經(jīng)部署的合約,而是部署新的合約、新的執(zhí)行邏輯但同時能繼續(xù)利用已經(jīng)存在的資料。
首先要知道的是Ethereum Virtual Machine(EVM)要知道如何執(zhí)行合約的那個函數(shù)。合約最后都會被編譯成字節(jié)碼,而你發(fā)起一個transaction要執(zhí)行合約里的某個函數(shù)時,交易里的數(shù)據(jù)同樣也是字節(jié)碼,而不是人看得懂的函數(shù)名稱。 以一個簡單的合約為例:
contract Multiply {
function multiply(int x, int y) constant returns(int) {
return x*y;
}
}編譯完的二進制碼:
6060604052341561000c57fe5b5b60ae8061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633c4308a814603a575bfe5b3415604157fe5b605e60048080359060200190919080359060200190919050506074565b6040518082815260200191505060405180910390f35b600081830290505b929150505600a165627a7a72305820c40f61d36a3a1b7064b58c57c89d5c3d7c73b9116230f9948806b11836d2960c0029
如果你要執(zhí)行multiply函數(shù),算出8*7等于多少,你的transaction里的數(shù)據(jù)是 0x3c4308a800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000007
分成三部分: 第一個是四個字節(jié)的3c4308a8,第二和第三個分別是32個字節(jié)長的參數(shù),8和7。
3c4308a8是multiply函數(shù)的signature(簽名),是取函數(shù)名稱和參數(shù)類型使用sha3取前四個byte而得到(不包含0x):
sha3("multiply(int256,int256)"));
//0x3c4308a8851ef99b4bfa5ffd64b68e5f2b4307725b25ad0d14040bdb81e3bafc sha3("multiply(int256,int256)")).substr(2,8);
//3c4308a8EVM就是靠函數(shù)的signature來知道該執(zhí)行那個函數(shù)的。在合約編譯完的字節(jié)碼里查詢也能找到這個signature。
接下來要介紹Solidity里的三種調(diào)用方式:call、callcode和delegatecall。
call:一般的調(diào)用都是這種方式,執(zhí)行背景跳到下一個函數(shù)的環(huán)境(這里的環(huán)境是指msg的值和合約的Storage)。如果被調(diào)用的是不同合約的函數(shù)那么變換成被調(diào)用的合約的環(huán)境,且msg.sender編程調(diào)用者。
callcode:和call相同,只是將被調(diào)用函數(shù)搬到調(diào)用者的環(huán)境里執(zhí)行。
假設A合約的x函數(shù)用callcode方式調(diào)用B合約的y函數(shù),就會在A合約里執(zhí)行y函數(shù),使用A的參數(shù),所以如果y函數(shù)里修改某個參數(shù)的值且這個參數(shù)的名稱剛好和A的某個參數(shù)名稱一致,則A的該參數(shù)就會被修改。就把它想像成A多了一個y函數(shù)并執(zhí)行。
delegatecall:和callcode相同,都是把被調(diào)用的函數(shù)搬到調(diào)用者的環(huán)境里執(zhí)行,只是在msg.sender的值上有區(qū)別。
來看一個例子:加入A合約用delegatecall的方式調(diào)用B合約的函數(shù),B合約的函數(shù)接下用callcode或call的方式調(diào)用C合約的函數(shù),那么函數(shù)里看到的msg.sender會是B;但如果B改用delegatecall的方式調(diào)用C合約的函數(shù)的話,那么函數(shù)里看到的msg.sender會是A。就把它想像成把msg相關的值保持不變傳遞下去就ok了。
接下來實際來看一下delegatecall的效果:
contract Plus {
int z;
function plus(int x, int y) {
z = x+y;
}
}
contract Multiply {
int public z;
function multiply(int x, int y) {
z = x*y;
}
function delegateToPlus(address _plus, int x, int y) {
_plus.delegatecall( bytes4(sha3("plus(int256,int256)")) ,x ,
y);
}
}部署并按順序執(zhí)行Multiply的multiply和delegateToPlus并觀察z值的變化:
可以看到執(zhí)行delegatecall之后z的值變成是8+7。 所以如果要讓我們未來可以改變執(zhí)行邏輯的話怎么寫代碼呢?
contract Plus {
int z;
function plus(int x, int y) { //sig:"0xccf65503"
z = x+y;
}
}
contract Multiply {
int z;
function multiply(int x, int y) { //sig:"0x3c4308a8"
z = x*y;
}
}
contract Main {
int public z;
function delegateCall(address _dest, bytes4 sig, int x, int y) {
_dest.delegatecall(sig, x , y);
}
}我們將合約的地址和函數(shù)的signature當做參數(shù)傳遞給delegateCall去執(zhí)行,假設原本是用Plus合約的執(zhí)行路基,現(xiàn)在我們更新成Multiply合約:
0x4429 是Plus合約的地址, 0xe905 是Multiply合約的地址。
我們以后只要給它改變后的函數(shù)signature和合約地址就可以使用新的執(zhí)行邏輯了!
但如果合約不是只給一個人使用的話,應當在更新合約的時候所有參與的人都必須要更新新合約的位置。這時候可以用一個合約來幫助我們導到新的合約位置,就像路由器似的,我們統(tǒng)一發(fā)送(還是以delegatecall的形式)到路由合約,再由路由合約幫我們導到正確的位置,未來更新合約就只需要更新路由合約的資料即可。
contract Upgrade {
mapping(bytes4=>uint32) returnSizes;
int z;
function initialize() {
returnSizes[bytes4(sha3("get()"))] = 32;
}
function plus(int _x, int _y) {
z = _x + _y;
}
function get() returns(int) {
return z;
}
}
contract Dispatcher {
mapping(bytes4=>uint32) returnSizes;
int z;
address upgradeContract;
address public dispatcherContract;
function replace(address newUpgradeContract) {
upgradeContract = newUpgradeContract;
upgradeContract.delegatecall(bytes4(sha3("initialize()")));
}
function() {
bytes4 sig;
assembly { sig := calldataload(0) }
var len = returnSizes[sig];
var target = upgradeContract;
assembly {
calldatacopy(mload(0x40), 0x0, calldatasize)
delegatecall(sub(gas, 10000), target, mload(0x40),
calldatasize, mload(0x40), len)
return(mload(0x40), len)
}
}
}
contract Main {
mapping(bytes4=>uint32) public returnSizes;
int public z;
address public upgradeContract;
address public dispatcherContract;
function deployDispatcher() {
dispatcherContract = new Dispatcher();
}
function updateUpgrade(address newUpgradeContract) {
dispatcherContract.delegatecall(
bytes4( sha3("replace(address)")), newUpgradeContract
);
}
function delegateCall(bytes4 _sig, int _x, int _y) {
dispatcherContract.delegatecall(_sig, _x, _y);
}
function get() constant returns(int output){
dispatcherContract.delegatecall(bytes4( sha3("get()")));
assembly {
output := mload(0x60)
}
}
}執(zhí)行順序:
1. 執(zhí)行Main.deployDispatcher() 部署路由合約
2. 部署upgrade合約并將其address當做Main.updateUpgrade()的參數(shù)傳入用來更新upgrade合約的地址資料。
3. 執(zhí)行Main.delegateCall(),參數(shù)是plus(int256,int256)的signature和任意兩個值。
4. 執(zhí)行Main.get(),由delegatecall去調(diào)用upgrade合約的get函數(shù),回傳相加完的z值。因為是delegatecall,所以這個z值其實是Main合約自己的,upgrade合約的z值是零。
如果delegatecall調(diào)用的函數(shù)有返回值的話,必須要用assembly來手動獲得返回值,因為delegatecall和call一樣,只會回傳true of false來代表執(zhí)行是否成功。Dispatcher在調(diào)用是同樣也是用assembly code。
但因為是用assembly手動獲得返回值,因此前提是返回值的長度必須是固定且已知的,所以當我們在步驟2更新upgrade合約時,Dispatcher合約同時去調(diào)用upgrade合約的initialize()函數(shù),upgrade合約在initialize函數(shù)里將它所有會有返回值的函數(shù)的返回值大小寫入returnSizes中,之后如果調(diào)用具有返回值的函數(shù)時,Dispatcher就知道返回值的大小了。
這個還有一個重點是參數(shù)定義的順序
因為合約執(zhí)行要用參數(shù)值的時候,它會到對應的Storage位置去找。所以如果你的合約參數(shù)定義像這樣子
upgrade:
int x
int y
?—?—?—?—
Dispathcer:
int x
int y
?—?—?—?—
Main:
int x
int abc
int y
當upgrade合約的函數(shù)需要用到x和y的值的時候,它會找不到y(tǒng),因為Storage是Main的。
到此,關于“怎么在區(qū)塊鏈上開發(fā)可更新的智能合約”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
網(wǎng)站名稱:怎么在區(qū)塊鏈上開發(fā)可更新的智能合約
網(wǎng)站URL:http://chinadenli.net/article18/pgjogp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供建站公司、自適應網(wǎng)站、、云服務器、Google、品牌網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)