投票Dapp开发

1.开发环境准备:ganache+webjs+nodejs

2.创建一个文件夹Dapp
mkdir Dapp

3.安装ganache-cli,要求(nodejs>=V8)
npm install -g ganache-cli

ganache是 开发和测试的本地内存区块链。它模拟了真实的以太坊网络的功能,包括由测试以太币资助的多个账户的可用性。
4.安装web3js
npm install web3 -save

5.安装truffle
npm install -g truffle

truffle是节省程序员写多余代码的框架,通过truffle命令可以直接生成开发框架
安装过程如果出错建议更新一下nodejs
安装完成通过truffle -V检查版本
6.在remix中编写智能合约,并编译通过(新版本,需要翻墙: Remix - Ethereum IDE  旧版本: Remix - Ethereum IDE
pragma solidity >=0.4.22 < 0.8.0;  
//选择编译器版本,需要确保正在这个区间,并且需要大于0.4.22,低于这个版本有的关键词不能识别

contract Vote {  //创建vote投票合约
    uint public candidatesCount;  //定义候选人数量
    mapping(address => bool) public voters; //将投票人地址,映射成一个布尔值,用以判断该账户知否已经投过
    struct Candidate {  //定义一个结构体,包含候选人ID,名字,投票数
        uint id;
        string name;
        uint voteCount;
    }

    mapping(uint => Candidate) public candidates; //通过ID来访问候选人
   
    function addCandidate(string memory _name) private{  //定义添加候选人函数,并声明为私有的
        candidatesCount ++;  //添加一个就将候选人总数加一
        candidates[candidatesCount] = Candidate(candidatesCount,_name,0); //将整个结构体赋予对应的候选人
    }

    constructor () public {  //构造函数,添加候选人
        addCandidate("张三");
        addCandidate("李四");
    }

    function vote(uint _candidateId) public { //投票函数,传入输入框候选人对应的ID
        require(!voters[msg.sender]);  //检查该账户是否已投过票,msg.sender为调用合约地址
        require(_candidateId > 0 && _candidateId <= candidatesCount); //检查所投的候选人是否在候选人名单中

        voters[msg.sender] = true; //将调用合约账户设为已投
        candidates[_candidateId].voteCount ++; //将所投候选人投票数加一
        emit votedEvent(_candidateId);//发出事件
    }

    event votedEvent ( //定义事件,用以刷新界面
        uint indexed _candidateId
    );  
}

7.在Dapp中创建模板工程
truffle unbox pet-port

此过程可能会出错,多试几次,大部分是因为网络问题
8.运行ganache-cli
ganache-cli

运行成功会生成10个合约账户以及对应的私钥,同时还有连接的本地端口
9.修改truffle-config.js
 
连接的端口和地址需要与ganache最终的一致
10.创建合约
vim Election.sol

将remix中的智能合约粘贴在这
11.编写前端页面,用以显示投票,修改src/index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>投票 DApp </title>
  <link href="css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div class="container" style="width: 650px;">
    <div class="row">
      <div class="col-lg-12">
        <h1 class="text-center">投票 DApp</h1>
        <hr />
        <br />
        <div id="loader">
          <p class="text-center">Loading...</p>
        </div>
        <div id="content" style="display: none;">
          <table class="table">
            <thead>
              <tr>
                <th scope="col">#</th>
                <th scope="col">候选人</th>
                <th scope="col">得票数</th>
              </tr>
            </thead>
            <tbody id="candidatesResults">
            </tbody>
          </table>
          <hr />
          <form onSubmit="App.castVote(); return false;">
            <div class="form-group">
              <label for="candidatesSelect">选择候选人</label>
              <select class="form-control" id="candidatesSelect">
              </select>
            </div>
            <button type="submit" class="btn btn-primary">投票</button>
            <hr />
          </form>
          <p id="accountAddress" class="text-center"></p>
        </div>
      </div>
    </div>
  </div>
  <script src="js/jquery.min.js"></script>
  <script src="js/bootstrap.min.js"></script>
  <script src="js/web3.min.js"></script>
  <script src="js/truffle-contract.js"></script>
  <script src="js/app.js"></script>
</body>

</html>

12.修改src/js/app.js代码
​
App = {
  web3Provider: null,
  contracts: {},
  account: '0x0',
  hasVoted: false,
  init: async function() {
    return await App.initWeb3();
  },
  initWeb3: async function() {
      if (window.ethereum) {
        App.web3Provider = window.ethereum;
        try {
          await window.ethereum.enable();
        } catch (error) {
   
          console.error("User denied account access")
        }
      } else if (window.web3) {
        App.web3Provider = window.web3.currentProvider;
      }
      else {
        App.web3Provider = new Web3.providers.HttpProvider('http://localhost:8545');
      }
      web3 = new Web3(App.web3Provider);
    return App.initContract();
  },
  initContract: function() {
    $.getJSON("Election.json", function(election) {
      App.contracts.Election = TruffleContract(election);
      App.contracts.Election.setProvider(App.web3Provider);
      App.listenForEvents();
      return App.render();
    });
  },
  listenForEvents: function() {
    App.contracts.Election.deployed().then(function(instance) {
      instance.votedEvent({}, {
        fromBlock: 0,
        toBlock: 'latest'
      }).watch(function(error, event) {
        console.log("event triggered", event)
        App.render();
      });
    });
  },
  render: function() {
    var electionInstance;
    var loader = $("#loader");
    var content = $("#content");
    loader.show();
    content.hide();
    web3.eth.getCoinbase(function(err, account) {
      if (err === null) {
        App.account = account;
        $("#accountAddress").html("Your Account: " + account);
      }
    });
    App.contracts.Election.deployed().then(function(instance) {
      electionInstance = instance;
      return electionInstance.candidatesCount();
    }).then(function(candidatesCount) {
      var candidatesResults = $("#candidatesResults");
      candidatesResults.empty();
      var candidatesSelect = $('#candidatesSelect');
      candidatesSelect.empty();
      for (var i = 1; i <= candidatesCount; i++) {
        electionInstance.candidates(i).then(function(candidate) {
          var id = candidate[0];
          var name = candidate[1];
          var voteCount = candidate[2];
          // Render candidate Result
          var candidateTemplate = "<tr><th>" + id + "</th><td>" + name + "</td><td>" + voteCount + "</td></tr>"
          candidatesResults.append(candidateTemplate);
          // Render candidate ballot option
          var candidateOption = "<option value='" + id + "' >" + name + "</ option>"
          candidatesSelect.append(candidateOption);
        });
      }
      return electionInstance.voters(App.account);
    }).then(function(hasVoted) {
      if(hasVoted) {
        $('form').hide();
      }
      loader.hide();
      content.show();
    }).catch(function(error) {
      console.warn(error);
    });
  },
  castVote: function() {
    var candidateId = $('#candidatesSelect').val();
    App.contracts.Election.deployed().then(function(instance) {
      return instance.vote(candidateId, { from: App.account });
    }).then(function(result) {
      // Wait for votes to update
      $("#content").hide();
      $("#loader").show();
    }).catch(function(err) {
      console.error(err);
    });
  }
};
$(function() {
  $(window).load(function() {
    App.init();
  });
});
​

12.更新依赖
npm install

13.编译部署合约
truffle compile
truffle migrate

14.需要在谷歌浏览器中安装钱包插件,
Releases · MetaMask/metamask-extension · GitHub直接下载对应的版本,如果出错,选不了网络,可以下载其他版本地址如下
提取码:0w3n
解压添加到谷歌浏览器插件
15.在插件中导入账户,将ganache中生成的账户私钥输入
16.运行合约
npm run dev

17.在浏览器地址输入127.0.0.1:3000,会自动调出钱包,需要对钱包下一步即可

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值