美文网首页
ETH 004 投票项目Ballot

ETH 004 投票项目Ballot

作者: 三文鱼的一生 | 来源:发表于2018-12-02 16:45 被阅读0次

    4.1 介绍

    下面我们要介绍一个使用Solidity 编写的投票合约。该合约实现了一下功能。

    1. 选民登记
    2. 候选人提议登记
    3. 投票
    4. 委托第三方投票
    5. 票数统计,决选出候选人

    该投票项目是一个公开透明的,不可作弊的工程。

    4.2

    //声明使用的Solidity 版本号
    pragma solidity >=0.4.22 <0.6.0;
    
    /// 投票程序
    contract Ballot {
    
        //使用结构体(STRUCT),声明一个选票对象。 
        struct Voter {
            uint weight; // 选票的权重,1表示1票
            bool voted;  // 该选票是否已经投出
            address delegate; //  该选票委托给第三方地址(如果空就是没有)
            uint vote;   // 该选票投给哪个提议
        }
    
        //使用结构体(STRUCT),声明一个【提议】
        struct Proposal {
            bytes32 name;   // 32 位的提议名称
            uint voteCount; // 总票数
        }
    
         //address  关键字代表一个以太坊地址
        // 声明该项目的主持人。  
        address public chairperson;
    
        //mapping 关键字代表一个 集合
       // 声明以太坊地址(选民)和选票之间的映射
        mapping(address => Voter) public voters;
    
        // 【提议数组】 本投票程序的候选提议
        Proposal[] public proposals;
    
        // 构造函数 项目部署的时候 进行初始化设计,只运行一次
        constructor(bytes32[] memory proposalNames) public {
            // 项目部署者就是该项目的主持人。msg是以太坊关键字代表当前交易信息。
            chairperson = msg.sender; 
           // 主持人也有投票的权力,将其
            voters[chairperson].weight = 1;
    
            // 讲传入的提议 初始化。 
            for (uint i = 0; i < proposalNames.length; i++) {
                // `Proposal({...})` 函数 创建一个临时的提议对象
                //  `proposals.push(...)` 函数讲该提议放入proposals 末尾
                proposals.push(Proposal({
                    name: proposalNames[i],
                    voteCount: 0
                }));
            }
        }
    
       // 选民登记
        function giveRightToVote(address voter) public {
            // require 关键字表示拦截,如果返回的结果是false 则执行终止,所有对状态和以太余额的更改将被还原
            require(
                msg.sender == chairperson,
                "只有主持人,能进行选民登记."
            );
    
            require(
                !voters[voter].voted,
                "该选民存在,并且已经投票过"
            );
           // 该选民必须是从来没有登记过
            require(voters[voter].weight == 0); 
           //登记选民,并且给予1票的权力
            voters[voter].weight = 1;
        }
    
       // 投票
        function vote(uint proposal) public {
           //获取当前的自己的选票 storage 表示直接操作存储
            Voter storage sender = voters[msg.sender];
           //weight  不能等于0 
            require(sender.weight != 0, "Has no right to vote");
             //voted  必须还没有投票过
            require(!sender.voted, "Already voted.");
           // 将选票设置为已投
            sender.voted = true;
          //  设置要投给哪个提议
            sender.vote = proposal;
    
            // 更新 该提议的票数
            proposals[proposal].voteCount += sender.weight;
        }
    
      
        ///选民可以将它们的选票委托给第三方机构来投票
        function delegate(address to) public {
              //获取当前的自己的选票 storage 表示直接操作存储 
            Voter storage sender = voters[msg.sender];
           //voted  必须还没有投票过
            require(!sender.voted, "You already voted.");
           // 委托人(to) 不能是自己。 
            require(to != msg.sender, "Self-delegation is disallowed.");
    
            //  这段话比较绕,就是你委托给A,A还有他的委托人B 那你的委托人就是B。知道没有委托人为止。 address(0) 表示0地址 。
            while (voters[to].delegate != address(0)) {
                to = voters[to].delegate;
                // We found a loop in the delegation, not allowed.
                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 {
            //如果委托人还没投票 ,将委托人手上的票数+1 
                delegate_.weight += sender.weight;
            }
        }
    
     
        /// 获取票数最多的提议 编号
        ///  view 表示调用该函数不需要触发交易。 
        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;
                }
            }
        }
    
        // 获取获胜协议的 名称 
        function winnerName() public view
                returns (bytes32 winnerName_)
        {
            winnerName_ = proposals[winningProposal()].name;
        }
    
    }
    

    4.3 测试

    部署时候的输入参数:

    ["0xca35b7d915458ef540ade6068dfe2f44e8fa733c","0xca35b7d915458ef540ade6068dfe2f44e8fa733c"]

    相关文章

      网友评论

          本文标题:ETH 004 投票项目Ballot

          本文链接:https://www.haomeiwen.com/subject/ojercqtx.html