这个例子相对复杂一些,用到了以太坊编程语言Solidity的很多特性。例子实现了一个投票智能合约。电子投票系统的一个主要问题是如何分配合理的权限给正确的人,并且要防止篡改。这个例子不能解决所有问题,但是实现了如何去委托投票,整个投票计数过程是自动且完全透明的。
功能上首先要为投票设立一个简称创建一个合约,发起者作为主席来给每一个独立的地址分配权限。每一个参与者可以自己投票或者委托给信任的人。程序最后会返回得票数最多的那个提议。
// 一个有委托功能的投票系统 |
contract Ballot { |
// 定义一个复杂类型,后面作为变量来使用, |
// 代表一个投票人。 |
struct Voter { |
unit weight; // weight在代表投票过程中会累积 |
bool voted; // 如果值为true,代表这个投票人已经投过票 |
address delegate; // 投票人地址 |
unit vote; // 当前投票的索引 |
} |
// 代表一份提议的数据结构 |
struct Posposal { |
bytes32 name; // 提议的名称 |
unit voteCount; // 提议接受的投票数 |
} |
// 定义投票发起人 |
address public chairperson; |
// 这个状态变量存储了所有潜在投票人 |
mapping(address => Voter) public voters; |
// 定义动态数组存储所以提议 |
Posposal[] public proposals; |
// 传入提议名称来定义一个投票对象 |
function Ballot(bytes32[] proposalNames){ |
chairperson = msg.sender; |
voters[chairperson].weight = 1; |
// 把传入的提议名称创建一个提议,并加入到前面定义的提议数组 |
for(unit i = 0; i < proposalNames.length; i++){ |
// 创建一个临时提议对象,加入提议数组 |
proposals.push(Proposal({ |
name: proposalNames[i], |
voteCount: 0; |
})); |
} |
} |
// 给投票人分配投票权限,这个操作只有发起人(主席)才可以 |
function giveRightToVote(address: voter){ |
if(msg.sender != chairperson || voter.voted) { |
throw; |
} |
voters.weight = 1; |
} |
// 委托投票给另外一个投票人 |
function delegate(address to){ |
// 找出委托发起人,如果已经投票,终止程序 |
Voter sender = voters[msg.sender]; |
if(sender.voted) |
throw; |
while(voters[to].delegate != address[0] && |
voters[to].delegate != msg.sender){ |
to = voters[to].delegate; |
} |
// 发起人、委托人不能是同一个,否则终止程序 |
if(to == msg.sender){ |
throw; |
} |
// 标识发起人已经投过票 |
sender.voted = true; |
sender.delegate = to; |
Voter delegate = voters[0]; |
if (delegate.voted) { |
// 投票成功,投票总数加上相应的weight |
proposals[delegate.vote].voteCount += sender.weight; |
} |
else { |
// 如果还没投票,发起人weight赋值给委托人 |
delegate += sender.weight; |
} |
} |
// 投票给某个提议 |
function vote(unit proposal) { |
Voter sender = voters[msg.sender]; |
if (sender.voted) |
throw; |
sender.voted = true; |
sender.voter = proposal; |
proposals[proposal].voteCount += sender.weight; |
} |
// 找出投票数最多的提议 |
function winningProposal() constant returns (winningProposal) |
{ |
unit winningVoteCount = 0; |
for (unit p = 0; p < voteCount; p++) { |
if (proposals[p].voteCount > winningVoteCount){ |
winningVoteCount = proposals[p].voteCount; |
winningProposal = p; |
} |
} |
} |
} |