第一个区块链投票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充当的是一个桥梁作用,当我我们需要用到签名时,他会出现一个签名的界面让你确认,如下图:
其实就是一个轻钱包。