投票机制设计

公链

说明:转载请说明出处,无端盗用必追责!

黑名单功能

使用:

1. 限制交易,即在gossipswitch提供blacklist,限制某些账户的交易;

2. 惩罚机制,如果被列入黑名单,不能参与出块;

设计:

1. 发起黑名单请求(必须是超级节点,才能发起设置黑名单的请求),附带惩罚原因,或者是公示的标记;

2. 超级节点对黑名单的提议内容进行审核投票,为了快速达成一致,超过1/3节点投票通过即设置;

3. 支持黑名单的设置和取消功能,建议投票超过2/3才能取消;

4. 投票过程分为两种:投赞成票,弃权(不进行投票);

5. 支持移除黑名单,也采用投票机制;

6. 一旦对某个黑名单进行投票,则不能取消;

代码实现:

  1 pragma solidity >=0.4.24 <0.6.0;
  2 
  3 /*
  4 * 安全操作函数
  5 *  SafeMath to avoid data overwrite
  6 */
  7 library SafeMath {
  8     function mul(uint a, uint b) internal pure returns (uint) {
  9         uint c = a * b;
 10         require(a == 0 || c / a == b, "overwrite error");
 11         return c;
 12     }
 13  
 14     function div(uint a, uint b) internal pure returns (uint) {
 15         require(b > 0, "overwrite error");
 16         uint c = a / b;
 17         require(a == b * c + a % b, "overwrite error");
 18         return c;
 19     }
 20  
 21     function sub(uint a, uint b) internal pure returns (uint) {
 22         require(b <= a, "overwrite error");
 23         return a - b;
 24     }
 25  
 26     function add(uint a, uint b) internal pure returns (uint) {
 27         uint c = a + b;
 28         require(c>=a && c>=b, "overwrite error");
 29         return c;
 30     }
 31 }
 32 
 33 contract JustitiaRight {
 34     uint256 public totalSupply;
 35     
 36     function lockCount(address _account, uint _count) public;
 37     function unlockCount(address _account, uint _count) public;
 38     function residePledge(address _owner) public view returns(uint balance);
 39     
 40     function balanceOf(address _owner) public view returns (uint256 balance);
 41     function transfer(address _to, uint256 _value) public returns (bool success);
 42     function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
 43     function approve(address _spender, uint256 _value) public returns (bool success);
 44     function allowance(address _owner, address _spender) public view returns (uint256 remaining);
 45 }
 46 
 47 contract CandidateManage {
 48     
 49     using SafeMath for uint;
 50     uint256 public totalPledge;
 51     uint constant MINIMUM_PLEDGE_TOKEN = 100;
 52   
 53     JustitiaRight public justitia;
 54     
 55     struct Candidate{
 56         address account;
 57         uint pledge;   // total support pledge
 58         string memo;
 59         uint ranking;
 60         bool isValid;
 61     }
 62     address [] public CandidateList;
 63     mapping(address => Candidate) public candidateLookup;
 64     // mapping(support, totalPledge)
 65     mapping(address => uint256) public balanceOfPledge;
 66 
 67     // event define
 68     event ApplyToCandidateEvent(address, bool, string);
 69     
 70     // criterias that be a candidate 
 71     function candidateCriteria(address candidate, uint256 pledge) private view returns(bool){
 72         uint256 balance = justitia.residePledge(candidate);
 73         if(MINIMUM_PLEDGE_TOKEN <= balance && balance >= pledge){
 74             return true;
 75         }
 76         return false;
 77     }
 78     
 79     // role classify
 80     // normal: account with PR, which has right to vote
 81     // participate: normal account which has participate in vote and has peldge currently
 82     // candidate: account pledge PR to be a candidate
 83     function isNormal(address _account) public view returns(bool){
 84         if(!isParticipate(_account) && !isCandidate(_account)){
 85             return true;
 86         }
 87         return false;
 88     }
 89     
 90     function isParticipate(address _account) public view returns(bool){
 91         if (0 != balanceOfPledge[_account]){
 92             return true;
 93         }
 94         return false;
 95     }
 96   
 97     function isCandidate(address account) public view returns(bool){
 98         return candidateLookup[account].isValid;
 99     }
100     
101     // get account balance statistic
102     function balanceStatistic(address _owner) public view returns (uint256 balance, uint256 pledge){
103         require(address(0) != _owner);
104         
105         uint256 total;
106         uint256 reside;
107         
108         total = justitia.balanceOf(_owner);
109         reside = justitia.residePledge(_owner);
110         
111         require(total.sub(reside) == balanceOfPledge[_owner]);
112         
113         return (total, balanceOfPledge[_owner]);
114     }
115     
116     // get candidate information
117     function candidateState(address candidate) public view returns(uint256, uint256, string){
118         require(isCandidate(candidate));
119         uint index;
120         for(index = 0; index < CandidateList.length; index++){
121             if(CandidateList[index] == candidate){
122                 break;
123             }    
124         }
125         return (index, candidateLookup[candidate].pledge, candidateLookup[candidate].memo);
126     }
127     
128     // find index to insert the account by specified candidate in CandidateList
129     function findIndexOfCandidate(uint pledge) private view returns(uint){
130         uint index;
131         for(index = 0; index < CandidateList.length; index++){
132             if(candidateLookup[CandidateList[index]].pledge <= pledge){
133                 break;
134             }
135         }
136         return index;
137     }
138     
139     // add applicant to candidate list
140     function addToCandidateListDescending(address applicant, uint pledge) private returns(uint){
141         uint index;
142         index = findIndexOfCandidate(pledge);
143         CandidateList.push(applicant);
144         for(uint i = CandidateList.length - 1; i > index; i--){
145             CandidateList[i] = CandidateList[i - 1];
146             candidateLookup[CandidateList[i]].ranking = i;
147         }
148         CandidateList[index] = applicant;
149         candidateLookup[CandidateList[index]].ranking = index;
150         return index;
151     }
152     
153     // candidate list adjustment
154     function adjustCandidateList(address candidate, uint pledge) public returns(uint){
155         if(!isCandidate(candidate)){
156             return addToCandidateListDescending(candidate, pledge);
157         } 
158         
159         uint currentIndex;
160         uint rightIndex;
161         for(currentIndex = 0; currentIndex < CandidateList.length; currentIndex++){
162             if(CandidateList[currentIndex] == candidate){
163                 break;
164             }
165             if(candidateLookup[CandidateList[rightIndex]].pledge >= candidateLookup[candidate].pledge){
166                 rightIndex++;
167             }
168             
169         }
170         
171         // adding
172         if(rightIndex < currentIndex){
173             for(uint i = currentIndex; i > rightIndex; i--){
174                 CandidateList[i] = CandidateList[i - 1];
175                 candidateLookup[CandidateList[i]].ranking = i;
176             }
177         } else {
178             for(uint j = currentIndex; j < rightIndex; j++){
179                 CandidateList[j] = CandidateList[j + 1];
180                 candidateLookup[CandidateList[j]].ranking = j;
181             }
182         }
183         
184         CandidateList[rightIndex] = candidate;
185         candidateLookup[CandidateList[rightIndex]].ranking = rightIndex;
186         return rightIndex;
187     }
188     
189     // apply to candidate 
190     function ApplyToCandidate(uint pledge, string memo) public returns(bool, string){
191         require(!isCandidate(msg.sender));
192         
193         string memory errors;
194         if(!candidateCriteria(msg.sender, pledge)){
195             errors = "errors: some criterias not met.";
196             emit ApplyToCandidateEvent(msg.sender, false, errors);
197             return (false, errors);
198         }
199         
200         totalPledge = totalPledge.add(pledge);
201         justitia.lockCount(msg.sender, pledge);
202         balanceOfPledge[msg.sender] = balanceOfPledge[msg.sender].add(pledge);
203         adjustCandidateList(msg.sender, pledge);
204         candidateLookup[msg.sender].memo = memo;
205         candidateLookup[msg.sender].isValid = true;
206         candidateLookup[msg.sender].pledge = candidateLookup[msg.sender].pledge.add(pledge);
207         candidateLookup[msg.sender].account = msg.sender;
208         emit ApplyToCandidateEvent(msg.sender, true, errors);
209         return (true, errors);
210     }
211     
212     // get candidates
213     function Candidates() public view returns(address[]){
214         return CandidateList;
215     }
216 }
217 
218 
219 contract BlackListElection {
220     using SafeMath for uint;
221     struct BlackListItem{
222         string reason;
223         address []approveAccounts;
224         address []rejectAccounts;
225         mapping(address => bool) approveRecords;
226         mapping(address => bool) rejectRecoeds;
227         bool isValid;
228         uint index;
229     }
230     mapping(address => BlackListItem) public blackListItemLookup;
231     address [] public blackListProcessing;
232     
233     function isRegiste(address _account) public view returns(bool){
234         return blackListItemLookup[_account].isValid;
235     }
236     
237     function toBlackList(address _account, string reason) public returns(uint){
238         if(!isRegiste(_account)){
239             blackListItemLookup[_account].reason = reason;
240             blackListItemLookup[_account].approveAccounts.push(_account);
241             blackListItemLookup[_account].approveRecords[msg.sender] = true;
242             blackListItemLookup[_account].isValid = true;
243             blackListItemLookup[_account].index = blackListProcessing.push(_account).sub(1);
244         } else {
245             if(!blackListItemLookup[_account].approveRecords[msg.sender]){
246                 blackListItemLookup[_account].approveAccounts.push(_account);
247                 blackListItemLookup[_account].approveRecords[msg.sender] = true;
248             }
249         }
250         return blackListItemLookup[_account].approveAccounts.length;
251     }
252     
253     function blackListToProcess() public view returns(address[]){
254         return blackListProcessing;
255     }
256     
257     function removeBlackList(address _account) public {
258         require(isRegiste(_account));
259         delete blackListProcessing[blackListItemLookup[_account].index];
260         delete blackListItemLookup[_account];
261     }
262 }
263 
264 
265 contract BlackListManage is BlackListElection{
266     
267     uint public thresHoldToAddBlackList;
268     uint public thresHoldToRrmoveBlackList;
269     
270     struct BlackList {
271         uint date;
272         bool isValid;
273     }
274     mapping(address => BlackList) public blackListLookup;
275     address [] public blackList;
276     
277     event AddToBlackListEvent(address, string);
278     
279     function isInBlackList(address _account) public view returns(bool){
280         return blackListLookup[_account].isValid;
281     }
282     
283     function voteForBlacklist(address _account, string comment) public {
284         uint supporters = toBlackList(_account, comment);
285         if (supporters >=  thresHoldToAddBlackList){
286             blackListLookup[_account].date = now;
287             blackListLookup[_account].isValid = true;
288             blackList.push(_account);
289             removeBlackList(_account);
290             emit AddToBlackListEvent(_account, blackListItemLookup[_account].reason);
291         }
292     }
293     
294     function getBlackList() public view returns(address[]){
295         return blackList;
296     }
297     
298 }
299 
300 /* 
301 *  系统合约调用
302 *  管理选举情况,包括:选举,取消选举,选举情况统计等
303 */
304 contract ElectionManage is CandidateManage, BlackListManage {
305     
306     using SafeMath for uint;
307     uint public totalNodes;
308     uint constant ENTRY_HRESHOLD = 100;
309     bool private mainNetSwitch;
310     uint constant MAINNET_ONLINE_THRESHOLD = 1000;
311     
312     event MainNetOnlineEvent(uint, uint);
313     event IssueVoteEvent(address, address, uint);
314     event AdjustmentVoteEvent(address, address, uint);
315     
316     struct Election{
317         bool isValid;
318         address[] participates;
319         mapping(address => uint) election; 
320     }
321     // record candidate election
322     mapping(address => Election) private candidateElection;
323     
324     // constructor
325     constructor (address token, uint nodeNum) public {
326         justitia = JustitiaRight(token);
327         totalNodes = nodeNum;
328         thresHoldToAddBlackList = nodeNum.div(3);
329         thresHoldToRrmoveBlackList = thresHoldToAddBlackList.mul(2) + 1;
330     }
331     
332     // try to online main network
333     // we assume that once mainnet onlie, it will onlie forever 
334     function tryToOnlineMainNet() private {
335         // only state changed, emit event
336         if(!mainNetSwitch){
337             if(totalPledge >= MAINNET_ONLINE_THRESHOLD){
338                 mainNetSwitch = true;
339                 emit MainNetOnlineEvent(now, totalPledge);
340             }
341         }
342     }
343     
344     // to get the pledge of participate for specified candidate
345     function getPledgeFlow(address candidate, address participate) public view returns(uint){
346         require(isCandidate(candidate));
347         return candidateElection[candidate].election[participate];
348     }
349     
350     // to get all supporters of the specified candidate
351     function getSupportOfCandidate(address candidate) public view returns(address[]){
352         require(isCandidate(candidate));
353         return candidateElection[candidate].participates;
354     }
355     
356     // get rank of candidate
357     function ranking(address _candidate) public view returns(uint){
358         require(isCandidate(_candidate));
359         require(address(0) != _candidate);
360         uint index;
361         uint rank;
362         for(index = 0; index < CandidateList.length; index++){
363             if(isCandidate(_candidate)){
364                 rank++;
365                 if(_candidate == CandidateList[index]){
366                     return rank;
367                 }
368             }
369         }
370     }
371     
372     // issue a election for candidate with some pledges
373     function issueVote(address candidate, uint pledge) private {
374         require(isCandidate(candidate));
375         require(!isCandidate(msg.sender));
376         require(pledge <= justitia.residePledge(msg.sender));
377         
378         if(!candidateElection[candidate].isValid){
379             candidateElection[candidate].participates.push(msg.sender);
380             candidateElection[candidate].isValid = true;
381         }
382         candidateLookup[candidate].pledge = candidateLookup[candidate].pledge.add(pledge);
383         candidateElection[candidate].election[msg.sender] = candidateElection[candidate].election[msg.sender].add(pledge);
384         adjustCandidateList(candidate, candidateLookup[candidate].pledge);
385         balanceOfPledge[msg.sender] = balanceOfPledge[msg.sender].add(pledge);
386         totalPledge = totalPledge.add(pledge);
387         justitia.lockCount(msg.sender, pledge);
388         
389         emit IssueVoteEvent(msg.sender, candidate, pledge);
390     }
391     
392     // to adjustment of voting for specified candidate with pledge
393     function adjustmentVote(address candidate, uint pledge) private {
394         require(isCandidate(candidate));
395         require(pledge <= candidateElection[candidate].election[msg.sender]);
396         
397         candidateLookup[candidate].pledge = candidateLookup[candidate].pledge.sub(pledge);
398         candidateElection[candidate].election[msg.sender] = candidateElection[candidate].election[msg.sender].sub(pledge);
399         adjustCandidateList(candidate, candidateLookup[candidate].pledge);
400         balanceOfPledge[msg.sender] = balanceOfPledge[msg.sender].sub(pledge);
401         totalPledge = totalPledge.sub(pledge);
402         justitia.unlockCount(msg.sender, pledge);
403         
404         emit AdjustmentVoteEvent(msg.sender, candidate, pledge);
405     }
406     
407     function rightToVoteBlackList(address _account) private view returns(bool){
408         require(isCandidate(_account));
409         if(candidateLookup[_account].ranking < totalNodes){
410             return true;
411         }
412         return false;
413     }
414     
415     function GetOnlineSymbol() public view returns(bool){
416         return mainNetSwitch;
417     }
418     
419     function VoteAdjustment(address candidate, uint canceledPledge) public {
420         require(isCandidate(candidate));
421         adjustmentVote(candidate, canceledPledge);
422     }
423     
424     function Votting(address candidate, uint pledge) public{
425         require(isCandidate(candidate));
426         issueVote(candidate, pledge);
427         tryToOnlineMainNet();
428     }
429     
430     function SetBlackList(address _account) public{
431         require(rightToVoteBlackList(msg.sender));
432         if(!isInBlackList(_account)){
433             voteForBlacklist(_account, "errors");
434         }
435     }
436 }
View Code

 

posted @ 2019-02-26 14:52  yunlion  阅读(885)  评论(0编辑  收藏  举报