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; //声明变量,给每个地址存储一个Voter mapping(address => Voter) public voters; //动态数组Proposal Proposal[] public proposals; //构造函数为proposalNames的每个提案,创建新的投票表决 constructor(bytes32[] proposalNames) public { chairperson = msg.sender;//将第一个部署合约的人设置为主持人 voters[chairperson].weight = 1;//设置主持人权重为1 //将所有待选的提案,创建新的Proposal对象放入数组中 for (uint i = 0;i < proposalNames.length;i++){ // `Proposal({...})` 创建一个临时 Proposal 对象, // `proposals.push(...)` 将其添加到 `proposals` 的末尾 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." );//如果投过票,!voters[voter].voted为false,提示该人已经投过票了 require(voters[voter].weight == 0);//分发票权,将权重设置为1 voters[voter].weight = 1; } // 把投票权委托到投票者 `to` 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 is delegation."); } sender.voted = true;//设置委托人已经投票,相当于把票权让出去了 sender.delegate = to;//委托对象是“to” Voter storage delegate_ = voters[to];// if(delegate_.voted){//判断被委托人是否投了票 proposals[delegate_.vote].voteCount += sender.weight;//将委托人的票加上去 }else{ delegate_.weight += sender.weight;//如果被委托人没有投票,被委托人的票权=委托人 //+被委托人 } } // 把你的票(包括委托给你的票),投给提案 `proposals[proposal].name` function vote(uint proposal) public { Voter storage sender = voters[msg.sender]; require(!sender.voted,"already voted.");//检查有没有投票权 sender.voted = true;//如果有投票权,把是否投票设置为true,表示投票权用掉 sender.vote = proposal;// //如果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; //找出得票数最多的提案 } } } // 调用winningProposal() 函数以获取提案数组中获胜者的索引,并以此返回提案的名称 function winnerName() public view returns(bytes32 winnerName_){ return winnerName_ = proposals[winningProposal()].name; } }
部署过程:
2.主持人:0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
3.分发票权
得票人地址:0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2=①
0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c=②
0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db=③
此时三个地址一人一票
4.委托票权
①把票权委托给②
然后查看0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c=②的票权重
此时①0票,②2票,③1票
5.投票
点两下transact
查看此时第二个(1号)提案
点击第三下,错误
然后换到③再对0投一次票
6.查看得票最多的提案