solidity实现投票智能合约
投票需求
投票合约虽然有些复杂,但却展示了solidity语言的特性。电子投票的主要问题是如何将投票权分给正确的人以及如何防止被操作,以及如何委托别人进行投票,同时计算票数又是自动和完全透明的。
实现这个需求的想法是为每个(投票)建议建立一份合约,然后作为合约的创造者——即主席,将给予每个独立地址以投票权。
获取投票权之后,每个地址可以选择自己投票,也可以选择把投票权委托给信任的人进行投票,在投票结束后,获取最终胜利的建议以及相应票数。
投票实现
为了实现投票智能合约,我构建了一个投票者的结构体,结构体包含了用来投票的权重 uint weight,用来表示是否已经投票的bool类型数据voted,用来表示已投票提议的索引,以及委托人的地址类型数据delegate。
struct Voter{
uint weight; //weight is accumulated by delegation
bool voted; //if true ,that perpn already voted
uint vote;
address delegate;
}
接着我定义了一个提案的结构体,里面包含投票的次数。
struct Proposal{
uint voteCount;
}
随后定义了投票发起人的地址类型数据chairPerson,同时把地址类型映射成Voter结构体,建立Proposal机构体数组。
address public chairPerson;
mapping(address => Voter) voters;
Proposal[] proporsals;
构造函数,初始化发起人,初始化发起人投票者的权重,同时设置提案数组的大小。
constructor (uint _numProposal)public{
chairPerson = msg.sender;
voters[chairPerson].weight = 1;
proporsals.length = _numProposal;
}
定义给予投票权的函数giveRightToVote(address to ),再给予投票权时需要限制只有发起者才能把投票权给予别人,同时欢迎保证被给予者没投过票,同时没有把票委托出去。
function giveRightToVote(address to )public{
require(
msg.sender == chairPerson,
"Only chairperson can give right to vote."
);
require(
!voters[to].voted,
"The voter already voted."
);
require(voters[to].weight == 0);
voters[to].weight = 1;
}
定义委托函数delegate(address to ),在把票委托给别人时,应保证委托投票时没有投过票,同时不能委托给自己,另外考虑到委托人也可能把票委托给另外一个人,所以使用一个while循环实现。委托实现后,投票者的是否投票设置为true;之后如果委托人已经投过票,就将投票者的权重加在所投建议的票数上,如果未投票,就把投票者的权重加在委托人投票者上。
function delegate(address to ) public{
Voter storage sender = voters[msg.sender];
require(!sender.voted, "you hava already voted");
require(to != msg.sender);
while(voters[to].delegate != address(0) && voters[to].delegate != msg.sender){
to = voters[to].delegate;
}
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if(delegateTo.voted){
proporsals[delegateTo.vote].voteCount += sender.weight;
}
else{
delegateTo.weight += sender.weight;
}
}
投票函数vote(uint proposal),要求投票者没有投过,否则,则没有权限投票,投完票以后将voted设为true,同时把所投提案的票数加上。
function vote(uint proposal) public{
Voter storage sender = voters[msg.sender];
require(!sender.voted ,"no right");
sender.voted = true;
sender.vote = proposal;
proporsals[sender.vote].voteCount += sender.weight;
}
赢得投票的提案函数winningProposal(),通过遍历每个提案所得票数获得最高。
function winningProposal() public view returns(uint _winningProposal){
uint winningCount = 0;
for(uint prop = 0; prop <proporsals.length; prop++){
if(winningCount < proporsals[prop].voteCount){
winningCount = proporsals[prop].voteCount;
_winningProposal = prop;
}
}
}
得出获胜提议的最高票数函数winningCount(uint),通过遍历得出获胜提议的票数。
function winningCount(uint) view public returns(uint){
uint _winningCount = 0;
uint _winningProposal = 0;
for(uint prop = 0; prop <proporsals.length; prop++){
if(_winningCount < proporsals[prop].voteCount){
_winningCount = proporsals[prop].voteCount;
_winningProposal = prop;
}
}
return proporsals[_winningProposal].voteCount;
}
总体代码实现
pragma solidity >=0.4.22 <0.7.0;
contract Ballot{
struct Voter{
uint weight; //weight is accumulated by delegation
bool voted; //if true ,that perpn already voted
uint vote;
address delegate;
}
struct Proposal{
uint voteCount;
}
address public chairPerson;
mapping(address => Voter) voters;
Proposal[] proporsals;
constructor (uint _numProposal)public{
chairPerson = msg.sender;
voters[chairPerson].weight = 1;
proporsals.length = _numProposal;
}
function giveRightToVote(address to )public{
require(
msg.sender == chairPerson,
"Only chairperson can give right to vote."
);
require(
!voters[to].voted,
"The voter already voted."
);
require(voters[to].weight == 0);
voters[to].weight = 1;
}
function delegate(address to ) public{
Voter storage sender = voters[msg.sender];
require(!sender.voted, "you hava already voted");
require(to != msg.sender);
while(voters[to].delegate != address(0) && voters[to].delegate != msg.sender){
to = voters[to].delegate;
}
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
if(delegateTo.voted){
proporsals[delegateTo.vote].voteCount += sender.weight;
}
else{
delegateTo.weight += sender.weight;
}
}
function vote(uint proposal) public{
Voter storage sender = voters[msg.sender];
require(!sender.voted ,"no right");
sender.voted = true;
sender.vote = proposal;
proporsals[sender.vote].voteCount += sender.weight;
}
function winningProposal() public view returns(uint _winningProposal){
uint winningCount = 0;
for(uint prop = 0; prop <proporsals.length; prop++){
if(winningCount < proporsals[prop].voteCount){
winningCount = proporsals[prop].voteCount;
_winningProposal = prop;
}
}
}
function winningCount(uint) view public returns(uint){
uint _winningCount = 0;
uint _winningProposal = 0;
for(uint prop = 0; prop <proporsals.length; prop++){
if(_winningCount < proporsals[prop].voteCount){
_winningCount = proporsals[prop].voteCount;
_winningProposal = prop;
}
}
return proporsals[_winningProposal].voteCount;
}
}
运行环境:0.6.0以下版本的EVM。