投票合约详解--以太坊实战

    科技2022-08-07  102

    话不多说先上代码:

    pragma solidity ^0.4.22; /** 创建投票活动,传入选项名称 授权某地址用户可以投票 用户投票 用户授权代理人 查看投票结果 需要一个投票选项(名称、票数)列表、一个投票人(地址=>{拥有的票数、代理人地址、是否已经投票、投给哪个选项})列表 */ contract Ballot { // 投票人 struct Voter { uint weight; // 投票所占权重 bool voted; // 是否已经投票 address delegate; // 代理人地址 uint vote; // 给谁投票,提案索引 } // 提案 struct Proposal { bytes32 name; // 提案名称 uint voteCount; // 累计投票数 } address public chairperson; // 主席地址 mapping (address => Voter) voters; // 投票人列表 Proposal[] proposals; // 提案列表 /// 构造函数 // 创建人就是主席 // 设置主席的票数=1 // 遍历提案名称列表,构造提案,放入列表 constructor(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 })); } } // 给某人分配投票权 // 要求:1. 只有主席才能执行此动作;2. 此人没有投过票;3. 此人的票数为0 // 加入投票人列表,并设置票数为1 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 giveRightToVoteByBatch(address[] batch) public { require(msg.sender==chairperson); for(uint i=0;i<batch.length;i++){ address voter=batch[i]; require(!voters[voter].voted && (voters[voter].weight==0)); voters[voter].weight=1; } } /// 把投票权代理给某人 // 要求:1. 调用者没有投过票;2. 调用者不是目标代理人 function delegate(address to) { Voter storage sender=voters[msg.sender];// 根据调用者地址取得对应的投票人对象 require((!sender.voted)&&(sender.weight!=0), "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; } // 如果代理人还没投票,就把票数给代理人 else { delegate_.weight += sender.weight; } } // 直接投票 // 根据调用者地址取得投票人对象 // 要求:还没有投过票 // 设置投票人已经投过票、投的提案 // 增加提案票数 function vote(uint proposal) { require(proposal<proposals.length); Voter storage sender = voters[msg.sender];// 根据调用者地址,取得对应的投票人对象 require((!sender.voted)&&(sender.weight!=0), "Already voted."); // 必须还没投过 sender.voted = true;// 设置已投票 sender.vote = proposal; // 设置投票提案的索引值 proposals[proposal].voteCount += sender.weight; // 增加目标提案的票数 } // 遍历提案,找出票数最高的,返回胜出提案索引值 function winningProposal() constant returns (uint[] winningProposals) { uint [] memory tempWinner =new uint [](proposals.length); uint winningCount = 0; uint winningVoteCount = 0; for (uint p = 0; p < proposals.length; p++) { if (proposals[p].voteCount > winningVoteCount) { winningVoteCount = proposals[p].voteCount; tempWinner[0]=p; winningCount=1; } else if(proposals[p].voteCount == winningVoteCount){ tempWinner[winningCount]=p; winningCount++; } } winningProposals=new uint [](winningCount); for(uint q=0;q<winningCount;q++){ winningProposals[q]=tempWinner[q]; } return winningProposals; } // 取得胜出提案名称 function winnerName() constant returns (bytes32[] winnerNames) { uint[] memory winningProposals =winningProposal(); winnerNames = new bytes32[](winningProposals.length); for(uint p=0;p<winningProposals.length;p++){ winnerNames[p]=proposals[winningProposals[p]].name; } return winnerNames; } }

    测试

    (1)发布

    1.部署合约 2.确定主持人,然后添加提案。 构造参数是 bytes32[] 填: [“0x6f7074696f6e4100000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4200000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4300000000000000000000000000000000000000000000000000”,“0x6f7074696f6e4400000000000000000000000000000000000000000000000000”] 点击deploy函数即可添加进去

    (2)授权

    1.在acount找几个账户,然后复制它们的地址 2.将复制的地址分别填到 giveRightToVote参数输入框中,然后用户换成主持人给它们投票权利并执行

    (3)投票

    把account切换到授权投票的账号,执行投票操作,vote参数中填写提案索引,例如 1。 执行 winnerProposal 和 winnerName 查看效果:

    (4)代理

    把account切换到另一个 账号,执行设置代理的操作,代理给上一个账户。

    Processed: 0.010, SQL: 8