预安装nodejs和npm
使用npm安装ganache-cli、[email protected]、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()
DOCTYPE html>
<html>
<head>
<title>投票DApptitle>
<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 Applicationh1>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Candidateth>
<th>Votesth>
tr>
thead>
<tbody>
<tr>
<td>Alicetd>
<td id="candidate-1">td>
tr>
<tr>
<td>Bobtd>
<td id="candidate-2">td>
tr>
<tr>
<td>Carytd>
<td id="candidate-3">td>
tr>
tbody>
table>
div>
<input type="text" id="candidate" />
<a href="#" onclick="voteForCandidate()" class="btn btn-primary">Votea>
body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.js">script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js">script>
<script src="./vote.js">script>
html>
运行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