ETH 004 投票项目Ballot

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"]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容