美文网首页
[solidity] 投票系统

[solidity] 投票系统

作者: 朱慢慢 | 来源:发表于2022-08-19 17:46 被阅读0次
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

/*  
投票系统,由合约创建者(主席)发起提案,主席拥有赋予指定选民投票的权利
选民可以指定另一个选民作为自己的代表
部署地址 https://rinkeby.etherscan.io/tx/0x08eb435a2c57bc552168aa109836b925589434b3ca12799f4852be9bae2eb64e
 */
contract Ballot {

    // 此结构代表了一个选民
    struct Voter {
        uint weight; // 累积的投票权重
        bool voted; // true则代表已经投过票
        address delegate; // 记录代表地址
        uint vote; // 确定投票第vote个提案,相当于proposals数组的索引index
    }

    // 此结构代表了一个提案
    struct Proposal {
        bytes32 name; // 提案的名称
        uint voteCount; // 累计的提案支持数量
    }

    address public chairperson; // 发起提案的合约拥有人 - 主席

    mapping(address => Voter) public voters; // 此状态变量,address映射到每个Voter的struct

    Proposal[] public proposals; // 数组的length是动态的,proposals保存了提案

    // constructor是初始化函数,只会在合约创建时调用一次 
    // 通过传入一个proposalNames数组来初始化添
    constructor(bytes32[] memory proposalNames) {
        // 合约创建时,指定chairperson
        chairperson = msg.sender;
        voters[chairperson].weight = 1;

        // 根据传入proposalNames数组
        // 循环创建Proposal提案,并添加到proposals
        for(uint i = 0; i < proposalNames.length; i++) {
            proposals.push(Proposal({
                name: proposalNames[i], // 提案名称
                voteCount: 0 // 初始化支持数是0
            }));
        }
    }

    // 给与指定地址拥有”表决权“
    // 此方法只有‘chairperson’可以调用
    function giveRightToVote(address voter) external {
        // require如果判定为false,则执行终止 && 回滚合约状态
        // 第二个参数则可以记录解释发生了什么问题(测试过 - 字符串不支持中文)
        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;
    }
    
    // 指定to为自己的代表
    function delegate(address to) external {
        // 从“已投票地址”voters数组 - 获取Voter选民  
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "Your already voted"); // 检查是否已参与过投票

        require(to != msg.sender, "Self-delegation is disallowed.");// 不允许指定自己为代表 

        // 一般来说使用此类循环是很危险的
        // 如果运行的时间过长,可能会需要消耗更多的gas
        // 甚至有可能会导致死循环
        // 此While是向上寻找顶层delegate(代表)
        while(voters[to].delegate != address(0)) { // 地址不为空
            // 此处意思是比如有多级delegate(代表),那么就需要不断向上寻找
            to = voters[to].delegate; 
            // 再向上寻找过程不允许“to”和“请求发起人”msg.sender重合
            require(to != msg.sender, "Found loop in delegation.");
        }

        Voter storage delegate_ = voters[to];

        // 检查是否又投票权
        require(delegate_.weight >= 1);
        // 更改发起人的投票状态和代理
        sender.voted = true;
        sender.delegate = to;
        // 检查代理的投票状态
        // 如果已经投票则直接为提案增加投票数、反之则增加delegate_代表的投票权重
        if(delegate_.voted) {
            proposals[delegate_.vote].voteCount += sender.weight;
        } else {
            delegate_.weight += sender.weight;
        }
    }

    // 为提案投票
    function vote(uint proposal) external {
        // 获取选民
        Voter storage sender = voters[msg.sender];
        // 判断是否有投票权
        require(sender.weight >= 0, "Has no rigth to vote.");
        // 判断是否已经投过票
        require(sender.voted, "Already vote.");

        // 通过校验后,则改变其自身状态
        sender.voted = true;
        sender.vote = proposal;

        // 为指定提案增加支持数量
        // 如果proposal超出数组范围,则会停止执行
        proposals[proposal].voteCount += sender.weight;
    }

    // 统计获胜提案
    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;
            }
        }
    }

    // 通过winningProposal()方法获取获胜添的index
    // 再通过proposals数组获取提案object的name
    function winnerName() external view 
        returns (bytes32 winnerName_)
    {
        winnerName_ = proposals[winningProposal()].name;
    }
}

相关文章

网友评论

      本文标题:[solidity] 投票系统

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