Skip to content
Snippets Groups Projects
Commit 223fcc24 authored by Robert Martin-Legene's avatar Robert Martin-Legene
Browse files

Major rewrite of the Sealers contract. Bugs weeded out, and more public functions.

parent 113e0725
No related branches found
No related tags found
No related merge requests found
pragma solidity ^0.4.22;
// 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 occasionally (every 5 minutes) run the related SealerSync.js
contract Sealers {
// 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 {
address victim; // Whom are we voting about.
uint votestart; // In which block did this vote begin?
uint256 votestart; // In which block did this vote begin?
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
}
Proposal[] public adminproposals;
address[] public sealers;
Proposal[] public sealerproposals;
event vote( address voter, address victim, bool promotionOrDemotion );
event adminChange( address admin, bool promotionOrDemotion );
......@@ -18,107 +24,139 @@ contract Sealers {
sealers[0] = msg.sender;
}
function isSealer( address subj ) public view returns (bool) {
for (uint i=sealers.length; i>0; i--)
{
if (subj == sealers[i-1])
return true;
}
return false;
}
modifier onlySealersTX {
require( isSealer( tx.origin ), "tx.origin is not a known sealer and can not call this function." );
_;
// Public utility, works on any list needle and haystack given.
//
// Returns an index to the position of the needle inside haystack.
// 0 is first position. -1 means not found.
function findAddressInList( address[] haystack, address needle ) public pure returns (int256) {
uint256 i = haystack.length;
while ( i-- > 0 )
if ( needle == haystack[i] )
return int256(i & 0x7fffffffffffffffffffffffffffffff);
return -1;
}
modifier onlySealers {
require( isSealer( msg.sender ), "msg.sender is not a known sealer and can not call this function." );
_;
function sealerIdx( address needle ) public view returns (int256) {
return findAddressInList( sealers, needle );
}
function sealerLength() public view returns (uint) {
// This function is to be used to know how many sealers are in the sealers list.
function sealerLength() public view returns (uint256) {
return sealers.length;
}
function sealerPosition( uint idx ) public view returns (address) {
require( idx <= sealers.length, "There are not that many sealers registered in the list." );
// This function is to be used to get the address from a specific position in the sealers list.
// Remember first position is 0.
// Last position is sealers.length-1.
function sealerPosition( uint256 idx ) public view returns (address) {
require( idx < sealers.length, "There are not that many sealers registered in the list." );
return sealers[idx];
}
function isSealer( address subject ) public view returns (bool) {
return ( sealerIdx(subject) > -1 );
}
function requireSealer( address subject ) public view {
require( isSealer(subject), "Not sealer" );
}
function _remove_entry( uint256 idx, list alist ) private returns (list) {
uint256 pos = idx;
// Move all items in the list (after idx) one step closer to the
// front of the list.
while ( ++pos < list.length )
alist[pos-1] = alist[pos];
// "pop" the end of the list, making the list shorter.
alist.length--;
return alist;
}
// This function sees if any proposals have overstayed their welcome and thus
// needs to be removed.
function _trimProposals() private {
uint i = adminproposals.length;
while ( i-- > 0 )
for ( uint256 i = sealerproposals.length-1; i>=0; i-- )
{
if ( adminproposals[i].votestart < block.number+30000 )
{
while ( i < adminproposals.length )
{
adminproposals[i] = adminproposals[i+1];
i--;
}
adminproposals.length--;
}
// If a proposal is more than 30K blocks old, then remove it from the list.
if ( sealerproposals[i].votestart + 30000 <= block.number )
sealerproposals = _remove_entry( i, sealerproposals );
}
}
function admin_promote( address victim, bool promotion ) public onlySealersTX {
// Janitor
_trimProposals();
bool isS = isSealer(victim);
function promotionIdx( address victim, bool promotion ) public view return (int256) {
uint256 idx = sealerproposals.length;
while ( idx-- > 0)
if ( sealerproposals[idx].victim == victim && sealerproposals[idx].promotion == promotion )
return idx;
return -1;
}
// You can call this for free and know if your promote call
// will get accepted. Save the network, call this first.
function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
{
// Is caller a sealer?
if ( !isSealer(voter) )
return false;
// Is already Sealer and want to promote him?
if ( isS && promotion )
revert("You can't promote someone who is already a sealer.");
// Can't promote someone who is already a sealer.
if ( isSealer(victim) && promotion )
return false;
// Is not Sealer and want to demote him?
if ( !isS && !promotion )
revert("You can't demote someone who is not a sealer.");
// First see if we can find the index of an already running proposal for this victim,promotion tupple.
uint proppos = adminproposals.length;
while ( proppos>0 && adminproposals[proppos-1].victim != victim && adminproposals[proppos-1].promotion != promotion)
proppos--;
// If we found no matching proposals, we will add it, so we can now vote on it.
if (proppos == 0)
// Can't demote someone who is not a sealer.
if ( !isSealer(victim) && !promotion )
return false;
// See if the voter is already in the list of voters for this [victim,promotion] tupple
int256 proppos = promotionIdx( victim, promotion );
if ( proppos > -1 && findAddressInList( sealerproposals[proppos].voters, voter ) > -1 )
return false;
return true;
}
// 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 sealer
// and false if you want to remove one.
function promote( address victim, bool promotion ) public {
if ( ! mayVote(msg.sender, victim, promotion))
revert("That seems redundant.");
_trimProposals();
// Send notification of the vote
emit vote( msg.sender, victim, promotion );
// signed as opposed to unsigned (int)
int256 signedretval = promotionIdx( victim, promotion );
uint proppos;
if ( signedretval == -1 )
{
address[] memory sillycompiler;
proppos = adminproposals.push( Proposal(victim, block.number, promotion, sillycompiler ) );
// This is a new proposal, so we will add it, so we can vote on it.
address[] memory emptyAddressList;
proppos = sealerproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
}
// substract one, to make proppos actually reflect the position in the index.
proppos--;
else
proppos = uint256( signedretval & 0x7fffffffffffffffffffffffffffffff );
// Make things a bit more easy to read by using a shorter variable name
Proposal memory prop = adminproposals[proppos];
// Now look through the proposal and see if this sender already voted.
uint voterpos = prop.voters.length;
while ( voterpos>0 && prop.voters[voterpos-1] != msg.sender )
voterpos--;
// Return if sender already voted
if ( voterpos > 0 )
revert("You can not vote twice.");
// Send notification of the valid vote
emit vote( msg.sender, victim, promotion );
// Do we have enough votes to perform the operation?
Proposal memory prop = sealerproposals[proppos];
// Add our vote
prop.voters.push( msg.sender );
// Stop here if we do not have enough votes to perform the actual promotion/demotion
if ( prop.voters.length < sealers.length/2+1 )
return;
//
// Remove the proposal because the voting is complete.
sealerproposals = _remove_entry( proppos, sealerproposals );
// Is it a promotion or a demotion?
if ( prop.promotion )
{
if ( promotion )
// Add victim to sealer list
sealers.push( victim );
}
else
{
uint i = sealers.length;
// Delete all occurences of the victim from the sealer list (should be just a single occurence)
while ( i-- > 0 ) {
if (sealers[i] == victim )
{
for (uint j=i; j<sealers.length-1; j--)
sealers[j] = sealers[j+1];
sealers.length--;
}
}
}
// Remove the proposal, as the voting is complete.
for (i=proppos; i<adminproposals.length-1; i--)
adminproposals[i] = adminproposals[i+1];
adminproposals.length--;
// Remove victim from sealer list
sealers = _remove_entry( sealerIdx(victim), sealers );
// Send notification
emit adminChange( victim, promotion );
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment