智能合约样例-投票

合约内容预览

例子实现了一个投票智能合约即电子投票系统。解决的主要问题是如何分配合理的权限给正确的人,并且要防止被篡改。这个例子实现了如何去委托投票,整个投票计数过程是自动而且完全透明。

功能上它首先为投票创建一个合约,发起者作为所谓的 chairperson 姑且叫主席来给每一个独立的地址分配相应权限。每一个参与投票者可以自己投票或者委托自己信任的人。这段代码最后运行结果会返回得票数最多的那个议案或者叫倡议。

实现

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
pragma solidity ^0.4.22;

// 一个有委托功能的投票系统
contract Ballot {
// 一个投票人
struct Voter {
uint weight; // 代表投票过程中会累积
bool voted; // 如果值为 true,代表这个投票人已经投过票
address delegate; // 委托投票人地址
uint vote; // 当前投票的索引
}

// 一份议案的数据结构
struct Proposal {
bytes32 name; // 议案的名称
uint voteCount; // 议案得到的投票数
}

address public chairperson; // 定义投票发起人
mapping(address => Voter) public voters; // 所有潜在投票人
Proposal[] public proposals; // 定义动态数组存储议案

// 构造函数,传入议案名称来定义一个投票对象。注意需要传入一个bytes32数组,需要将 string 转为 bytes 传进来。
function Ballot(bytes32[] proposalNames) public {
chairperson = msg.sender; // 发起者才有权力分配选票
voters[chairperson].weight = 1; // 发起者自己有一票

// 按传入的议案名称创建一个议案,并加入到前面定义的议案数组
for (uint i = 0; i < proposalNames.length; i++) {
// 创建一个临时议案对象,加入议案数组
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}

// 给投票人分配投票权限,这个操作只有主席才可以
function giveRightToVote(address voter) public {
require(msg.sender == chairperson, "Only chairperson can give right to vote."); // 不是主席不允许分配选票
require(!voters[voter].voted, "The voter already voted."); // 投过票的不允许再分配选票了
require(voters[voter].weight == 0); // 已分配选票的不需要再给选票了

voters[voter].weight = 1;
}

// 委托投票给另外一个投票人
function delegate(address to) public {
// 找出委托发起人,如果已经投票,终止程序
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");

// 发起人、委托人不能是同一个,否则终止程序
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
require(to != msg.sender, "Found loop in delegation.");
}

// 标识发起人已经投过票
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
proposals[delegate_.vote].voteCount += sender.weight; // 投票成功,投票总数加上相应的weight
} else {
delegate_.weight += sender.weight; // 如果还没投票,发起人weight赋值给委托人
}
}

// 投票给某个议案
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;

proposals[proposal].voteCount += sender.weight;
}

// 找出投票数最多的议案
function winningProposal() public view returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}

// 返回投票最多的议案
function winnerName() public view returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}

其他

议案需要将 string 转为 bytes32,比如 string alice 转为 bytes32 则为 0x616c696365000000000000000000000000000000000000000000000000000000。一份转换代码如下:

1
2
3
4
5
6
7
8
var convert = function hexToStr(hex) {
var str = '';
for (var i = 0; i < hex.length; i += 2) {
var v = parseInt(hex.substr(i, 2), 16);
if (v) str += String.fromCharCode(v);
}
return str;
}
您的支持将鼓励我继续创作!
0%