上一篇我們介紹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()
查詢獲勝提案。
這個智能合約叫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。
下一篇我們將繼續改進這個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;
}
}
}