我們已經將原本Solidity官方文件的voting例子(https://solidity.readthedocs.io/en/v0.5.11/)做了許多改進,首先我們將用來委託投票權的delegate函數拿掉,讓投票不這麼複雜,接著我們介紹enum(列舉),可以將狀態分成Init(初始狀態)、Reg(註冊狀態)、Vote(投票狀態)和Done(完成狀態),並且設定經過多少時間可以進入到下一階段,但是我們的voting例子還有改進空間。
所以今天我們除了要把enum(列舉)和時間加入我們的投票例子外,還要來使用modifier函數,你可以將modifier當作函數(function)的守門員,modifier幫助我們在執行某個行為(函數)前檢查前置條件,通常使用require來檢查條件,如果條件失敗,可以使用revert()來拒絕該交易並恢復所有的狀態更改,我們這裡使用modifiers檢查狀態,簡單來說,modifier就是把函數執行前的檢查邏輯抽出來了。
modifier validStage(Stage reqStage)
{ require(stage == reqStage);
_;
}
用modifier 定義validStage, 再透過 validStage 檢查狀態是否為定義的狀態。
function register(address toVoter) public validStage(Stage.Reg) {
…..
}
function vote(uint8 toProposal) public validStage(Stage.Vote) {
…..
}
function winningProposal() public view validStage(Stage.Done) returns (uint8 _winningProposal) {
…..
}
現在我們把enum的狀態、時間以及modifier加入我們的voting(投票)範例中,完成這個voting(投票)的例子,今天我們介紹完modifiers後,將我們的投票例子做了許多的改善,也幫助大家更熟悉使用Solidity編寫智能合約,下一篇我將介紹區塊鏈的雙花攻擊(Double Spend Attack),那我們明天見~
程式碼
pragma solidity >=0.4.22 <0.6.0;
contract Ballot {
struct Voter {
uint weight;
bool voted;
uint8 vote;
}
struct Proposal {
uint voteCount;
}
enum Stage {Init,Reg, Vote, Done}
Stage public stage = Stage.Init;
address chairperson;
mapping(address => Voter) voters;
Proposal[] proposals;
uint startTime;
modifier validStage(Stage reqStage)
{ require(stage == reqStage);
_;
}
constructor(uint8 _numProposals) public {
chairperson = msg.sender;
voters[chairperson].weight = 2;
proposals.length = _numProposals;
stage = Stage.Reg;
startTime = now;
}
function register(address toVoter) public validStage(Stage.Reg) {
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
voters[toVoter].voted = false;
if (now > (startTime+ 10 seconds)) {stage = Stage.Vote; }
}
function vote(uint8 toProposal) public validStage(Stage.Vote) {
Voter storage sender = voters[msg.sender];
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
if (now > (startTime+ 30 seconds)) {stage = Stage.Done;}
}
function winningProposal() public view validStage(Stage.Done) returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}