注意點(diǎn):mapping(string => uint) aa芹助; 當(dāng)mapping的key類型為string時(shí)候,不能將aa聲明未public類型
其次當(dāng)我們使用string類型作為函數(shù)參數(shù)的時(shí)候徒坡,目前版本需要加入pragma experimental ABIEncoderV2;否則無(wú)法編譯通過(guò);
pragma solidity ^0.4.14;
pragma experimental ABIEncoderV2;
contract Vote {
/* 1箍鼓、 合約主人初始化候選人列表
2崭参、 合約主人才能賦予某個(gè)地址投票權(quán)
2、 每個(gè)人都能給某一個(gè)候選人投票款咖,或者代理給其他人投票何暮,不能重復(fù)投票
3、 合約能計(jì)算誰(shuí)的投票數(shù)最多
*/
// 定義一個(gè)投票的結(jié)構(gòu)體
struct Voter {
uint weight; // 累計(jì)的權(quán)重
bool voted; // 是否已經(jīng)投票
address delegate; // 委托的投票代表
uint vote; // 投票的索引
}
// 定義一個(gè)需要投票的結(jié)構(gòu)體
struct NeedVoter{
string name;
uint voteCount;
}
// 定義一個(gè)需要投票的數(shù)組
NeedVoter[] public needVoters;
address ownerAddress;
// mapping存儲(chǔ)每一個(gè)投票人的地址
mapping(address => Voter) voters;
string[] public winName;
uint public winCount;
uint public len;
// 初始化候選人列表
constructor (string[] personName)public{
// 保存創(chuàng)建此合約的地址
ownerAddress = msg.sender;
// 初始化候選人數(shù)組
len = personName.length;
for(uint i=0;i< personName.length;i++){
needVoters.push(NeedVoter({
name: personName[i],
voteCount: 0})
);
}
}
// 合約主人才能賦予某個(gè)地址投票權(quán)
function giveRightToVote(address voter)public{
// 這個(gè)地址首先有三個(gè)要求
// 1铐殃、必須是合約持有者調(diào)用的此方法
require(msg.sender == ownerAddress, "只有合約持有者才能賦予此地址投票權(quán)");
// 2海洼、此地址必須沒(méi)有投過(guò)票
require(!voters[voter].voted, "此地址已經(jīng)投票了");
// 3、此地址的投票權(quán)重為0
require(voters[voter].weight==0);
voters[voter].weight = 1;
}
// 投票
function vote(uint personal)public{
// 1富腊、給誰(shuí)投票
// 2坏逢、投票后我自己要改變什么內(nèi)容
// 3、給投票的人改變什么內(nèi)容
// 拿出我們存在mapping里面的voters
Voter storage sender = voters[msg.sender];
require(sender.weight!=0,"nihai你還meiyou你還沒(méi)有toupiao你還沒(méi)有投票quanxian");
require(!sender.voted, "已經(jīng)投過(guò)票,不能重復(fù)投票");
sender.voted = true;
sender.vote = personal;
// 改變索引為personal的count
// 如果你的選中的人超出了數(shù)組界限是整,則會(huì)自動(dòng)拋出肖揣,并回滾所有的改變
needVoters[personal].voteCount +=sender.weight;
}
// 代理投票,將投票權(quán)代理給其他人
function delegate(address to)public{
// 有哪幾種情況不能代理?
/*
1浮入、你必須沒(méi)有投過(guò)票龙优,否則無(wú)法代理
2、你不能代理給你自己
3事秀、你不能代理給一個(gè)不存在的人
4彤断、你不能代理給一個(gè)已經(jīng)投過(guò)票的人:分2種,一種是已經(jīng)投票了但是沒(méi)有代理給別人易迹,一種是你的代理已經(jīng)代理給了別人(這種就是要防止循環(huán)代理)
*/
// 拿到引用
Voter storage sender = voters[msg.sender];
require(!sender.voted, "您已經(jīng)投票");
require(msg.sender != to , "不能自己代理給自己");
require(voters[to].weight!=0, "不能自己代理給沒(méi)有投票權(quán)限的人");
// require(voters[to].delegate==address(0) && !voters[to].voted, "你代理的人已經(jīng)投票宰衙,無(wú)法代理");
while(voters[to].delegate != address(0)){
to = voters[to].delegate;
// 如果循環(huán)引用則死循環(huán)
require(to!=msg.sender, "循環(huán)代理");
}
// 能到這個(gè)地方那么前面的都通過(guò)了
// 修改需要代理的sender 的內(nèi)容
sender.voted = true;
sender.delegate = to;
// 修改代理的voter內(nèi)容
// 拿到代理的voter
Voter storage delegate_ = voters[to];
if(delegate_.voted){
// 代理的人已經(jīng)投票,把sender的票加到needVoters
needVoters[delegate_.vote].voteCount += sender.weight;
}else {
// 代理的人沒(méi)有投票
delegate_.weight += sender.weight;
}
}
// 計(jì)算勝出
function winningPersonal()public{
uint winPoint = 0;
// 每次調(diào)用計(jì)算勝出的要清零數(shù)組
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;
}
}
// 賦值最多的計(jì)數(shù)
winCount = count;
// 查看有沒(méi)有并列相同票數(shù)的人
for(uint j=0;j< needVoters.length;j++){
if(count == needVoters[j].voteCount){
winName.push(needVoters[j].name);
}
}
}
}