这篇文章将为大家详细讲解有关以太坊区块链如何使用NodeJs、Web3开发投票DApp,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
用户可以查看到当前参与投票的候选人名单已经他们各自的目前所得票数,选择其中一名进行投票,被投票的人所得票数对应增加。
本地NodeJs环境
Ganache测试环境
熟悉基础的Web3-Api操作,安装命令为: npm install web3@^0.20.0 --save
NodeJs安装Solc编译环境,安装命令为:npm install sol
期间遇坑,安装Windows构建工具,安装命令为:npm install --global --production windows-build-tools
python27
创建工作目录 Voting-Node,在此目录下新建 Voting.sol 智能合约文件,并在Remix中对此文件进行编辑,最后编辑完成后的文件内容如下:
pragma solidity ^0.4.18; contract Voting { mapping (bytes32 => uint8) public votesReceived; bytes32[] public candidateList; constructor (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 < candidateList.length; i++) { if (candidateList[i] == candidate) { return true; } } return false; } }
在Voting-Node目录打开命令行并输入node 命令,可以进入REPL环境,分步执行编译部署命令,不过这种方式比较麻烦,不方便维护和修改,此处直接在Voting-Node目录中编写好了一个编译、部署、测试 的 depoy.js文件,直接在Nodejs中运行就可以看到结果,内容如下:
//引入web3模块 let Web3 = require('web3'); //初始化 web3 let web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:7545")); //输出初始化结果 console.log('Initialization web3 complete,the first account is '+ web3.eth.accounts[0]); let fs = require('fs'); let code = fs.readFileSync('Voting.sol').toString(); let solc = require('solc'); //编译合约为ABI文件 let compiledCode = solc.compile(code); console.log('Compile Voting.sol complete'); //部署合约至区块链节点 let abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface); //写入ABI文件至本地文件目录 fs.writeFile('Voting.json',JSON.stringify(abiDefinition), {}, function(err) { console.log('write ABI file [Voting.json] complete . '); }); let VotingContract = web3.eth.contract(abiDefinition); let byteCode = compiledCode.contracts[':Voting'].bytecode; //调用VotingContract对象的new()方法来将投票合约部署到区块链。new()方法参数列表应当与合约的 构造函数要求相一致。对于投票合约而言,new()方法的第一个参数是候选人名单。 let deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000}); //输出合约 地址,如果此处没有返回地址,可以在Ganache日志中查看到 console.log('deploy complete,deploy address is '+ deployedContract.address); //let contractInstance = VotingContract.at(deployedContract.address); let contractInstance = VotingContract.at('0xa167fddc1c6d3d6187a748947b8f00b0dc4fc8db');///这里改为你自己的deployedContract.address //测试合约调用 contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Nick', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Jose', {from: web3.eth.accounts[0]}); contractInstance.voteForCandidate('Jose', {from: web3.eth.accounts[0]}); console.log("--------------finish----------------"); let RamaVote=contractInstance.totalVotesFor.call('Rama'); let NickVote=contractInstance.totalVotesFor.call('Nick'); let JoseVote=contractInstance.totalVotesFor.call('Jose'); console.log("Rama's vote is "+RamaVote); console.log("Nick's vote is "+NickVote); console.log("Jose's vote is "+JoseVote);
在完成上面的编写、编译、部署、测试环节后,添加网页交互那就很简单了。
在Voting-Node目录 打开命令行,执行初始化命令,如下:
npm init -y
会在此目录下生成 package.json 文件,修改此文件内容如下:
{ "name": "Voting-Node", "version": "1.0.0", "description": "", "main": "index.js", "dependencies": { "solc": "^0.4.23", "web3": "^0.19.0" }, "devDependencies": {}, "scripts": { "dev": "node index.js" }, "keywords": [], "author": "Ruoli", "license": "ISC" }
在目录下新建 index.js 、 index.html、app.js 文件,如下所示。
index.js 内容如下:
var express = require('express'); var app = express(); var server = require('http').createServer(app); var Web3 = require("web3"); app.use(express.static('.')); let web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545")); //这里导入你自己的ABI let abi = JSON.parse('[{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]') let VotingContract = web3.eth.contract(abi); //这里要替换成你自己的地址 let contractInstance = VotingContract.at('0xcadcaf0cf38ad0adc259b8426b723bb31faa899d'); app.get("/totalVotesFor", function(req, res) { var voteName = req.query.voteName; var vote_num=contractInstance.totalVotesFor.call(voteName).toString(); console.log(vote_num); res.send(vote_num); }); app.get("/voteForCandidate", function(req, res) { var voteName = req.query.voteName; contractInstance.voteForCandidate(voteName, {from: web3.eth.accounts[0]}); var vote_num=contractInstance.totalVotesFor.call(voteName).toString(); res.send(vote_num); }); server.listen(3000); // 控制台会输出以下信息 console.log('Server running at http://127.0.0.1:3000/index.html');
index.html 内容如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Voting DApp</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" > <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <style type="text/css"> .vote-row{ margin-top: 45px; margin-bottom: 45px; } .vote-person{ height: 150px; width: 150px; border: 1px solid #ccc; border-radius: 10px; margin:0 auto; } .vote-person:hover{ background-color: #eee; } .vote-btn{ margin-top: 14px; width:100%; border-radius: 10px; border-top-left-radius:0em; border-top-right-radius:0em; } .vote-name{ font-size: 18px; margin-top:7px; } .vote-num{ width:50px; height:50px; border: 1px solid #ccc; border-radius: 50%; text-align: center; margin:10px auto 6px auto; padding-top: 10px; font-size: 18px; } </style> </head> <body class="container"> <h3 class="text-center">简易投票 DApp</h3> <div class="row vote-row"> <div class="col-md-3 col-md-offset-1"> <div class="vote-person"> <div class="text-center vote-name">Rama</div> <div id="candidate-1" class="text-center vote-num"></div> <a href="#" class="btn btn-primary vote-btn">为TA投票</a> </div> </div> <div class="col-md-3"> <div class="vote-person"> <div class="text-center vote-name">Nick</div> <div id="candidate-2" class="text-center vote-num"></div> <a href="#" class="btn btn-primary vote-btn">为TA投票</a> </div> </div> <div class="col-md-3"> <div class="vote-person"> <div class="text-center vote-name">Jose</div> <div id="candidate-3" class="text-center vote-num"></div> <a href="#" class="btn btn-primary vote-btn">为TA投票</a> </div> </div> </div> </body> <!--<script src="./web3.js"></script>--> <script src="./app.js"></script> </html>
app.js 内容如下:
注意:此处需要将之前保存的 ABI文件内容引入。
let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"} $(document).ready(function() { //初始化余额 candidateNames = Object.keys(candidates); for (var i = 0; i < candidateNames.length; i++) { let voteName = candidateNames[i]; totalVotesFor(voteName); } //初始化事件 $(".vote-btn").click(function(){ //获取投票人名称 let voteName=$(this).prev().prev().text(); voteForCandidate(voteName); }); }); function totalVotesFor(voteName) { $.get("/totalVotesFor?voteName=" + voteName, function(data) { if(data == "Error") { alert('提示', '500'); } else { $("#"+candidates[voteName]).html(data); } }); } function voteForCandidate(voteName) { $.get("/voteForCandidate?voteName=" + voteName, function(data) { if(data == "Error") { alert('提示', '500'); } else { let div_id = candidates[voteName]; var vote_num = totalVotesFor(voteName); $("#"+div_id).html(data);//.fadeIn(800); $("#"+div_id);//.fadeOut(400); } }); }
至此所有开发已经完成。
执行如下命令启动服务:
PS C:\Workspace\Ruoli-Code\Voting-Node> npm run dev > Voting-Node@1.0.0 dev C:\Workspace\Ruoli-Code\Voting-Node > node index.js Server running at http://127.0.0.1:3000/index.html
执行完成后 在浏览器中 访问:http://127.0.0.1:3000/index.html
即可看到最开始的界面,至此所有开发完成。
关于“以太坊区块链如何使用NodeJs、Web3开发投票DApp”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。