投票合约详解--以太坊实战

话不多说先上代码:

pragma solidity ^0.4.22;

/**
    创建投票活动,传入选项名称
    授权某地址用户可以投票
    用户投票
    用户授权代理人
    查看投票结果

    需要一个投票选项(名称、票数)列表、一个投票人(地址=>{拥有的票数、代理人地址、是否已经投票、投给哪个选项})列表
*/
contract Ballot {
    // 投票人
    struct Voter {
        uint weight; // 投票所占权重
        bool voted;  // 是否已经投票
        address delegate; // 代理人地址
        uint vote;   // 给谁投票,提案索引
    }
    // 提案
    struct Proposal {
        bytes32 name;   // 提案名称
        uint voteCount; // 累计投票数
    }

    address public chairperson; // 主席地址
   mapping (address => Voter) voters; // 投票人列表
    Proposal[] proposals; // 提案列表

    /// 构造函数
    // 创建人就是主席
    // 设置主席的票数=1
    // 遍历提案名称列表,构造提案,放入列表
    constructor(bytes32[] proposalNames) public {
     	chairperson =msg.sender;
        voters[chairperson].weight=1;
        // 对于每个提案名称,创建一个新的提案对象,放入列表
        for(uint i=0;i<proposalNames.length;i++){
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount:0
            }));
        }
    }

    // 给某人分配投票权
    // 要求:1. 只有主席才能执行此动作;2. 此人没有投过票;3. 此人的票数为0
    // 加入投票人列表,并设置票数为1
 function giveRightToVote(address voter) public{
        require(
            msg.sender==chairperson,
            "Only chairperson can give right to vote");
        require(!voters[voter].voted,
        "the voter already voted");
        require(voters[voter].weight==0);
        voters[voter].weight=1;
    }
    //批量授予投票
       function giveRightToVoteByBatch(address[] batch) public {
        require(msg.sender==chairperson);
        for(uint i=0;i<batch.length;i++){
            address voter=batch[i];
            require(!voters[voter].voted && (voters[voter].weight==0));
            voters[voter].weight=1;
        }
    }
    /// 把投票权代理给某人
    // 要求:1. 调用者没有投过票;2. 调用者不是目标代理人
    function delegate(address to) {
        Voter storage sender=voters[msg.sender];// 根据调用者地址取得对应的投票人对象
        require((!sender.voted)&&(sender.weight!=0), "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 in delegation.");
        }
       sender.voted = true; // 设置为已投票,不能再投了
        sender.delegate = to; // 设置代理人
       Voter storage delegate_ = voters[to];// 取得代理人对应的投票人对象
        // 如果代理人已经投过票,增加代理人所投的那个提案的票数,票数为调用者的票数
         if (delegate_.voted) {
            proposals[delegate_.vote].voteCount += sender.weight;
        }
        // 如果代理人还没投票,就把票数给代理人
        else {
            delegate_.weight += sender.weight;
        }
    }

    // 直接投票
    // 根据调用者地址取得投票人对象
    // 要求:还没有投过票
    // 设置投票人已经投过票、投的提案
    // 增加提案票数
    function vote(uint proposal) {
       require(proposal<proposals.length);
        Voter storage sender = voters[msg.sender];// 根据调用者地址,取得对应的投票人对象
       require((!sender.voted)&&(sender.weight!=0), "Already voted."); // 必须还没投过
       sender.voted = true;// 设置已投票
       sender.vote = proposal; // 设置投票提案的索引值
       proposals[proposal].voteCount += sender.weight; // 增加目标提案的票数
    }

    // 遍历提案,找出票数最高的,返回胜出提案索引值
    function winningProposal() constant returns (uint[] winningProposals)
    {
         uint [] memory tempWinner =new uint [](proposals.length);
        uint winningCount = 0;
        uint winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++) {
            if (proposals[p].voteCount > winningVoteCount) {
                winningVoteCount = proposals[p].voteCount;
                tempWinner[0]=p;
                winningCount=1;
            }
            else if(proposals[p].voteCount == winningVoteCount){
                 tempWinner[winningCount]=p;
                 winningCount++;
            }
        }
        winningProposals=new uint [](winningCount);
        for(uint q=0;q<winningCount;q++){
        winningProposals[q]=tempWinner[q];
        }
        return winningProposals;

    }

    // 取得胜出提案名称
  function winnerName() constant returns (bytes32[] winnerNames)
    {
        uint[] memory winningProposals =winningProposal();
        winnerNames = new bytes32[](winningProposals.length);
        for(uint p=0;p<winningProposals.length;p++){
            winnerNames[p]=proposals[winningProposals[p]].name;
        }
        return winnerNames;
    }

}

测试

(1)发布

1.部署合约
在这里插入图片描述
2.确定主持人,然后添加提案。
在这里插入图片描述
在这里插入图片描述
构造参数是 bytes32[] 填:
[“0x6f7074696f6e4100000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4200000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4300000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4400000000000000000000000000000000000000000000000000”]
点击deploy函数即可添加进去

(2)授权

1.在acount找几个账户,然后复制它们的地址
在这里插入图片描述
2.将复制的地址分别填到 giveRightToVote参数输入框中,然后用户换成主持人给它们投票权利并执行
在这里插入图片描述
在这里插入图片描述

(3)投票

把account切换到授权投票的账号,执行投票操作,vote参数中填写提案索引,例如 1。
在这里插入图片描述
执行 winnerProposal 和 winnerName 查看效果:
在这里插入图片描述

(4)代理

把account切换到另一个 账号,执行设置代理的操作,代理给上一个账户。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38798147/article/details/108926723
今日推荐