iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
0
Blockchain

商管學生如何從零開始學習區塊鏈系列 第 16

DAY16 Solidity的投票例子

  • 分享至 

  • xImage
  •  

上一篇我們介紹Solidity中的地址(address)、映射(mapping)和消息(msg),今天我將帶大家看看Solidity中的voting例子,我們一樣使用Remix IDE (https://remix.ethereum.org/),接著使用Solidity官方文件中Solidity by Example的voting例子(https://solidity.readthedocs.io/en/v0.5.11/),在我們的voting(投票)範例中,會有一個主席(也就是發起投票的人),跟投票的人(會由主席選出來),我們將主席的投票權重設為2 (主席一票抵其他人兩票,你也可以設為1),其他人的投票權重設為1,我們所用的範例會跟Solidity上有一點不同,因為我們將用來委託投票權的delegate函數拿掉,讓投票不這麼複雜,讓我簡單介紹我們等等會用到的函數,我們用constructor(uint numProposals)建立我們的提案,用function giveRightToVote(address voter) 賦予投票人投票權,用function vote(uint toProposal) 進行投票,最後用function winningProposal()查詢獲勝提案。
https://ithelp.ithome.com.tw/upload/images/20190927/20120814RmQykvX29y.jpg
這個智能合約叫Ballot,Ballot是不記名投票的意思,投票一定要有投票人跟提案,所以我們使用struct 來把相關的不同資料串在一起,常用的例子是學生的資料會包含學號、姓名或成績等變數,回到我們的例子,投票人包含:投票的權重、他有沒有投票以及該投票人的選擇,提案包含: 每一個的提案的票數。

contract Ballot {

    struct Voter {
        uint weight;
        bool voted;
        uint vote;
    }

    struct Proposal {
        uint voteCount;
    }

下面定義了主席(投票發起人)、所有投票人和所有提案,我們使用映射mapping將地址映射到我們的投票人

    address chairperson;
    mapping(address => Voter) voters;
    Proposal[] proposals;

下面建立我們的提案,並由主席賦予投票人投票權,我們將主席的投票權重設為2 (主席1票抵其他人2票,你也可以設為1)

    constructor(uint _numProposals) public {
        chairperson = msg.sender;
        voters[chairperson].weight = 2;
        proposals.length = _numProposals;
    }

    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 vote(uint toProposal) public {
        Voter storage sender = voters[msg.sender];
        require(sender.weight != 0, "Has no right to vote");
        require(!sender.voted, "Already voted.");
        sender.voted = true;
        sender.vote = toProposal;
        proposals[toProposal].voteCount += sender.weight;
    }

下面查詢獲勝提案。

    function winningProposal() public view returns (uint _winningProposal) {
        uint256 winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++)
            if (proposals[p].voteCount > winningVoteCount) {
                winningVoteCount = proposals[p].voteCount;
                _winningProposal = p;
            }
    }

現在我們來看看運行的結果,我們選擇JavaScript VM並編譯部署這個智能合約,在部署時要決定有多少提案,我們使用3個(提案0、1、2),我們將第一個地址為0xCa3開頭的地址作為主席,首先,我們讓主席賦予一個人投票權,並在開始投票,我們選擇1號或2號提案進行投票,主席投給提案1,另一個投票人投給提案2,因為主席投票權重為2,所以票數等同兩票。因此你可以在winsProposal看到勝利的提案是提案1。
https://ithelp.ithome.com.tw/upload/images/20190927/201208141CpdR1pEQ6.jpg

下一篇我們將繼續改進這個Solidity的投票範例,我將在下一篇介紹enum(列舉)及時間,那我們明天見~

程式碼

pragma solidity >=0.4.22 <0.7.0;
contract Ballot {

    struct Voter {
        uint weight;
        bool voted;
        uint vote;
    }
    struct Proposal {
        uint voteCount;
    }

    address chairperson;
    mapping(address => Voter) voters;
    Proposal[] proposals;

    constructor(uint _numProposals) public {
        chairperson = msg.sender;
        voters[chairperson].weight = 2;
        proposals.length = _numProposals;
    }

    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 vote(uint toProposal) public {
        Voter storage sender = voters[msg.sender];
        require(sender.weight != 0, "Has no right to vote");
        require(!sender.voted, "Already voted.");
        sender.voted = true;
        sender.vote = toProposal;
        proposals[toProposal].voteCount += sender.weight;
    }

    function winningProposal() public view returns (uint _winningProposal) {
        uint256 winningVoteCount = 0;
        for (uint p = 0; p < proposals.length; p++)
            if (proposals[p].voteCount > winningVoteCount) {
                winningVoteCount = proposals[p].voteCount;
                _winningProposal = p;
            }
    }
}

上一篇
DAY15 address (地址)、mapping (映射)和msg (消息)
下一篇
DAY17 enum(列舉)和時間
系列文
商管學生如何從零開始學習區塊鏈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言