( O! [( ]& { j, Y
- pragma solidity >=0.7.0 <0.9.0;% G& u/ X6 |. U5 \' f
-
- //投票实验
- contract Ballot{
- struct Voter{
- uint weight;//投票(单票)权重" d m: A+ x% I) g" o! X! e" h, u0 j* m
- bool voted;//是否投过票,true为投过票,bool类型默认值为false
- address delegate;//想要委托投票的节点地址,address默认值为0x08 k" v2 z3 s( Y
- uint vote;//想要投票的节点的索引值(被投票节点信息用一维数组proposals存储)
- }
- % t, A: I- t( B$ u* n4 S& S
- struct Proposal{//被投票节点的相关参数. p9 U2 h! q+ O ~* K
- bytes32 name;//被投票节点的姓名标识
- uint voteCount;//累积被投票数$ m9 h$ ]. \) Y/ X R% `
- }
- * H+ r: I; }$ c- H9 \
- address public chairperson;//投票管理员地址2 C9 C5 b1 u7 }
- mapping(address => Voter) public voters;//地址对投票节点的信息的映射
- Proposal[] public proposals;//一维数组存储被投票节点信息3 w, Z) S& P! w8 p
-
- //构造方法、构造函数
- //solidity和其他语言不一样,构造函数仅在部署合约时调用一次,后续调用合约不调用其构造函数
- //且一个合约只能有一个构造函数,不能进行构造函数重载6 X6 F4 X& X# ?1 h; ]' M* ^
- constructor(bytes32[] proposalNames) public{2 u2 G3 P, R! Z7 O. r
- chairperson = msg.sender;//将第一次调用该合约的节点设置为管理员# k c4 F8 X# z5 L& g; P" `9 c
- voters[chairperson].weight = 1;//将管理员投票权置为1
-
- for(uint i=0; i<proposalNames.length; i++){
- //将所有被投票人姓名初始化进一维数组proposals,并将其对应票数初始化为0票
- //.push(),括号中内容需要强调数据类型,eg:arr.push(uint(6));
- proposals.push(Proposal({% v7 k7 d$ \! E5 G
- name:proposalNames[i],: P) L; @. j" A( B
- voteCount:08 o, _' r6 D6 `8 A- G: W
- }));
- }
- }( F4 L$ Z2 g, J: n6 z: t5 ]* d
- . Y; w* r5 u* R( L) z( {8 o
- //由管理员授权可投票节点
- function giveRightToVote(address voter) public{: H" w+ J' K( ~
- //require中判断条件为false时,输出字符串"xxx...",异常会被抛出,程序执行会被挂起,6 N9 l$ C0 A/ Q( n
- //未消耗的gas会被退回,合约状态会回退到初始状态
- require(9 }9 C6 h1 ~) r! T8 h
- msg.sender == chairperson,"Only chairperson can give right to vote."' M$ F/ j; l# A# ^: W9 I- P
- );//执行此function的节点一定为管理员节点! M' R; N, ?- C/ r1 W. L
- require(
- !voters[voter].voted,"The voter already voted."* h1 S; c* s0 o4 c3 x6 T; o; K
- );//若voter没投过票8 W {& @ E7 U6 ]) L
- require(voters[voter].weight == 0);6 S( W: G; d5 _% {# I
- //调用合约的人是管理员、待授权节点还没投过票、带授权节点投票权重为0时,进行授权
- voters[voter].weight = 1;//上述三个require()均成立时,授权票数
- }
-
- //投票授权1 P0 L/ ?( d! K0 v4 i; q$ q
- function delegate(address to) public{7 T5 ?3 U' a/ e b/ Y) w
- Voter storage sender = voters[msg.sender];7 v( D6 a3 J* U& l3 d; s
- require(!sender.voted, "You already voted.");
- require(to != msg.sender,"Self-delegation is disallowed.");+ o+ c, D' S8 M7 |, v9 V2 {3 N5 \
- //sender满足的条件:要有投票权限、没有投过票、被授权节点不是自己- d, T, S: t+ r( e7 b
- 8 R# s/ c& \( V$ ^5 c, [7 n7 V+ B$ P
- //判断代理节点地址是否为空:address(0)或者address(0x0)
- while(voters[to].delegate != address(0)){& N, |/ z5 x+ h; C+ K
- to = voters[to].delegate;//找到最终的代理节点& o( \% W6 V$ k" M
- require(to != msg.sender,"Found loop in delegation.");//若代理节点最终是自己则回退到初始状态
- }0 ~0 }+ p+ Z3 Q' k3 |
-
- sender.voted = true;//票权代理出去,状态改为已投票# W$ X8 G+ O* O/ J& u* ^( [0 ]
- sender.delegate = to;//票权代理地址
- Voter storage delegate_ = voters[to];//取出代理节点状态
- - {0 d( @2 x* A6 z- B- W6 p
- //若代理节点已投过票,将新代理的票权投出去,反之则将代理节点票权加和1 Y$ l& i( x* i2 k1 u3 r) q. a) G
- if(delegate_.voted){
- proposals[delegate_.vote].voteCount += sender.weight;
- }else{' v" I4 P+ b6 b; F) V n1 [
- delegate_.weight += sender.weight;6 _4 G4 y! i0 Z' z
- }
- }- P6 M8 d3 D) H6 O0 H
- 8 q( t5 I) l% V }
- function vote(uint proposal) public{
- Voter storage sender = voters[msg.sender];//通过地址获取对应投票信息6 N4 t( i, ~8 V8 p5 x) d- s
- require(!sender.voted,"Already voted.");//若sender未投过票
- sender.voted = true;//更改投票状态为已投过票& N7 x5 n0 O2 u, L0 k
- sender.vote = proposal;//保存已投票节点
- proposals[proposal].voteCount += sender.weight;//票权加和) w. J$ `( b5 X+ [( A: A$ d" K
- }
-
- //返回票数最多的节点在一维数组proposals中的索引1 y7 K, P$ ]0 o* M3 J
- function winningProposal() public view returns(uint winningProposal_){
- uint winningVoteCount = 0;, ?) K& }# E; t3 \* m' A
- for(uint p=0;p<proposals.length;p++){
- if(proposals[p].voteCount > winningVoteCount){- Q3 u3 `2 ~+ M$ n4 |; G
- winningVoteCount = proposals[p].voteCount;
- winningProposal_ = p;, f9 S9 h" c0 P, w4 b" m; ^
- }+ o e3 @, K' ]& K6 e7 }- l
- }
- }
- //输出票数最多的节点name. Y) V- Z! g8 \% r: P8 w4 M
- function winnerName() public view returns(bytes32 winnerName_){
- winnerName_ = proposals[winningProposal()].name;
- }# } x4 b! H" u4 f& @
- }