简单投票DApp

Posted 是澜澜呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单投票DApp相关的知识,希望对你有一定的参考价值。

简单投票DApp

环境配置

  1. 预安装nodejs和npm

  2. 使用npm安装ganache-cli、web3@0.20.1、solc,各软件版本如下图。

  3. 运行node_modules/.bin/ganache-cli,出现下图即为成功,默认创建了10个账户,每个账户有100个以太。

编写合约

合约内容

  1. 候选人组
  2. 候选人组及其票数
  3. 构造函数:初始化候选人组
  4. 投票函数
  5. 得到某个候选人票数的函数

代码

//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文件即可显示,输入框填入姓名即可投票。

踩坑实录

  1. 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的版本跟合约里指定编译器的版本要匹配。

  2. ParserError:Expected identifier,got ‘LParen’\\n"

    解决:在合约开头增加//SPDX-License-Identifier: SimPL-2.0

  3. TypeError: Data location must be “storage” or “memory” for constructor parameter

    修改:constructor(bytes32[] names) public{},之后变成warning

  4. Error:invalid address


    解决:contractInstance.getVotes.call('Alice')

以上是关于简单投票DApp的主要内容,如果未能解决你的问题,请参考以下文章

区块链 Hello World -- 基于以太坊的投票Dapp

区块链投票应用:使用solidity+truffle+metamsk开发Dapp应用

区块链投票应用:使用solidity+truffle+metamsk开发Dapp应用

区块链投票应用:使用solidity+truffle+metamsk开发Dapp应用

DApp入门

以太坊 DApp 开发入门实战! 用Node.js和truffle框架搭建——区块链投票系统!