zoukankan      html  css  js  c++  java
  • Solidity by Example详解

    Example地址:https://solidity.readthedocs.io/en/develop/solidity-by-example.html#voting

    Voting程序的功能:

    这个智能合约实现了一种在区块链上公开投票的功能。

    部署该智能合约的人称为chairperson(主席),主席的作用为:

    1. 在合约部署时,创建一系列proposals(提案),供大家投票

    2. 在合约部署后,主席有权邀请人来投票,对应于代码中的giveRightToVote(address)方法

    投票者(包括主席和其他参与投票的人)的投票权重均为1,他们可以:

    1. 给一个提案投票(每人只有一票,只能投一个提案)

    2. 也可以将自己的投票权委托给另一个投票者,则被委托人的投票权重变为2(票数还是1,只能投一个提案),如果被委托人还没投票,则当他投票时,一票抵两票;如果被委托人已经投票,则给他所投的提案再加一票。

    在区块链上实现这个功能的好处为:投票过程公开透明,不可篡改

    程序分析:

    pragma solidity ^0.4.16;
    
    
    /// 委托投票
    contract Ballot {
        // 投票人结构体
        struct Voter {
            uint weight; // 投票权重(可通过委托增加)
            bool voted;  // 是否已投票标识 ture-已投,false-未投
            address delegate; // 委托人(可以委托另一人带自己投票)
            uint vote;   // 所投的提案(提案数组的下标)
        }
    
        // 提案结构体
        struct Proposal {
            bytes32 name;   // 提案名(最长32byte)
            uint voteCount; // 累计票数
        }
    
        address public chairperson; //主席(合约创建人地址)
    
        //声明一个投票人字典,类似python中的字典数据结构 voters = {addr1: voter1, addr2: voter2, addr3: voter3}
        mapping(address => Voter) public voters;
    
        // 用于储存Proposal结构体的可变长数组
        Proposal[] public proposals;
    
        /// 构造函数,只执行一次,传入提案数组
        function Ballot(bytes32[] proposalNames) public {
            chairperson = msg.sender; // 主席被初始化为delopy合约的人
            voters[chairperson].weight = 1; // 主席的权重为1
    
            // 初始化提案数组为:名称 + 初始票数(0)
            for (uint i = 0; i < proposalNames.length; i++) {
                // `Proposal({...})` 创建一个临时的Proposal对象
                // `proposals.push(...)` 将其push进proposals数组中
                proposals.push(Proposal({
                    name: proposalNames[i],
                    voteCount: 0
                }));
            }
        }
    
        // 给予投票人投票的权利
        function giveRightToVote(address voter) public {
            // 通过require来做输入检查,如require中的运算结果为false,则合约终止运行,且不改变状态变量的值,退回gas消耗(旧版本可能没实现,新版本将实现)
            require(
                (msg.sender == chairperson) && //主席才能执行该方法
                !voters[voter].voted && // 投票人没投过票
                (voters[voter].weight == 0) // 投票人权重为0
            );
            voters[voter].weight = 1; //给投票人赋权重为1
        }
    
        /// 将自己投票权给另一人 `to`.
        function delegate(address to) public {
            // 声明Voter sender为引用类型变量,意味着在delegate()方法内对sender做的改变将会传递到方法外
            Voter storage sender = voters[msg.sender];
            require(!sender.voted); //要求sender在转让投票权前,自己未投票
    
            // 不能将投票权转移给自己
            require(to != msg.sender);
    
            // 当投票代表`to`也委托给别人时,寻找到最终的投票代表,将投票权转让
            // 通常来说,这样的循环结构有点危险,如果执行时间长,可能会将gas消耗殆尽,gas消耗完时合约可能不执行或被卡住.
            while (voters[to].delegate != address(0)) {
                to = voters[to].delegate;
    
                // 有可能死循环,加以下检查.
                require(to != msg.sender);
            }
    
            // 通过引用传递修改voters[msg.sender]的属性,投票权被转让后标记为已投票
            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) public {
            Voter storage sender = voters[msg.sender];
            require(!sender.voted);
            sender.voted = true;
            sender.vote = proposal;
    
            // If `proposal` is out of the range of the array,
            // this will throw automatically and revert all
            // changes.
            //数组下标越界自动报错
            proposals[proposal].voteCount += sender.weight;
        }
    
        /// 根据当前所有的投票计算出当前的胜出提案.
        // view关键字代表不对状态变量进行更新操作(但可以查看),会减少gas消耗
        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;
        }
    }
  • 相关阅读:
    Matlab命令集常用字符串函数
    统计独立性和统计相关性
    查看solaris下硬盘的物理大小
    Perl命令行开关
    DateFormat.getDateInstance出现Unparseable date
    ActiveMQ 本地转本地再转远程的完整配置
    aspose.words 操作word生成试卷
    汇编in和out介绍
    eclipse开发国际化项目利器:MultiProperties
    RCP+GEF+界面开发(2)[eclipse插件配置LINK方法]
  • 原文地址:https://www.cnblogs.com/huahuayu/p/8556526.html
Copyright © 2011-2022 走看看