solidity投票智慧合約程式碼

儘管我們手中空無一物發表於2022-03-28
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

相關文章