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
// vim:syntax:filetype=javascript:ai:sm
pragma solidity ^0.4.24;
pragma solidity ^0.4.24;
// This contract is supposed to maintain the list of authorized sealers.
// This contract is supposed to maintain a list of accounts authorized
// For this to work, a sealer must deploy the contract and then all sealers
// to control members of "the club" using a majority (n/1+1).
// must, say, every 5 minutes, run the related SealerSync.js
// For instance, could be useful for
// - a list of sealers
contract 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.
// 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.
// Votes taking longer than 30K blocks, will have to restart.
struct Proposal {
struct Proposal {
...
@@ -16,41 +20,41 @@ contract Sealers {
...
@@ -16,41 +20,41 @@ contract Sealers {
bool promotion; // true=promotion, false=demotion
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
address[] voters; // List of voters.
}
}
address[] p
rivate seal
ers;
address[] p
ublic vot
ers;
Proposal[] p
rivate seal
erproposals;
Proposal[] p
ublic vot
erproposals;
event voteCast( address voter, address victim, bool promotionOrDemotion );
event voteCast( address voter, address victim, bool promotionOrDemotion );
event adminChange( address admin, bool promotionOrDemotion );
event adminChange( address admin, bool promotionOrDemotion );
constructor() public
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.
// This function is used to know how many
voters ex
ist.
function
seal
erLength() public view returns (uint)
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.
// Remember first position is 0.
// Last position is
seal
ers.length-1.
// Last position is
vot
ers.length-1.
function
seal
erPosition( uint idx ) public view returns (address)
function
vot
erPosition( uint idx ) public view returns (address)
{
{
require( idx <
seal
ers.length, "There are not that many
sealers registered
in the list." );
require( idx <
vot
ers.length, "There are not that many
entries
in the list." );
return
seal
ers[idx];
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.
// Returns an index to the position of the needle inside haystack.
// Beware that:
// Beware that:
// 0 = not found.
// 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)
function _findAddressInList( address[] haystack, address needle ) private pure returns (uint)
{
{
uint i = haystack.length;
uint i = haystack.length;
...
@@ -64,34 +68,34 @@ contract Sealers {
...
@@ -64,34 +68,34 @@ contract Sealers {
{
{
// Move all items in the list (after idx) one step closer to the
// Move all items in the list (after idx) one step closer to the
// front of the list.
// front of the list.
uint max =
seal
erproposals.length;
uint max =
vot
erproposals.length;
while ( ++idx < max )
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.
// "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;
uint i = i_max;
// check all proposals
// check all proposals
while ( i-- > 0 )
while ( i-- > 0 )
{
{
// check all voters for every proposal
// 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;
uint j = j_max;
while ( j-- > 0 )
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
// Found the victim as voter, but since he is about
// to be deleted, we will remove him from the list.
// to be deleted, we will remove him from the list.
uint k = j;
uint k = j;
while ( ++k < j_max )
while ( ++k < j_max )
seal
erproposals[i].voters[k-1] =
seal
erproposals[i].voters[k];
vot
erproposals[i].voters[k-1] =
vot
erproposals[i].voters[k];
seal
erproposals[i].voters.length--;
vot
erproposals[i].voters.length--;
j_max--;
j_max--;
if (
seal
erproposals[i].voters.length == 0 )
if (
vot
erproposals[i].voters.length == 0 )
{
{
_remove_proposal( i );
_remove_proposal( i );
i_max--;
i_max--;
...
@@ -100,69 +104,70 @@ contract Sealers {
...
@@ -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.
// Remove votes that the victim has already cast.
_del_votes( victim );
_del_votes( victim );
// Move all items in the list (after match) one step closer to the
// Move all items in the list (after match) one step closer to the
// front of the list.
// front of the list.
uint max =
seal
ers.length;
uint max =
vot
ers.length;
uint i = max;
uint i = max;
while ( i-- > 0 )
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.
// We could have recycled 'i' here, but for clarity, we don't.
uint j = i;
uint j = i;
while ( ++j < max )
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.
// "pop" the end of the list, making the list shorter.
seal
ers.length--;
vot
ers.length--;
return;
return;
}
}
}
}
// This function sees if any proposals have overstayed their welcome and thus
// 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
function _trimProposals() private
{
{
uint i =
seal
erproposals.length;
uint i =
vot
erproposals.length;
while ( i-- > 0 )
while ( i-- > 0 )
{
{
// If a proposal is more than 30K blocks old, then remove it from the list.
// 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 );
_remove_proposal( i );
}
}
}
}
// We run through the entire list of proposals, checking if they fulfill the
// 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.
// not yet voted for a proposal, that proposal may now have achieved majority.
function _promotedemote() private
function _promotedemote() private
{
{
uint prevlength = 0;
uint prevlength = 0;
// Keep looping over the list until the number of proposals stops changing.
// 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;
prevlength = i;
uint majority =
seal
ers.length / 2 + 1;
uint majority =
vot
ers.length / 2 + 1;
// Loop over all proposals
// Loop over all proposals
while ( i-- > 0 )
while ( i-- > 0 )
{
{
// If we have enough votes to perform the actual promotion/demotion
// 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?
// Is it a promotion or a demotion?
if (
seal
erproposals[i].promotion )
if (
vot
erproposals[i].promotion )
// Add victim to
seal
er list
// Add victim to
memb
er list
seal
ers.push(
seal
erproposals[i].victim );
vot
ers.push(
vot
erproposals[i].victim );
else
else
// Remove victim from
seal
er list
// Remove victim from
memb
er list
_remove_
sealer( seal
erproposals[i].victim );
_remove_
voter( vot
erproposals[i].victim );
// Send notification
// Send notification
emit adminChange(
seal
erproposals[i].victim,
emit adminChange(
vot
erproposals[i].victim,
seal
erproposals[i].promotion );
vot
erproposals[i].promotion );
// Remove the proposal because the voting is complete.
// Remove the proposal because the voting is complete.
_remove_proposal( i );
_remove_proposal( i );
}
}
...
@@ -175,9 +180,9 @@ contract Sealers {
...
@@ -175,9 +180,9 @@ contract Sealers {
// 1 = first position.
// 1 = first position.
function promotionIdx( address victim, bool promotion ) public view returns (uint)
function promotionIdx( address victim, bool promotion ) public view returns (uint)
{
{
uint i =
seal
erproposals.length;
uint i =
vot
erproposals.length;
while ( i-- > 0)
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 i+1;
return 0;
return 0;
}
}
...
@@ -186,24 +191,22 @@ contract Sealers {
...
@@ -186,24 +191,22 @@ contract Sealers {
// will get accepted. Save the network, call this first.
// will get accepted. Save the network, call this first.
function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
{
{
// Is caller a
seal
er?
// Is caller a
vot
er?
if ( !is
Seal
er(voter) )
if ( !is
Vot
er(voter) )
return false;
return false;
// Is already Sealer and want to promote him?
// Can't promote someone who is already a voter.
// Can't promote someone who is already a sealer.
bool victimVoter = isVoter( victim );
bool victimSealer = isSealer( victim );
if ( victimVoter && promotion )
if ( victimSealer && promotion )
return false;
return false;
// Is not Sealer and want to demote him?
// Can't demote someone who is not a member.
// Can't demote someone who is not a sealer.
if ( !victimVoter && !promotion )
if ( !victimSealer && !promotion )
return false;
return false;
// See if the voter is already in the list of voters for this [victim,promotion] tuple
// See if the voter is already in the list of voters for this [victim,promotion] tuple
uint proppos = promotionIdx( victim, promotion );
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 false;
return true;
return true;
}
}
...
@@ -211,7 +214,7 @@ contract Sealers {
...
@@ -211,7 +214,7 @@ contract Sealers {
// Calling this function will vote for adding an additional or
// Calling this function will vote for adding an additional or
// removing an existing member of "the inner circle".
// removing an existing member of "the inner circle".
// As per usual, this requires n/2+1 votes.
// 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.
// and false if you want to remove one.
function vote( address victim, bool promotion ) public
function vote( address victim, bool promotion ) public
{
{
...
@@ -227,18 +230,18 @@ contract Sealers {
...
@@ -227,18 +230,18 @@ contract Sealers {
{
{
// This is a new proposal, so we will add it, so we can vote on it.
// This is a new proposal, so we will add it, so we can vote on it.
address[] memory emptyAddressList;
address[] memory emptyAddressList;
proppos =
seal
erproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
proppos =
vot
erproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
}
}
proppos--;
proppos--;
// Add our vote
// 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.
// See if we're ready to promote/demote anyone, based on the proposals.
_promotedemote();
_promotedemote();
// If we have no more
seal
ers, we have no reason to live.
// If we have no more
vot
ers, we have no reason to live.
if (
seal
ers.length == 0 )
if (
vot
ers.length == 0 )
selfdestruct( msg.sender );
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