簡單投票DApp
文章目錄
- 簡單投票DApp
- 環境配置
- 撰寫合約
- 合約內容
- 代碼
- 編譯合約
- 部署合約
- 合約互動
- 網頁互動
- vote.html
- vote.js
- 踩坑實錄
環境配置
-
預安裝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')
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/335249.html
標籤:區塊鏈
