//SPDX-License-Identifier:MIT
pragma solidity >=0.7.0 <0.9.0;
///@title Voting with delegate 文档注释,执行指定命令会将特殊标记的东西生成说明文档
contract Ballot {
/*
这里定义了一个结构类型,类似于C++语言中的代码结构,类似于对象中的对象*/
struct Voter{
uint weight;//权重
bool voted;//是否已经投票
address delegate;//委托地址
uint vote;//投票的对应提案编号
}
/*
定义了一个提案,有两个数据属性*/
struct Proposal{
bytes32 name;//提案名称
uint voteCount;//获得票数
}
/*
定义了一个状态变量chairperson
*/
address public chairperson;
/*
定义了一个复杂的数据结构mapping, key是地址,value是一个Voter对象.
*/
mapping(address => Voter)public voters;
//定义了一个动态数量的数组,类型是一个Proposal结构
Proposal[]public proposals;
/*
合约的构造函数,需要传递一个参数数组,将所有提案的名称数组传递进来,并将其初始的票数设置为0
*/
constructor(bytes32[]memory proposalNames){
chairperson = msg.sender; //合约创建的时候定义了一个公共状态变量chairperson,现在将合约创建者的地址赋值给chairperson
voters[chairperson].weight =1;//同时将投票创建者自身的投票权重设置为1
for(uint i =0;i< proposalNames.length; i++){
//将构造函数的参数构建为Proposal,并初始化值,赋值给proposals 公共状态变量
proposals.push(Proposal({
name: proposalNames[i],
voteCount:0
}));
}
}
/*
给其他地址授权,这个方法只能是主席人所对应的地址才可以调用*/
function giveRightToVote(address voter)external {
require(msg.sender == chairperson,"只有主席才可以授权给他人投票");
require(!voters[voter].voted,"the voter already voted");
require(voters[voter].weight ==0);
voters[voter].weight =1;
}
/*
代理方法,将调用方的投票授权代理给 to 地址*/
function delegate(address to)external {
Voterstorage sender = voters[msg.sender];//将调用方的地址映射的Voter结构从 mapping取出来,放入到 storage中进行存储,方便后续的校验及运算
require(sender.weight!=0,"you have no right to vote");//判断调用方的地址是否有投票权重,如果没有权重,则提醒对方没有投票权限
require(!sender.voted,"you already voted");//判断调用方是否已经投过票,如果已经投票了,则提醒其已经投票
require(to!=msg.sender,"self-delegation is disallowed");//校验授权的代理地址不能是当前的调用方,也就是不能自己代理给自己,否则就发出提醒
Voterstorage delegate_ =voters[to];// 如果校验都通过了,则从mapping中取出代理地址对应的 Voter数据结构,并且放入到storage中进行存储,方便后续使用
require(delegate_.weight >=1);//授权委托的地址必须是一个可以投票的地址
sender.voted =true;//将调用方的投票状态设置为true
sender.delegate = to;//将调用方的授权地址设置为传递进来的参数
//如果授权委托的地址已经投票了,那么将当前调用方的票数,增加到授权委托方已经投票的提案,如果授权委托的地址未投票,则将调用方的投票权重增加给委托地址
if(delegate_.voted){
proposals[delegate_.vote].voteCount += sender.weight;
}else{
delegate_.weight += sender.weight;
}
}
/*
投票方法,将调用方所投的提案,以及对应的票数,增加到对应的提案上.
*/
function vote(uint proposal)external {
Voterstorage sender = voters[msg.sender]; // 从voters 的mapping中取出调用方对应的 Voter结构,并且存入到storage区域中,方便下文使用
require(sender.weight!=0," has no right to vote");
require(sender.voted,"you already voted");
sender.voted =true;//设置为已投票
sender.vote = proposal;//将传递进来的参数,设置为想提案的id
proposals[proposal].voteCount +=sender.weight; //将当前地址拥有的投票权重赋值给他想投的提案的已经获得的票数上
}
/*
统计各个提案获得的票数,并且选出票数最多的提案id,然后返回获得投票数最多的提案id
*/
function winningProposal()public view returns(uint winningProposal_) {
uint winningVoteCount =0;
for(uint p=0; p
if(proposals[p].voteCount > winningVoteCount){
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
/*
获取对应获胜的提案id,然后在Proposal的结构通过id获得对应的proposal对象,然后获得对应的name
*/
function winnerName()external view returns(bytes32 winnerName_){
winnerName_ = proposals[winningProposal()].name;
}
}
网友评论