指路牌
以太坊
区块链
Dapp
以太坊 hello world
环境
Windows 10 64bit
参考博客
youclavier -- 以太坊投票 Dapp 教程 https://www.jianshu.com/p/3076347c8a5a
背景
准备接手一个 IPFS+Ethereum 的项目, 先学习一下 Ethereum, 并尝试完成一个 Hello World.
步骤
参考我另一片 blog, 安装 nvm
安装 node 9.11.1 并切换环境
- nvm install 9.11.1
- nvm use 9.11.1
创建一个新的工作目录, 并在命令行索引到该路径
安装 ganche-cli,web3,solc
- NPM install ganache-cli
- NPM install [email protected]
- NPM install [email protected] // 此处原博客没有版本, 会安装高于 0.4 的版本, 会导致后续编译 smart contract 编译失败
在安装了 ganache-cli 与 web3 时, 由于教程版本问题会出现报错, 但是不影响.
启动 ganache-cli
node_modules\.bin\ganache-cli
使用 Solidity 创建 Smart Contract, 命名为: Voting.sol
- pragma solidity ^0.4.18;
- contract Voting {
- mapping (bytes32 => uint8) public votesReceived;
- bytes32[] public candidateList;
- function Voting(bytes32[] candidateNames) public {
- candidateList = candidateNames;
- }
- function totalVotesFor(bytes32 candidate) view public returns (uint8) {
- require(validCandidate(candidate));
- return votesReceived[candidate];
- }
- function voteForCandidate(bytes32 candidate) public {
- require(validCandidate(candidate));
- votesReceived[candidate] += 1;
- }
- function validCandidate(bytes32 candidate) view public returns (bool) {
- for(uint i = 0; i <candidateList.length; i++) {
- if (candidateList[i] == candidate) {
- return true;
- }
- }
- return false;
- }
- }
7. 启动 node 交互控制台, 依次输入以下命令
- Web3 = require('web3')
- web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545/"))
- web3.eth.accounts
输入以上最后一条命令后会获取 Ganache 创建的 10 个帐号, 如下
- > code = fs.readFileSync('Voting.sol').toString()
- > solc = require('solc')
- > compiledCode = solc.compile(code)
全部完成会得到如下截图的输出, 表示 smart contract 编译成功
8. 部署 smart contract
- > abi = JSON.parse(compiledCode.contracts[':Voting'].interface)
- > VotingContract = web3.eth.contract(abi)
- > byteCode = compiledCode.contracts[':Voting'].bytecode
- > deployedContract = VotingContract.new(['James', 'Norah', 'Jones'],{
- data: byteCode, from: web3.eth.accounts[0], gas: 4700000
- })
- > deployedContract.address
此时会获取 address, 记下来后续会用到
contractInstance = VotingContract.at(deployedContract.address)
下载 web3.JS 文件, 下载后放在工作根目录下.
由 cdn 不知什么原因不可用, 所以直接下载源文件, 链接如下
web3.JS 0.20.6
在根目录下创建 index.html 文件, 并粘贴以下代码, 需要在截图标出处, 更换成第 8 步自己部署的 smart contract 的 address
- <!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>
- 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>
- James
- </td>
- <td id="candidate-1">
- </td>
- </tr>
- <tr>
- <td>
- Norah
- </td>
- <td id="candidate-2">
- </td>
- </tr>
- <tr>
- <td>
- Jones
- </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="web3.js">
- </script>
- <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js">
- </script>
- <script language="javascript" type="text/javascript">
- web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
- abi = JSON.parse('[{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"x","type":"bytes32"}],"name":"bytes32ToString","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"contractOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"type":"constructor"}]') VotingContract = web3.eth.contract(abi);
- contractInstance = VotingContract.at('0x47f49b300eb86d972f91f103913376fb0a8e52e7');
- candidates = {
- "James": "candidate-1",
- "Norah": "candidate-2",
- "Jones": "candidate-3"
- }
- function voteForCandidate(candidate) {
- candidateName = $("#candidate").val();
- try {
- contractInstance.voteForCandidate(candidateName, {
- from: web3.eth.accounts[0]
- },
- function() {
- let div_id = candidates[candidateName];
- $("#" + div_id).HTML(contractInstance.totalVotesFor.call(candidateName).toString());
- });
- } catch(err) {}
- }
- $(document).ready(function() {
- candidateNames = Object.keys(candidates);
- for (var i = 0; i < candidateNames.length; i++) {
- let name = candidateNames[i];
- let val = contractInstance.totalVotesFor.call(name).toString() $("#" + candidates[name]).HTML(val);
- }
- });
- </script>
- </HTML>
![更换 address](https://user-images.githubusercontent.com/37465243/64078738-f976e400-cd10-11e9-82ef-20468a8e6ba5.png)
11. 在浏览器打开 index.HTML, 输入 Candidate 中的人名后, 点击 Vote 即可投票, 投票后效果如下
![](https://user-images.githubusercontent.com/37465243/64078736-f8de4d80-cd10-11e9-9e1a-173c812f2264.png)
每次点击投票, 也都会生成一个新的区块, 效果如下.
- ![](https://user-images.githubusercontent.com/37465243/64078737-f8de4d80-cd10-11e9-874c-d3e8570432fb.png)
- ## 后记
以上步骤就完成了一个基于 Ethereum 的投票 Dapp 的完整搭建流程, 整合个补全后步骤应该不会有坑的可以顺利搭建完成.
就像 "hello world" 的字面意思一样, 0-1 的过程是最艰难的, 但是开了头, 剩下的 1-n 也就会顺畅不少.
####
*** 要获取更多 Haytham 原创文章, 请关注公众号 "许聚龙":***
![我的微信公众号](https://user-images.githubusercontent.com/37465243/63688227-5b2ede00-c839-11e9-9aa9-2b461444f463.png)
来源: http://www.bubuko.com/infodetail-3199424.html