简单的投票合约Ballot
需求叙述
- 这个合约展示了如何进行委托投票,同时计票又是自动和完全透明的
- 为每个(投票)表决创建一份合约,然后作为合约的创造者-主席,将给予每个独立地址以投票权
- 地址后面的人可以自己选择投票,或委托他们信任的人投票
- 投票时间结束时,winingProposal()将返回获得最多投票的提案
Ballot智能合约源码
pragma solidity >=0.4.22 <0.6.0;
contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
address delegate;
}
struct Proposal {
uint voteCount;
}
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
/// Create a new ballot with $(_numProposals) different proposals.
constructor(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).
function giveRightToVote(address toVoter) public {
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
/// Delegate your vote to the voter $(to).
function delegate(address to) public {
Voter storage sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
/// Give a single vote to proposal $(toProposal).
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
function winningProposal() public view returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}
Ballot智能合约源码解读
首先定义了两个结构体,Voter和Proposal:
struct Voter { uint weight; bool voted; uint8 vote; address delegate; } struct Proposal { uint voteCount; }
Voter是投票者结构体,包括:weight(投票权重,可以简单理解为票数),voted(指代是否投过票),vote(指代要投给哪个提案),delegate(代理的地址,可以让其他人代理投票)。 Proposal是提案结构体,voteCount指代提案的总投票数。
- 之后定义了chairperson变量,一个地址到投票者的映射voters,即为每个投票者存储他们的状态,定义了一个Proposal结构类型的动态数组。
- 在构造函数中,传入的参数是提案的数量,初始化主席,以及主席的投票权重,初始化提案的个数。
constructor(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
- 将投票权分发给投票者,这个函数只能主席进行调用。
function giveRightToVote(address toVoter) public {
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
首先判断调用者是否是主席,赋予投票权利的必须是主席,并且投票者必须是没有投过票,投票者才有票数(权重)
- 之后定义代理函数,代理函数的功能是让其他投票者代理投票,代理函数的代码如下:
function delegate(address to) public {
Voter storage sender = voters[msg.sender]; // assigns reference
if (sender.voted) return;
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
to = voters[to].delegate;
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
在这个函数中,传入的参数是代理投票者的地址,首先获得需要代理的投票者的状态,将相关信息存储到sender变量中,随后,要保证需要代理的投票者没有投过票。之后的while循环实现的是嵌套代理功能。因为代理投票者也有可能将代理权交由其他投票者进行代理,因此需要将代理的地址设为最内层代理投票者的地址,并且需要保证,代理的地址不为0地址且代理者不为需要代理者本身,之后再检查一下代理的投票者是不是投票者本身,如果是则返回,将需要代理的投票者的投票状态设为已投票,代理设为最后得到的代理地址,最后一句代理投票者的状态更新一下相关信息,如果代理投票者已经投过票了,将代理投票者投给的那个提案的票数相应地增加,增加的票数就是需要代理的投票者的票数(weight),如果代理投票者还没有投票,将代理投票者的票数增加相应的票数。
- 之后定义投票函数,如下:
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
投票函数首先需要保证调用者没有投过票并且投给的那个提案有效,之后,改变调用函数的投票者的状态,更改提案的状态,即在投票给的那个提案上增加相应的票数。
- 最后是判断哪个提案胜出的函数:
function winningProposal() public view returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
这个函数的功能就是不断地遍历提案,选出提案里票数最多地提案,返回这个提案的提案号。
文档信息
- 本文作者:Atomyzd
- 本文链接:https://atomyzd.github.io/2020/08/23/Solidity%E7%AC%94%E8%AE%B03/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)