如何在以太坊上搭建一個Dapp?對于開發人員來說,最好的學習辦法就是親自動手做一個小項目。所以,接下來將會以一個投票程序為例,帶著你在以太坊平臺上搭建一個dapp,并且通過借助這樣一個例子介紹Dapp的編譯、部署及交互過程。
這個程序的功能很簡單,只是設定一組候選項,讓所有人都可以給這些候選項投票,以及顯示每個候選項收到的總票數。
事先說明,因為所有dapp框架都會隱藏掉一些底層細節,對初學者來說,貿然使用框架可能會形成對系統認識上的障礙,所以本文不會介紹如何借助框架搭建dapp。這樣等將來需要甄選框架時,你也能清楚地看到框架到底幫你做了什么。
首先,準備開發環境,學習在開發環境中的合約編寫、編譯和部署流程,通過node.js控制臺與區塊鏈上的合約交互,通過一個簡單的網頁與合約交互,在頁面上提供投票功能并顯示候選項及相應的票數。
整個程序的開發都是在一臺干凈的ubuntu 16.04 xenial上完成的。除此之外,我還在一臺macos上重復了一遍搭建和測試過程。
準備開發環境
按web開發的說法,真實區塊鏈(live blockchain)相當于生產環境,我們自然不應該在生產環境上做開發,因此本文用了一個名為ganache的內存區塊鏈(相當于區塊鏈模擬器)。本教程的第二篇文章才會跟真正的區塊鏈交互。
下面是在linux操作系統上安裝ganache和web3js,以及啟動測試區塊鏈的步驟。在macos上可以用同樣的命令。windows系統可以參照這里的命令。
注意:ganache-cli會創建10個自動參與交易的測試賬號,每個賬號里都預存了100個以太幣(當然,只能用于測試),區塊鏈DAPP項目開發,DAPP系統開發模式源碼,DAPP錢包系統搭建技術。
簡單的投票合約
接下來我們要用Solidity編程語言編寫合約。如果你熟悉面向對象編程,就會覺得這個學起來很輕松。
我們要編寫一個名為Voting的合約(相當于OOP語言中的類)。這個合約中會有個構造器,負責初始化一個包含候選項的數組;還會有兩個方法,一個用于返回指定候選項的總票數,另一個給候選項的得票數加一。
注意:在將合約部署到區塊鏈上時,構造器會執行,并且只會執行這一次。在做web應用時,每次重新部署都會覆蓋掉原來的代碼,但部署到區塊鏈上的代碼是不可變的。也就是說,即便你更新了合約,又重新部署了一次,之前的合約仍然會原封不動地留在區塊鏈上,并且其中存儲的數據也不會受到絲毫影響,新部署的代碼會創建一個全新的合約實例。
下面是帶有注釋的投票合約代碼:
pragma solidity^0.4.18;
//必須指明編譯這段代碼的編譯器版本
contract Voting{
/*下面這個mapping域相當于一個關聯數組或哈希。
mapping的鍵是候選項的名字,類型為bytes32;
值的類型是無符號整型,用于存儲得票數。
*/
mapping(bytes32=>uint8)public votesReceived;
/*Solidity(還)不允許給構造器傳入字符串數組。
所以我們用bytes32數組存儲候選項
*/
bytes32[]public candidateList;
/*這就是把合約部署到區塊鏈上時會執行一次的構造器。
在部署合約時,我們會傳入一個包含候選項的數組。
*/
function Voting(bytes32[]candidateNames)public{
candidateList=candidateNames;
}
//這個函數用于返回指定候選項的總票數,其參數即為指定候選項
function totalVotesFor(bytes32 candidate)view public returns(uint8){
require(validCandidate(candidate));
return votesReceived[candidate];
}
//這個函數用于將指定候選項的票數加一
//這相當于實現了投票功能
function voteForCandidate(bytes32 candidate)public{
require(validCandidate(candidate));
votesReceived[candidate]+=1;
}
function validCandidate(bytes32 candidate)view public returns(bool){
for(uint i=0;i
if(candidateList==candidate){
return true;
}
}
return false;
}
}
部署區塊鏈
將上面的代碼保存到Voting.sol文件中,放在hello_world_voting目錄下。接下來我們要編譯這段代碼,并將它部署到ganache區塊鏈上。
在編譯Solidity代碼之前,需要先安裝npm模塊solc。我們會在node控制臺中用這個庫編譯合約。
首先,在終端中運行node命令進入node控制臺,初始化solc和web3對象。下面是需要在node控制臺中輸入的代碼:
mahesh projectblockchain:~/hello_world_voting$node
>Web3=require('web3')
>web3=new Web3(new Web3.providers.HttpProvider
為了確保web3對象初始化成功,可以跟區塊鏈通訊,我們可以查詢一下區塊鏈上的所有賬號。
為了編譯合約,需要先加載文件Voting.sol中的代碼,并將其賦值給一個字符串變量,然后再編譯這個字符串。
>code=fs.readFileSync('Voting.sol').toString()
>solc=require('solc')
>compiledCode=solc.compile(code)
代碼編譯成功后,可以在node終端中輸入compiledCode命令查看contract對象,有兩個域非常重要,一定要搞明白:compiledCode.contracts[‘:Voting’].bytecode:這是Voting.sol中的代碼編譯而成的字節碼,也是要部署到區塊鏈上的代碼。compiledCode.contracts[‘:Voting’].interface:這是合約的接口或者說模板(稱為abi),告訴合約的用戶有哪些方法可用。將來不管什么時候要跟合約交互,都需要這個abi定義。這里有關于ABI的詳細介紹。
部署合約
先創建一個在區塊鏈中部署和初始化合約的合約對象(即下面的VotingContract)。
>abiDefinition=JSON.parse(compiledCode.contracts[':Voting'].interface)
>VotingContract=web3.eth.contract(abiDefinition)
>byteCode=compiledCode.contracts[':Voting'].bytecode
>deployedContract=VotingContract.new(['Rama','Nick','Jose'],{data:byteCode,from:web3.eth.accounts[0],gas:
4700000})
>deployedContract.address
>contractInstance=VotingContract.at(deployedContract.address)
上面代碼中的VotingContract.new將合約部署到區塊鏈上。它的第一個參數是包含候選項的數組,一看就能明白。第二個參數中各數據項的含義分別為:data:這是已編譯好要部署到區塊鏈上的字節碼。from:區塊鏈必須追蹤是誰部署的合約。在這個例子中,我們只是調用了web3.eth.accounts,然后將返回結果的第一個賬號作為這個合約的所有者(即將合約部署到區塊鏈上的賬號)。
記住,web3.eth.accounts返回的是ganche在啟動測試區塊鏈時創建的10個測試賬號組成的數組。然而在真實的區塊鏈中,不能隨便指定一個賬號。那必須是你擁有的賬號,并且在交易之前要解鎖那個賬號。在創建賬號時,系統會要求你提供一個口令,這個口令就是用來證明你對賬號的所有權的。為了用起來方便,Ganache默認把10個賬號全解鎖了。
gas:跟區塊鏈交互是要花錢的。為了把你的代碼放到區塊鏈上,是需要讓礦機干活的,這筆錢就是給那些付出計算力的礦機的。
你必須明確愿意為此支付多少錢,即給‘gas’一個值。購買燃料的以太幣是從你的from賬號中出的。燃料的價格是由網絡設定的。合約部署好之后,我們就可以跟合約的實例(即上面的變量contractInstance)交互了。區塊鏈上有成百上千個合約,怎么確定哪個是你的呢?答案是用deployedContract.address。在你必須跟合約交互時,需要這個部署地址和之前說過的那個abi定義。
審核編輯 黃昊宇
-
開發
+關注
關注
0文章
366瀏覽量
40811 -
區塊鏈智能合約
+關注
關注
4文章
426瀏覽量
11216
發布評論請先 登錄
相關推薦
評論