简单投票DApp

简单投票DApp

文章目录

    • 简单投票DApp
      • 环境配置
      • 编写合约
        • 合约内容
        • 代码
      • 编译合约
      • 部署合约
      • 合约交互
      • 网页交互
        • vote.html
        • vote.js
      • 踩坑实录

环境配置

  1. 预安装nodejs和npm

  2. 使用npm安装ganache-cli、[email protected]、solc,各软件版本如下图。

    简单投票DApp_第1张图片

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

    简单投票DApp_第2张图片

编写合约

合约内容

  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在另一个窗口运行。

简单投票DApp_第3张图片

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)

简单投票DApp_第4张图片

简单投票DApp_第5张图片

部署合约

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);

简单投票DApp_第6张图片

合约部署成功后,在ganache会得到合约地址,如下图。

简单投票DApp_第7张图片

合约交互

为Alice投票,以及查看Alice的票数。

contractInstance.vote('Alice',{from:web3.eth.accounts[0]});
contractInstance.getVotes('Alice').toString();
contractInstance.getVotes.call('Alice').toString()

在这里插入图片描述

简单投票DApp_第8张图片

网页交互

vote.html

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>

vote.js

运行solcjs --bin --abi Voting.sol,得到Voting的abi和bin文件。复制abi文件中的内容粘贴到js文件中的abi代码行中。contractAddr的内容填入之前部署合约的地址。

简单投票DApp_第9张图片

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

简单投票DApp_第10张图片

简单投票DApp_第11张图片

踩坑实录

  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"

    简单投票DApp_第12张图片

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

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

    简单投票DApp_第13张图片

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

    简单投票DApp_第14张图片

  4. Error:invalid address

    简单投票DApp_第15张图片
    解决:contractInstance.getVotes.call('Alice')

你可能感兴趣的:(以太坊,1024程序员节)