注意点:mapping(string => uint) aa; 当mapping的key类型为string时候,不能将aa声明未public类型
其次当我们使用string类型作为函数参数的时候,目前版本需要加入pragma experimental ABIEncoderV2;否则无法编译通过;
pragma solidity ^0.4.14;
pragma experimental ABIEncoderV2;
contract Vote {
/* 1、 合约主人初始化候选人列表
2、 合约主人才能赋予某个地址投票权
2、 每个人都能给某一个候选人投票,或者代理给其他人投票,不能重复投票
3、 合约能计算谁的投票数最多
*/
// 定义一个投票的结构体
struct Voter {
uint weight; // 累计的权重
bool voted; // 是否已经投票
address delegate; // 委托的投票代表
uint vote; // 投票的索引
}
// 定义一个需要投票的结构体
struct NeedVoter{
string name;
uint voteCount;
}
// 定义一个需要投票的数组
NeedVoter[] public needVoters;
address ownerAddress;
// mapping存储每一个投票人的地址
mapping(address => Voter) voters;
string[] public winName;
uint public winCount;
uint public len;
// 初始化候选人列表
constructor (string[] personName)public{
// 保存创建此合约的地址
ownerAddress = msg.sender;
// 初始化候选人数组
len = personName.length;
for(uint i=0;i< personName.length;i++){
needVoters.push(NeedVoter({
name: personName[i],
voteCount: 0})
);
}
}
// 合约主人才能赋予某个地址投票权
function giveRightToVote(address voter)public{
// 这个地址首先有三个要求
// 1、必须是合约持有者调用的此方法
require(msg.sender == ownerAddress, "只有合约持有者才能赋予此地址投票权");
// 2、此地址必须没有投过票
require(!voters[voter].voted, "此地址已经投票了");
// 3、此地址的投票权重为0
require(voters[voter].weight==0);
voters[voter].weight = 1;
}
// 投票
function vote(uint personal)public{
// 1、给谁投票
// 2、投票后我自己要改变什么内容
// 3、给投票的人改变什么内容
// 拿出我们存在mapping里面的voters
Voter storage sender = voters[msg.sender];
require(sender.weight!=0,"nihai你还meiyou你还没有toupiao你还没有投票quanxian");
require(!sender.voted, "已经投过票,不能重复投票");
sender.voted = true;
sender.vote = personal;
// 改变索引为personal的count
// 如果你的选中的人超出了数组界限,则会自动抛出,并回滚所有的改变
needVoters[personal].voteCount +=sender.weight;
}
// 代理投票,将投票权代理给其他人
function delegate(address to)public{
// 有哪几种情况不能代理?
/*
1、你必须没有投过票,否则无法代理
2、你不能代理给你自己
3、你不能代理给一个不存在的人
4、你不能代理给一个已经投过票的人:分2种,一种是已经投票了但是没有代理给别人,一种是你的代理已经代理给了别人(这种就是要防止循环代理)
*/
// 拿到引用
Voter storage sender = voters[msg.sender];
require(!sender.voted, "您已经投票");
require(msg.sender != to , "不能自己代理给自己");
require(voters[to].weight!=0, "不能自己代理给没有投票权限的人");
// require(voters[to].delegate==address(0) && !voters[to].voted, "你代理的人已经投票,无法代理");
while(voters[to].delegate != address(0)){
to = voters[to].delegate;
// 如果循环引用则死循环
require(to!=msg.sender, "循环代理");
}
// 能到这个地方那么前面的都通过了
// 修改需要代理的sender 的内容
sender.voted = true;
sender.delegate = to;
// 修改代理的voter内容
// 拿到代理的voter
Voter storage delegate_ = voters[to];
if(delegate_.voted){
// 代理的人已经投票,把sender的票加到needVoters
needVoters[delegate_.vote].voteCount += sender.weight;
}else {
// 代理的人没有投票
delegate_.weight += sender.weight;
}
}
// 计算胜出
function winningPersonal()public{
uint winPoint = 0;
// 每次调用计算胜出的要清零数组
winName.length = 0;
uint count = needVoters[0].voteCount;
for(uint i=1;i< needVoters.length;i++){
if(count < needVoters[i].voteCount){
winPoint = i;
count = needVoters[i].voteCount;
}
}
// 赋值最多的计数
winCount = count;
// 查看有没有并列相同票数的人
for(uint j=0;j< needVoters.length;j++){
if(count == needVoters[j].voteCount){
winName.push(needVoters[j].name);
}
}
}
}