Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
nucleo
Manage
Activity
Members
Labels
Plan
Issues
4
Issue boards
Milestones
Wiki
Code
Merge requests
1
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
blockchain
nucleo
Commits
85314267
Commit
85314267
authored
6 years ago
by
Robert Martin-Legene
Browse files
Options
Downloads
Patches
Plain Diff
Generic majority voting system.
parent
16054aba
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/Majority.sol
+69
-66
69 additions, 66 deletions
src/Majority.sol
with
69 additions
and
66 deletions
src/
Sealers
.sol
→
src/
Majority
.sol
+
69
−
66
View file @
85314267
// Robert Martin-Legene <robert@nic.ar>
// vim:syntax:filetype=javascript:ai:sm
pragma solidity ^0.4.24;
// This contract is supposed to maintain the list of authorized sealers.
// For this to work, a sealer must deploy the contract and then all sealers
// must, say, every 5 minutes, run the related SealerSync.js
contract Sealers {
// This contract is supposed to maintain a list of accounts authorized
// to control members of "the club" using a majority (n/1+1).
// For instance, could be useful for
// - a list of sealers
// - a board of directors
// - a local chess club
// - even outsourcing this kind of management from another smart contract.
contract Majority {
// This struct contains a list of votes and who has voted for each victim/beneficiary.
// Votes taking longer than 30K blocks, will have to restart.
struct Proposal {
...
...
@@ -16,41 +20,41 @@ contract Sealers {
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
}
address[] p
rivate seal
ers;
Proposal[] p
rivate seal
erproposals;
address[] p
ublic vot
ers;
Proposal[] p
ublic vot
erproposals;
event voteCast( address voter, address victim, bool promotionOrDemotion );
event adminChange( address admin, bool promotionOrDemotion );
constructor() public
{
seal
ers.push( msg.sender );
vot
ers.push( msg.sender );
}
// This function is used to know how many
sealers are in the sealers l
ist.
function
seal
erLength() public view returns (uint)
// This function is used to know how many
voters ex
ist.
function
vot
er
s
Length() public view returns (uint)
{
return
seal
ers.length;
return
vot
ers.length;
}
// This function is to be used to get the address from a specific position in the
sealers
list.
// This function is to be used to get the address from a specific position in the list.
// Remember first position is 0.
// Last position is
seal
ers.length-1.
function
seal
erPosition( uint idx ) public view returns (address)
// Last position is
vot
ers.length-1.
function
vot
erPosition( uint idx ) public view returns (address)
{
require( idx <
seal
ers.length, "There are not that many
sealers registered
in the list." );
return
seal
ers[idx];
require( idx <
vot
ers.length, "There are not that many
entries
in the list." );
return
vot
ers[idx];
}
function is
Seal
er( address subject ) public view returns (bool)
function is
Vot
er( address subject ) public view returns (bool)
{
return ( _findAddressInList(
seal
ers, subject ) > 0 );
return ( _findAddressInList(
vot
ers, subject ) > 0 );
}
// Returns an index to the position of the needle inside haystack.
// Beware that:
// 0 = not found.
// 1 = first position.
// 1 = first position
in a list (so this is actually the real list position + 1)
.
function _findAddressInList( address[] haystack, address needle ) private pure returns (uint)
{
uint i = haystack.length;
...
...
@@ -64,34 +68,34 @@ contract Sealers {
{
// Move all items in the list (after idx) one step closer to the
// front of the list.
uint max =
seal
erproposals.length;
uint max =
vot
erproposals.length;
while ( ++idx < max )
seal
erproposals[idx-1] =
seal
erproposals[idx];
vot
erproposals[idx-1] =
vot
erproposals[idx];
// "pop" the end of the list, making the list shorter.
seal
erproposals.length--;
vot
erproposals.length--;
}
function _del_votes( address victim ) private
function
_del_votes( address victim ) private
{
uint i_max =
seal
erproposals.length;
uint i_max =
vot
erproposals.length;
uint i = i_max;
// check all proposals
while ( i-- > 0 )
{
// check all voters for every proposal
uint j_max =
seal
erproposals[i].voters.length;
uint j_max =
vot
erproposals[i].voters.length;
uint j = j_max;
while ( j-- > 0 )
if (
seal
erproposals[i].voters[j] == victim )
if (
vot
erproposals[i].voters[j] == victim )
{
// Found the victim as voter, but since he is about
// to be deleted, we will remove him from the list.
uint k = j;
while ( ++k < j_max )
seal
erproposals[i].voters[k-1] =
seal
erproposals[i].voters[k];
seal
erproposals[i].voters.length--;
vot
erproposals[i].voters[k-1] =
vot
erproposals[i].voters[k];
vot
erproposals[i].voters.length--;
j_max--;
if (
seal
erproposals[i].voters.length == 0 )
if (
vot
erproposals[i].voters.length == 0 )
{
_remove_proposal( i );
i_max--;
...
...
@@ -100,69 +104,70 @@ contract Sealers {
}
}
function _remove_
seal
er( address victim ) private
function _remove_
vot
er( address victim ) private
{
// Remove votes that the victim has already cast.
_del_votes( victim );
// Move all items in the list (after match) one step closer to the
// front of the list.
uint max =
seal
ers.length;
uint max =
vot
ers.length;
uint i = max;
while ( i-- > 0 )
if (
seal
ers[i] == victim )
if (
vot
ers[i] == victim )
{
// We could have recycled 'i' here, but for clarity, we don't.
uint j = i;
while ( ++j < max )
seal
ers[j-1] =
seal
ers[j];
vot
ers[j-1] =
vot
ers[j];
// "pop" the end of the list, making the list shorter.
seal
ers.length--;
vot
ers.length--;
return;
}
}
// This function sees if any proposals have overstayed their welcome and thus
// needs to be removed.
// needs to be removed. This is a bit like spring cleaning. We remove proposals
// that are over 30k blocks old.
function _trimProposals() private
{
uint i =
seal
erproposals.length;
uint i =
vot
erproposals.length;
while ( i-- > 0 )
{
// If a proposal is more than 30K blocks old, then remove it from the list.
if (
seal
erproposals[i].votestart + 30000 <= block.number )
if (
vot
erproposals[i].votestart + 30000 <= block.number )
_remove_proposal( i );
}
}
// We run through the entire list of proposals, checking if they fulfill the
// requirements. Why the whole list? Because if a
sealer is
removed, whom has
// requirements. Why the whole list? Because if a
voter has been
removed, whom has
// not yet voted for a proposal, that proposal may now have achieved majority.
function _promotedemote() private
{
uint prevlength = 0;
// Keep looping over the list until the number of proposals stops changing.
while ( prevlength !=
seal
erproposals.length )
while ( prevlength !=
vot
erproposals.length )
{
uint i =
seal
erproposals.length;
uint i =
vot
erproposals.length;
prevlength = i;
uint majority =
seal
ers.length / 2 + 1;
uint majority =
vot
ers.length / 2 + 1;
// Loop over all proposals
while ( i-- > 0 )
{
// If we have enough votes to perform the actual promotion/demotion
if (
seal
erproposals[i].voters.length >= majority )
if (
vot
erproposals[i].voters.length >= majority )
{
// Is it a promotion or a demotion?
if (
seal
erproposals[i].promotion )
// Add victim to
seal
er list
seal
ers.push(
seal
erproposals[i].victim );
if (
vot
erproposals[i].promotion )
// Add victim to
memb
er list
vot
ers.push(
vot
erproposals[i].victim );
else
// Remove victim from
seal
er list
_remove_
sealer( seal
erproposals[i].victim );
// Remove victim from
memb
er list
_remove_
voter( vot
erproposals[i].victim );
// Send notification
emit adminChange(
seal
erproposals[i].victim,
seal
erproposals[i].promotion );
emit adminChange(
vot
erproposals[i].victim,
vot
erproposals[i].promotion );
// Remove the proposal because the voting is complete.
_remove_proposal( i );
}
...
...
@@ -175,9 +180,9 @@ contract Sealers {
// 1 = first position.
function promotionIdx( address victim, bool promotion ) public view returns (uint)
{
uint i =
seal
erproposals.length;
uint i =
vot
erproposals.length;
while ( i-- > 0)
if (
seal
erproposals[i].victim == victim &&
seal
erproposals[i].promotion == promotion )
if (
vot
erproposals[i].victim == victim &&
vot
erproposals[i].promotion == promotion )
return i+1;
return 0;
}
...
...
@@ -186,24 +191,22 @@ contract Sealers {
// will get accepted. Save the network, call this first.
function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
{
// Is caller a
seal
er?
if ( !is
Seal
er(voter) )
// Is caller a
vot
er?
if ( !is
Vot
er(voter) )
return false;
// Is already Sealer and want to promote him?
// Can't promote someone who is already a sealer.
bool victimSealer = isSealer( victim );
if ( victimSealer && promotion )
// Can't promote someone who is already a voter.
bool victimVoter = isVoter( victim );
if ( victimVoter && promotion )
return false;
// Is not Sealer and want to demote him?
// Can't demote someone who is not a sealer.
if ( !victimSealer && !promotion )
// Can't demote someone who is not a member.
if ( !victimVoter && !promotion )
return false;
// See if the voter is already in the list of voters for this [victim,promotion] tuple
uint proppos = promotionIdx( victim, promotion );
if ( proppos > 0 && _findAddressInList(
seal
erproposals[proppos-1].voters, voter ) > 0 )
if ( proppos > 0 && _findAddressInList(
vot
erproposals[proppos-1].voters, voter ) > 0 )
return false;
return true;
}
...
...
@@ -211,7 +214,7 @@ contract Sealers {
// Calling this function will vote for adding an additional or
// removing an existing member of "the inner circle".
// As per usual, this requires n/2+1 votes.
// The boolean must be true if you want to add a
seal
er
// The boolean must be true if you want to add a
memb
er
// and false if you want to remove one.
function vote( address victim, bool promotion ) public
{
...
...
@@ -227,18 +230,18 @@ contract Sealers {
{
// This is a new proposal, so we will add it, so we can vote on it.
address[] memory emptyAddressList;
proppos =
seal
erproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
proppos =
vot
erproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
}
proppos--;
// Add our vote
seal
erproposals[proppos].voters.push( msg.sender );
vot
erproposals[proppos].voters.push( msg.sender );
// See if we're ready to promote/demote anyone, based on the proposals.
_promotedemote();
// If we have no more
seal
ers, we have no reason to live.
if (
seal
ers.length == 0 )
// If we have no more
vot
ers, we have no reason to live.
if (
vot
ers.length == 0 )
selfdestruct( msg.sender );
}
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment