區塊鏈 Hello World -- 基於以太坊的投票Dapp

指路牌

  • 以太坊
  • 區塊鏈
  • Dapp
  • 以太坊hello world

環境

windows 10 64bitjavascript

參考博客

youclavier -- 以太坊投票Dapp教程css

背景

準備接手一個IPFS+Ethereum的項目,先學習一下Ethereum,並嘗試完成一個Hello World。html

步驟

  1. 參考我另外一片blog, 安裝nvm
  2. 安裝node 9.11.1 並切換環境
nvm install 9.11.1
nvm use 9.11.1
複製代碼
  1. 建立一個新的工做目錄,並在命令行索引到該路徑
  2. 安裝ganche-cli、web三、solc
npm install ganache-cli
npm install web3@0.20.1
npm install solc@0.4.21       //此處原博客沒有版本,會安裝高於0.4的版本,會致使後續編譯smart contract編譯失敗 
複製代碼

在安裝了ganache-cli與web3時,因爲教程版本問題會出現報錯,可是不影響。java

  1. 啓動ganache-cli
node_modules\.bin\ganache-cli
複製代碼

ganache-cli啓動後輸出以下
6. 使用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;
   }}
複製代碼
  1. 啓動node交互控制檯,依次輸入如下命令
> Web3 = require('web3')
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"))
> web3.eth.accounts
複製代碼

輸入以上最後一條命令後會獲取Ganache建立的10個賬號,以下node

> code = fs.readFileSync('Voting.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)
複製代碼

所有完成會獲得以下截圖的輸出,表示smart contract編譯成功 jquery

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,記下來後續會用到web

> contractInstance = VotingContract.at(deployedContract.address)
複製代碼
  1. 下載web3.js文件,下載後放在工做根目錄下。

    由cdn不知什麼緣由不可用,因此直接下載源文件,連接以下 web3.js 0.20.6npm

  2. 在根目錄下建立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

  1. 在瀏覽器打開index.html,輸入Candidate中的人名後,點擊Vote便可投票,投票後效果以下
    每次點擊投票,也都會生成一個新的區塊,效果以下。

後記

以上步驟就完成了一個基於Ethereum的投票Dapp的完整搭建流程,整合個補全後步驟應該不會有坑的能夠順利搭建完成。bootstrap

就像「hello world」的字面意思同樣,0-1的過程是最艱難的,可是開了頭,剩下的1-n也就會順暢很多。windows

要獲取更多Haytham原創文章,請關注公衆號"許聚龍":

個人微信公衆號
相關文章
相關標籤/搜索