pragma solidity >=0.7.0 <0.9.0; //投票實驗 contract Ballot{ struct Voter{ uint weight;//投票(單票)權重 bool voted;//是否投過票,true為投過票,bool型別預設值為false address delegate;//想要委託投票的節點地址,address預設值為0x0 uint vote;//想要投票的節點的索引值(被投票節點資訊用一維陣列proposals儲存) } struct Proposal{//被投票節點的相關引數 bytes32 name;//被投票節點的姓名標識 uint voteCount;//累積被投票數 } address public chairperson;//投票管理員地址 mapping(address => Voter) public voters;//地址對投票節點的資訊的對映 Proposal[] public proposals;//一維陣列儲存被投票節點資訊 //構造方法、建構函式 //solidity和其他語言不一樣,建構函式僅在部署合約時呼叫一次,後續呼叫合約不呼叫其建構函式 //且一個合約只能有一個建構函式,不能進行建構函式過載 constructor(bytes32[] proposalNames) public{ chairperson = msg.sender;//將第一次呼叫該合約的節點設定為管理員 voters[chairperson].weight = 1;//將管理員投票權置為1 for(uint i=0; i<proposalNames.length; i++){ //將所有被投票人姓名初始化進一維陣列proposals,並將其對應票數初始化為0票 //.push(),括號中內容需要強調資料型別,eg:arr.push(uint(6)); proposals.push(Proposal({ name:proposalNames[i], voteCount:0 })); } } //由管理員授權可投票節點 function giveRightToVote(address voter) public{ //require中判斷條件為false時,輸出字串"xxx...",異常會被丟擲,程式執行會被掛起, //未消耗的gas會被退回,合約狀態會回退到初始狀態 require( msg.sender == chairperson,"Only chairperson can give right to vote." );//執行此function的節點一定為管理員節點 require( !voters[voter].voted,"The voter already voted." );//若voter沒投過票 require(voters[voter].weight == 0); //呼叫合約的人是管理員、待授權節點還沒投過票、帶授權節點投票權重為0時,進行授權 voters[voter].weight = 1;//上述三個require()均成立時,授權票數 } //投票授權 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."); //sender滿足的條件:要有投票許可權、沒有投過票、被授權節點不是自己 //判斷代理節點地址是否為空:address(0)或者address(0x0) 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) public{ Voter storage sender = voters[msg.sender];//通過地址獲取對應投票資訊 require(!sender.voted,"Already voted.");//若sender未投過票 sender.voted = true;//更改投票狀態為已投過票 sender.vote = proposal;//儲存已投票節點 proposals[proposal].voteCount += sender.weight;//票權加和 } //返回票數最多的節點在一維陣列proposals中的索引 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; } } } //輸出票數最多的節點name function winnerName() public view returns(bytes32 winnerName_){ winnerName_ = proposals[winningProposal()].name; } }
來源於solidity文件官網:https://docs.soliditylang.org/en/v0.8.13/solidity-by-example.html