简单投票DApp
Posted 是澜澜呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单投票DApp相关的知识,希望对你有一定的参考价值。
简单投票DApp
环境配置
-
预安装nodejs和npm
-
使用npm安装ganache-cli、web3@0.20.1、solc,各软件版本如下图。
-
运行
node_modules/.bin/ganache-cli
,出现下图即为成功,默认创建了10个账户,每个账户有100个以太。
编写合约
合约内容
- 候选人组
- 候选人组及其票数
- 构造函数:初始化候选人组
- 投票函数
- 得到某个候选人票数的函数
代码
//SPDX-License-Identifier: SimPL-2.0
pragma solidity >0.4.20;
contract Voting {
bytes32[] public candidateList;
mapping(bytes32 => uint8) votesReceived;
constructor(bytes32[] memory names) public {
//candidateList =[bytes32("Alice"),"Bob","Cary"];
candidateList = names;
}
function isCandidate(bytes32 candidateName) internal view returns(bool) {
for (uint8 i = 0; i < candidateList.length; i++) {
if(candidateName == candidateList[i]) {
return true;
}
}
return false;
}
function vote(bytes32 candidateName) public {
require(isCandidate(candidateName));
votesReceived[candidateName] += 1;
}
function getVotes(bytes32 candidateName) public view returns(uint8) {
require(isCandidate(candidateName));
return votesReceived[candidateName];
}
}
编译合约
在终端运行node,进入node控制台,同时确保ganache在另一个窗口运行。
var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'))
var solc = require('solc')
var sourceCode = fs.readFileSync('Voting.sol','utf8').toString()
var compileCode = solc.compile(sourceCode)
部署合约
var abi = JSON.parse(compileCode.contracts[':Voting'].interface);
var byteCode = compileCode.contracts[':Voting'].bytecode;
var votingContract = web3.eth.contract(abi);
var deployTxObj = {data:byteCode, from: web3.eth.accounts[0],gas:3000000};
var contractInstance = votingContract.new(['Alice','Bob','Cary'], deployTxObj);
合约部署成功后,在ganache会得到合约地址,如下图。
合约交互
为Alice投票,以及查看Alice的票数。
contractInstance.vote('Alice',{from:web3.eth.accounts[0]});
contractInstance.getVotes('Alice').toString();
contractInstance.getVotes.call('Alice').toString()
网页交互
vote.html
<!DOCTYPE html>
<html>
<head>
<title>投票DApp</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
</head>
<body class="container">
<h1>A Simple Voting Application</h1>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Candidate</th>
<th>Votes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td id="candidate-1"></td>
</tr>
<tr>
<td>Bob</td>
<td id="candidate-2"></td>
</tr>
<tr>
<td>Cary</td>
<td id="candidate-3"></td>
</tr>
</tbody>
</table>
</div>
<input type="text" id="candidate" />
<a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
</body>
<script src="https://cdn.jsdelivr.net/npm/web3@0.20.1/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="./vote.js"></script>
</html>
vote.js
运行solcjs --bin --abi Voting.sol
,得到Voting的abi和bin文件。复制abi文件中的内容粘贴到js文件中的abi代码行中。contractAddr的内容填入之前部署合约的地址。
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
var abi = JSON.parse('[{"inputs":[{"internalType":"bytes32[]","name":"names","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"candidateList","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"getVotes","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"candidateName","type":"bytes32"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]');
var contractAddr = '0xce3530dbc5e0c2b821fefd8d3043624adacae62c';
var votingContract = web3.eth.contract(abi);
var contractInstance = votingContract.at(contractAddr);
var candidates = {"Alice":"candidate-1", "Bob":"candidate-2", "Cary":"candidate-3"};
$(document).ready(function(){
var candidateList = Object.keys(candidates);
for (let i = 0; i < candidateList.length; i++) {
let name = candidateList[i];
let count = contractInstance.getVotes.call(name).toString();
$("#" + candidates[name]).html(count);
}
});
function voteForCandidate() {
let candidateName = $("#candidate").val();
try {
contractInstance.vote(candidateName, {from:web3.eth.accounts[0]},(err,res)=>{
if (err) {
console.log("Error: ", err);
} else {
let id = candidates[candidateName];
let cnt = contractInstance.getVotes.call(candidateName).toString();
$("#" + id).html(cnt);
}
})
}catch(err){}
}
打开votehtml文件即可显示,输入框填入姓名即可投票。
踩坑实录
-
compileCode {“errors”:[{“component” general" “formattedMessage expected.\\nLine1,Column2\\nExtranon-whitespace ntaxerr0r:value,object0rarrayexpected.\\nLine1, 'severity”:’‘error’ “type” Line1,ColumnI\\nSyntaxerr0r: afterJSONvalue.\\n" 'message Column2\\nExtranon-whitespace value,object0rarray Line1,ColumnI\\nS afterJSONvalue.\\n"
解决:solcjs的版本跟合约里指定编译器的版本要匹配。
-
ParserError:Expected identifier,got ‘LParen’\\n"
解决:在合约开头增加
//SPDX-License-Identifier: SimPL-2.0
-
TypeError: Data location must be “storage” or “memory” for constructor parameter
修改:constructor(bytes32[] names) public{},之后变成warning
-
Error:invalid address
解决:contractInstance.getVotes.call('Alice')
以上是关于简单投票DApp的主要内容,如果未能解决你的问题,请参考以下文章
区块链 Hello World -- 基于以太坊的投票Dapp
区块链投票应用:使用solidity+truffle+metamsk开发Dapp应用
区块链投票应用:使用solidity+truffle+metamsk开发Dapp应用