投票DAPP
投票智能合约
- contracts/Voting.sol
1 | pragma solidity ^0.4.18; |
使用node console调试合约
打开ganche
,使用web3
交互。
1 | ➜ chapter1 git:(master) ✗ node |
查看区块账号
1 | > web3.eth.accounts |
读取并编译智能合约
1 | > code = fs.readFileSync('Voting.sol').toString() |
部署智能合约
1 | > abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface) |
- compiledCode.contracts[‘:Voting’].bytecode: 合约二进制代码,用于部署到区块链中.
- compiledCode.contracts[‘:Voting’].interface: 智能合约接口模板(abi),告诉合约用户可使用的接口.
调用合约方法
1 | > contractInstance.totalVotesFor.call('Rama') |
0xb78beb95dce55f946fe9d3bbe06f3ed588749e2714fa2834e4f0a59f6a2d55d6
是每一次交易发生的transaction id
前端页面
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<html>
<head>
<title>Hello World 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 Hello World 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>Rama</td>
<td id="candidate-1"></td>
</tr>
<tr>
<td>Nick</td>
<td id="candidate-2"></td>
</tr>
<tr>
<td>Jose</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.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="./index.js"></script>
</html>index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
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);
// nodejs console中contractInstance.address获得的地址
contractInstance = VotingContract.at('0xf7f433a4a2f9bf3f364bb96abe6a07778a61e095');
candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
function voteForCandidate() {
candidateName = $("#candidate").val();
contractInstance.voteForCandidate(candidateName, {from: web3.eth.accounts[0]}, function() {
let div_id = candidates[candidateName];
$("#" + div_id).html(contractInstance.totalVotesFor.call(candidateName).toString());
});
}
$(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);
}
});
以上是不使用框架的智能合约的开发应用。
voting优化
创建truffle工程
1 | mkdir voting |
创建合约植入代码。
- migrations/2_deploy_contracts.js
1
2
3
4
5var VotingContract = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
deployer.deploy(VotingContract,['Rama', 'Nick', 'Jose'], {gas: 6700000});
};
DAPP前端代码
app/javasripts/app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58// Import the page's CSS. Webpack will know what to do with it.
import "../stylesheets/app.css";
// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'
import voting_artifacts from '../../build/contracts/Voting.json'
var Voting = contract(voting_artifacts);
let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}
window.voteForCandidate = function(candidate) {
let candidateName = $("#candidate").val();
try {
$("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.")
$("#candidate").val("");
/* Voting.deployed() returns an instance of the contract. Every call
* in Truffle returns a promise which is why we have used then()
* everywhere we have a transaction call
*/
Voting.deployed().then(function(contractInstance) {
contractInstance.voteForCandidate(candidateName, {gas: 140000, from: web3.eth.accounts[0]}).then(function() {
let div_id = candidates[candidateName];
return contractInstance.totalVotesFor.call(candidateName).then(function(v) {
$("#" + div_id).html(v.toString());
$("#msg").html("");
});
});
});
} catch (err) {
console.log(err);
}
}
$( document ).ready(function() {
if (typeof web3 !== 'undefined') {
console.warn("Using web3 detected from external source like Metamask")
// Use Mist/MetaMask's provider
window.web3 = new Web3(web3.currentProvider);
} else {
console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
}
Voting.setProvider(web3.currentProvider);
let candidateNames = Object.keys(candidates);
for (var i = 0; i < candidateNames.length; i++) {
let name = candidateNames[i];
Voting.deployed().then(function(contractInstance) {
contractInstance.totalVotesFor.call(name).then(function(v) {
$("#" + candidates[name]).html(v.toString());
});
})
}
});app/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<html>
<head>
<title>Hello World 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 Hello World Voting Application</h1>
<div id="address"></div>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Candidate</th>
<th>Votes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rama</td>
<td id="candidate-1"></td>
</tr>
<tr>
<td>Nick</td>
<td id="candidate-2"></td>
</tr>
<tr>
<td>Jose</td>
<td id="candidate-3"></td>
</tr>
</tbody>
</table>
<div id="msg"></div>
</div>
<input type="text" id="candidate" />
<a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
</body>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="app.js"></script>
</html>
编译部署智能合约:
1 | ➜ voting git:(master) ✗ truffle compile |
运行应用
npm run dev
登录metamask
进行应用访问:
代码
1 | git clone https://github.com/LiZoRN/BlockChain.git |
投票v2版本
一般在选举中,每一个选民只能投出一票给候选人。但假设你是一家公司的股东,你可能需要会有这样的要求:票数按拥有的股票数来定。
- 项目目标
- 学习使用数据类型
Struct
用来组织和存储区块链上的数据 - 学习票据(tokens)的概念并应用到本项目
功能说明
- 票据(tokens):表示可用于投票的总票数
- 每一个选民使用货币(
eth
)来购买票据用于投票 - 你可以查看投票信息:
- 每个候选人拥有多少tokens
- 自己所投的token情况
- 候选人不再指定,从整条链上获取。
智能合约
1 | pragma solidity ^0.4.18; //We have to specify what version of the compiler this code will use |
- migrations/2_deploy_contracts.js
1
deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
重新部署智能合约
1 | truffle compile |
启动工程:npm run dev
完成代码
1 | git clone https://github.com/LiZoRN/BlockChain.git |