
第一個區塊鏈投票DAPP
前言
本篇文章,將帶讀者用Truffle框架在ganache環境上

搭建一個屬于自己的投票DAPP雛形,你可以在這基礎上進行擴展。這里如果你對ganache不熟悉的可以使用testrpc環境也是一樣的。
開發包對應版本
web3.js v0.20.5
Truffle v4.1.3
Solidity v0.4.2
Ganache 1.1.0
初始化工程
這里我們需要提前安裝好 node 和 Truffle,如果不會的,可自行翻閱文檔,網上很多資料。
truffle unbox pet-shop
這個命令是通過 truffle 的 unbox 工具初始化一個寵物DAPP,我們這里偷個懶,在官方的 pet-shop 項目上進行修改。
編寫合約
在contracts文件夾下面新建一個 Election.sol 的合約文件,在這里我們進行合約編寫。

合約內容如下:
pragma solidity ^0.4.2;
contract Election {
//結構體
struct Candidate {
uint id;
string name;
uint voteCount;
} //事件
event votedEvent(
uint indexed _candidateId
); //存儲結構體
mapping (uint => Candidate) public candidates; //是否已經投票了
mapping (address=>bool) public voters; //總數量
uint public candidateCount; //構造函數
function Election () public {
addCandidate("張三);
addCandidate("李四);
} //添加候選人
function addCandidate(string _name) private {
candidateCount ++;
candidates[candidateCount] = Candidate(candidateCount, _name, 0);
} //投票
function vote(uint _candidateId) public { //過濾
require(!voters[msg.sender]);
require(_candidateId > 0 && _candidateId <= candidateCount);
//記錄用戶已經投票了
voters[msg.sender] = true;
candidates[_candidateId].voteCount ++;
votedEvent(_candidateId);
}
}
合約部分不贅述,如果有疑問可以留言。
部署合約
Truffle框架部署合約很簡單,可以通過他的 migration 功能直接部署。
var Election = artifacts.require("./Election.sol);
module.exports = function(deployer) {
deployer.deploy(Election);
};
這里說明下,如果你想偷懶,也可以直接在他下面的1_initial_migration.js文件里面導入Election.sol文件再加到 migration 里面。
truffle migrate --reset
就能部署好了。為啥要加 --reset 如果你的合約第一次部署,可以不加,如果是迭代覆蓋部署,就的加這個參數,好從新給你分配一個地址,否者會出現莫名其妙的問題,具體詳細介紹,請查閱官方文檔。
如果你這里使用的tesrpc環境,服務地址的端口是 8545 你需要去 修改下項目里面的 truffle.js文件里面的配置

編寫html頁面
由于我們是在 pet-shop 項目上進行修改的,所以我們只需要去修改 src/index.html 文件的內容就可以了。
我們把內容修改成如下內容:
區塊鏈投票
區塊鏈投票
Loading...
代碼很簡單,不用解釋應該都能看懂哈。
編寫js文件
js部分是DAPP比較麻煩的地方,也是最初學者迷惑的地方,我這里先把最終代碼粘貼過來再解釋:
App = {
web3Provider: null,
contracts: {},
account: '0x0',
init: function() { return App.initWeb3();
},
initWeb3: function() { if (typeof web3 !== 'undefined') {
App.web3Provider = web3.currentProvider;
console.warn("Meata);
}else{
App.web3Provider = new Web3.providers.HttpProvider('https://localhost:7545');
}
web3 = new Web3(App.web3Provider); return App.initContract();
},
initContract: function() {
$.getJSON("Election.json",function(election){
App.contracts.Election = TruffleContract(election);
App.contracts.Election.setProvider(App.web3Provider);
App.listenForEvents(); return App.reander();
})
},
reander: function(){ var electionInstance;
var $loader = $("#loader); var $content = $("#content);
$loader.show();
$content.hide(); //獲得賬號信息
web3.eth.getCoinbase(function(err,account){ if(err === null){
App.account = account;
$("#accountAddress).html("您當前的賬號: " + account);
}
}); //加載數據
App.contracts.Election.deployed().then(function(instance){
electionInstance = instance; return electionInstance.candidateCount();
}).then(function(candidatesCount)
{ var $candidatesResults = $("#candidatesResults);
$candidatesResults.empty();
var $cadidatesSelect = $("#cadidatesSelect);
$cadidatesSelect.empty(); for (var i=1;i<=candidatesCount;i++){
electionInstance.candidates(i).then(function(candidate)
{ var id = candidate[0]; var name = candidate[1];
var voteCount = candidate[2];
var candidateTemplate =
"";
$candidatesResults.append(candidateTemplate); //投票
var cadidateOption = ""+id+" | "+name+" | "+voteCount+" |
---|
其他的都是調取的web3.js提供的api,除了api之外我覺得最有必要解釋的是 App.contracts.Election.deployed().then(function(instance)... 這一串代碼,這是實例化Election合約后會調取后面then 里面的方法同時,把實例化的變量通過 instance 帶入到方法的參數里面。
同時在then里面有返回了一個方法 return instance.vote(candidateId,{from: App.account}); 這個方法又會執行,執行完后,又把執行的結果待會給下一個 then ,依次類推,這貌似是es6的鏈式語法。
如果我解釋得不太明白,可以留言。
運行起來
上面的代碼啥的一切準備就緒,現在只需要執行
npm run dev
項目就啟動了,由于需要和testrpc或者Ganache交互,所有我們需要用到 MetaMask 插件,所以得要用谷歌瀏覽器,打開我們的項目,同時需要MetaMask 插件連接到我們的測試環境。

就能看到出來的效果了。
如果對MetaMask不了解的,可以在網上查閱相關資料。這里我的理解是,在DAPP中MetaMask充當的是一個橋梁作用,當我我們需要用到簽名時,他會出現一個簽名的界面讓你確認,如下圖:

其實就是一個輕錢包。