iT邦幫忙

0

Solidity實現投票功能

  • 分享至 

  • xImage
  •  

使用solidity實現基本的投票並且去操作功能,像是投票,發票或是委託票等。

創建contract
https://ithelp.ithome.com.tw/upload/images/20220426/20108931aO5ZWnPDoI.png

Solidity by Example — Solidity 0.8.10 documentation (soliditylang.org)

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/// @title Voting with delegation.
contract Voting {
    
    // 選民
    struct Voter {
        uint weight; // weight is accumulated by delegation
        bool voted;  // if true, that person already voted
        address delegate; // 被委託人 person delegated to
        uint vote;   // 投票提案的索引 index of the voted proposal
    }

    // This is a type for a single proposal.
    struct Proposal {
        string name;   // short name (up to 32 bytes)
        uint voteCount; // number of accumulated votes
    }

    address public chairperson;

    // This declares a state variable that
    // stores a `Voter` struct for each possible address.
    mapping(address => Voter) public voters;

    // A dynamically-sized array of `Proposal` structs.
    Proposal[] public proposals;

    // 為`proposalNames` 中的每個提案,創建一個新投票表決 Create a new ballot to choose one of `proposalNames`.
    constructor(string[] memory proposalNames) {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;

        // 對每一提案名稱,創建一個新的Proposal並添加到array
        for (uint i = 0; i < proposalNames.length; i++) {
            // `Proposal({...})` creates a temporary
            // Proposal object and `proposals.push(...)`
            // appends it to the end of `proposals`.
            proposals.push(Proposal({
                name: proposalNames[i],
                voteCount: 0
            }));
        }
    }

    // 授權voter對這個表決進行投票,只有chairperson能調用此函數
    function giveRightToVote(address voter) external {
        // If the first argument of `require` evaluates
        // to `false`, execution terminates and all
        // changes to the state and to Ether balances
        // are reverted.
        // This used to consume all gas in old EVM versions, but
        // not anymore.
        // It is often a good idea to use `require` to check if
        // functions are called correctly.
        // As a second argument, you can also provide an
        // explanation about what went wrong.
        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;
    }

    /// 將您的投票委託給選民 voter `to`.
    function delegate(address to) external {
        // assigns reference
        Voter storage sender = voters[msg.sender];
        require(!sender.voted, "You already voted.");

        require(to != msg.sender, "Self-delegation is disallowed.");

        // Forward the delegation as long as
        // `to` also delegated.
        // In general, such loops are very dangerous,
        // because if they run too long, they might
        // need more gas than is available in a block.
        // In this case, the delegation will not be executed,
        // but in other situations, such loops might
        // cause a contract to get "stuck" completely.
        while (voters[to].delegate != address(0)) {
            to = voters[to].delegate;

            // We found a loop in the delegation, not allowed.
            require(to != msg.sender, "Found loop in delegation.");
        }

        // Since `sender` is a reference, this modifies `voters[msg.sender].voted`
        sender.voted = true;
        sender.delegate = to;
        Voter storage delegate_ = voters[to];
        if (delegate_.voted) {
            // If the delegate already voted,
            // directly add to the number of votes
            proposals[delegate_.vote].voteCount += sender.weight;
        } else {
            // If the delegate did not vote yet,
            // add to her weight.
            delegate_.weight += sender.weight;
        }
    }

    /// 把你的票(包括委託給你的票),投給提案`proposals[proposal].name`.
    function vote(uint proposal) external {
        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 = proposal;

        // If `proposal` is out of the range of the array,
        // this will throw automatically and revert all
        // changes.
        proposals[proposal].voteCount += sender.weight;
    }

    /// @dev Computes the winning proposal taking all
    /// previous votes into account.
    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;
            }
        }
    }

    // Calls winningProposal() function to get the index
    // of the winner contained in the proposals array and then
    // returns the name of the winner
    function winnerName() external view
            returns (string memory winnerName_)
    {
        winnerName_ = proposals[winningProposal()].name;
    }
}

測試

啟動節點模擬

使用Remix

Compile
6836d7755c7f47e9d9968d03d963102f.png

Deploy合約
60dcbda1e6fb9b626bf32a42971da503.png

Output:
01a42accd383115e71bb7f2a0cc666ca.png

測試環節

測試Proposals
c41a256adb6ddb4d5e74e7f4eb0d41ad.png
ec2ace9a949252c68b2b6828906e45eb.png
結果
7cf338dc0710f7c6d010bab3fd485e1b.png

chairperson
e7b48c98bf1819e87e938545b0a6b3be.png
f3ddc2c074769fe9d3691d4f3d323f7c.png

chairperson(0xac55502aF00E1F405f115C17F45D43c36C47F7C3)給其他人票:
b5747b3d057a8069cf752a86eedbfee6.png

91248b3a2723be21181060f45997dc92.png
dfa40f2058113e31c7db89516cbe4b10.png
其他也是:
0xF197FFB0422d7026809210826325bfa719105251
0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3
0x9AD3eB9367f6B123a843AcF946e4D360c445FB9d

測試非Chairperson給其他人票:
28a7f09e7a7942092216d701d825690a
出現ERROR:
6b2de3ffc6f39cc46ee968bc366dd34d
Output
bf38ca023c06dd9a531fd6627694ed6b

測試Voter:
ffbd08e166bbddb3e22d921110c33de6.png
f25eef82869bd061a8a2d70e0e7635e3.png
5c7d3c18e0bd0498e8b4f0178b6d4426.png

接著切換帳戶:
0xF197FFB0422d7026809210826325bfa719105251
將自己的票委託給他人(0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3):
7782111f4b8d5767b184026a0b427738.png
00f86906c6a8040498549947acd013bc.png

使用看Voter函數來觀察:
587cf0d82be3660e1facb6a451814760.png

測試投票:
0xF197FFB0422d7026809210826325bfa719105251
5df311b3ed3db7bd7221dca18795fd1a.png
2ffce6578af5e74817d11de5550720cd.png
(我們把票給別人了,無法投,並且先看一下propsal)
9260e0e053c89ee645efeca41703bfba.png
能看到沒有投成功
834c890042afc1541f94fc1f328d9add.png

切換成其他人開始投票:
0x7CB7374abE10dDd7e16b3dfe5E68623DAb1b13F3
0x9AD3eB9367f6B123a843AcF946e4D360c445FB9d
執行vote
76a1125299a3e9dfa09f0873a9438c8c.png
5ff749732431754ff317ebb3d246e551.png
接著看proposal(Alice, Bob):
02953c4bf5ce86b50cea475500955786.png

呼叫WINNERNAME和WINNINGPROPOSAL
2297887d4239991f95b92da765d5e315.png
bee24a7df5dea92ab6e26c8bcb0c0ca7.png

合約內的東西都測試完畢


Reference:

Solidity by Example


歡迎大家來我的Blog看:

1.Blog: 文章連結


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言