# Q9 g2 a3 d! M
- pragma solidity >=0.7.0 <0.9.0;
- 0 M; m6 ]* _7 D9 g8 f+ k
- //投票实验, k/ f( |" y# p( J% O
- contract Ballot{8 q! t, A s% y( A$ X
- struct Voter{& p# C# n1 U/ t' w% x& G6 V! z
- uint weight;//投票(单票)权重! y% z3 w$ S* v) k8 @2 |% f
- bool voted;//是否投过票,true为投过票,bool类型默认值为false" [0 ?) A9 m, D `; P7 e
- address delegate;//想要委托投票的节点地址,address默认值为0x0
- uint vote;//想要投票的节点的索引值(被投票节点信息用一维数组proposals存储)9 u# d$ C1 j2 r$ `2 T
- }, r' Q. h/ i* f6 b, V d' J
-
- struct Proposal{//被投票节点的相关参数% ]& h8 | e5 M8 q6 R# u5 H
- bytes32 name;//被投票节点的姓名标识9 ?1 j' w# m6 {
- uint voteCount;//累积被投票数* o9 B5 F" v; {" l7 p) H2 F
- }' ]; O' F0 Z3 E2 O
- 1 Z( _* Y) e- @! ^
- address public chairperson;//投票管理员地址6 \* S) i7 E, g% C5 S) H+ c$ C
- mapping(address => Voter) public voters;//地址对投票节点的信息的映射
- Proposal[] public proposals;//一维数组存储被投票节点信息2 G9 r0 Q G: K+ W- s+ Z
-
- //构造方法、构造函数
- //solidity和其他语言不一样,构造函数仅在部署合约时调用一次,后续调用合约不调用其构造函数* E1 q W& p u+ b m
- //且一个合约只能有一个构造函数,不能进行构造函数重载# s& G% E1 j, O ? F
- constructor(bytes32[] proposalNames) public{
- chairperson = msg.sender;//将第一次调用该合约的节点设置为管理员
- voters[chairperson].weight = 1;//将管理员投票权置为1: l+ z# u7 f0 }
- 2 K9 j" B) a6 w. A/ b2 |4 ?# Y4 ~
- for(uint i=0; i<proposalNames.length; i++){
- //将所有被投票人姓名初始化进一维数组proposals,并将其对应票数初始化为0票
- //.push(),括号中内容需要强调数据类型,eg:arr.push(uint(6));0 O) d" q+ V, X
- proposals.push(Proposal({8 p3 V5 R. u/ d+ b/ z
- name:proposalNames[i],: I" C8 ^5 {4 G& w9 D" K
- voteCount:0
- }));% G$ R( @. A C- r H" w) a
- }. {6 G9 J% s1 {- Z0 j6 u
- }
- : O" e1 S& `0 H# z. y
- //由管理员授权可投票节点9 F4 L# }) x7 k& ^, p* t
- function giveRightToVote(address voter) public{ \1 y X2 g* k, |+ G6 t
- //require中判断条件为false时,输出字符串"xxx...",异常会被抛出,程序执行会被挂起,
- //未消耗的gas会被退回,合约状态会回退到初始状态
- require() a! e4 B2 m( b1 w. U
- msg.sender == chairperson,"Only chairperson can give right to vote."
- );//执行此function的节点一定为管理员节点9 ]2 C( v; y$ _4 M$ M
- require(' [8 O! B5 n& {8 S4 m+ A/ h+ ?' y
- !voters[voter].voted,"The voter already voted."
- );//若voter没投过票
- require(voters[voter].weight == 0);# I% i! R# c$ [4 C
- //调用合约的人是管理员、待授权节点还没投过票、带授权节点投票权重为0时,进行授权6 B$ _" C% V# R
- voters[voter].weight = 1;//上述三个require()均成立时,授权票数) T4 G$ N% ]- e# q8 W& b5 p
- }
-
- //投票授权- L. s0 t7 Y% \4 F
- 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.");/ f! U! I& T8 l+ e) D* C4 W! Y4 X
- //sender满足的条件:要有投票权限、没有投过票、被授权节点不是自己
-
- //判断代理节点地址是否为空:address(0)或者address(0x0)
- while(voters[to].delegate != address(0)){
- to = voters[to].delegate;//找到最终的代理节点
- require(to != msg.sender,"Found loop in delegation.");//若代理节点最终是自己则回退到初始状态8 O; ^3 s( j8 Z' B7 |# Z4 z& P
- }
- : x0 c0 K% L. s/ M* Y
- sender.voted = true;//票权代理出去,状态改为已投票. G; Z1 D9 X' s) e( l5 X1 G2 T
- sender.delegate = to;//票权代理地址
- Voter storage delegate_ = voters[to];//取出代理节点状态2 G7 g# J8 }6 H+ `' _
- ! E# f! \. L/ z5 M6 g
- //若代理节点已投过票,将新代理的票权投出去,反之则将代理节点票权加和# V7 `5 A) D. n! I1 q1 ]
- if(delegate_.voted){
- proposals[delegate_.vote].voteCount += sender.weight;
- }else{! x, {7 R9 e# M# V4 ? e n
- delegate_.weight += sender.weight;' h6 }0 \9 `: z* p- Q
- }7 o j4 d- @0 S+ F6 O1 {/ _
- }
-
- function vote(uint proposal) public{
- Voter storage sender = voters[msg.sender];//通过地址获取对应投票信息
- require(!sender.voted,"Already voted.");//若sender未投过票6 Y7 G s: V- H2 x# s$ u F# o3 i
- sender.voted = true;//更改投票状态为已投过票
- sender.vote = proposal;//保存已投票节点
- proposals[proposal].voteCount += sender.weight;//票权加和$ K8 C. D* q% S& A
- }
-
- //返回票数最多的节点在一维数组proposals中的索引: w' a' E, P" I
- function winningProposal() public view returns(uint winningProposal_){
- uint winningVoteCount = 0;' U7 n4 z; Q4 X. t
- for(uint p=0;p<proposals.length;p++){
- if(proposals[p].voteCount > winningVoteCount){& {4 z) E2 s+ ]
- winningVoteCount = proposals[p].voteCount;& |. \5 U9 R1 R G) F0 i* y
- winningProposal_ = p;
- }* g4 {1 R0 |+ `5 {/ C! J* r
- }
- }
- //输出票数最多的节点name9 S9 D9 m+ X- j* L
- function winnerName() public view returns(bytes32 winnerName_){6 }/ s8 t! E3 q) J. W' k" K
- winnerName_ = proposals[winningProposal()].name;$ N1 |2 m" o( k$ i8 j
- }, E# u( B \# T( `
- }