智能合约样例-投票

合约内容预览

例子实现了一个投票智能合约即电子投票系统。解决的主要问题是如何分配合理的权限给正确的人,并且要防止被篡改。这个例子实现了如何去委托投票,整个投票计数过程是自动而且完全透明。

功能上它首先为投票创建一个合约,发起者作为所谓的 chairperson 姑且叫主席来给每一个独立的地址分配相应权限。每一个参与投票者可以自己投票或者委托自己信任的人。这段代码最后运行结果会返回得票数最多的那个议案或者叫倡议。

实现

pragma solidity ^0.4.22;

// 一个有委托功能的投票系统
contract Ballot {
    // 一个投票人
    struct Voter {
        uint weight;        // 代表投票过程中会累积
        bool voted;         // 如果值为 true,代表这个投票人已经投过票
        address delegate;   // 委托投票人地址
        uint vote;          // 当前投票的索引
    }

    // 一份议案的数据结构 
    struct Proposal {
        bytes32 name;       // 议案的名称
        uint voteCount;     // 议案得到的投票数
    }

    address public chairperson;                 // 定义投票发起人
    mapping(address => Voter) public voters;    // 所有潜在投票人
    Proposal[] public proposals;                // 定义动态数组存储议案

    // 构造函数,传入议案名称来定义一个投票对象。注意需要传入一个bytes32数组,需要将 string 转为 bytes 传进来。
    function Ballot(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
            }));
        }
    }

    // 给投票人分配投票权限,这个操作只有主席才可以
    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 delegate(address to) public {
        // 找出委托发起人,如果已经投票,终止程序
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "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;   // 投票成功,投票总数加上相应的weight
        } else {
            delegate_.weight += sender.weight;                      // 如果还没投票,发起人weight赋值给委托人
        }
    }

    // 投票给某个议案
    function vote(uint proposal) public {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "Already voted.");
        sender.voted = true;
        sender.vote = 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;
            }
        }
    }

    // 返回投票最多的议案
    function winnerName() public view returns (bytes32 winnerName_)
    {
        winnerName_ = proposals[winningProposal()].name;
    }
}

其他

议案需要将 string 转为 bytes32,比如 string alice 转为 bytes32 则为 0x616c696365000000000000000000000000000000000000000000000000000000。一份转换代码如下:

var convert = function hexToStr(hex) {
    var str = '';
    for (var i = 0; i < hex.length; i += 2) {
       var v = parseInt(hex.substr(i, 2), 16);
       if (v) str += String.fromCharCode(v);
    }
  return str;
}
暂无评论

发送评论 编辑评论


				
上一篇
下一篇