diff --git a/README.md b/README.md index a0782d8d50f977dea99a3e00b38ff3752e809d24..e3ccd343d0390618587ec358ee6b45e2db5a6a35 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,14 @@ request: **geth** Connects you to your running local geth. -## create.contract +## compile.and.deploy.contract requires: **geth**, **solc**, **jq** Compiles and deploys a contract to the blockchain. A local "node1" must already be running and synchronized. Argument 1 is the filename of the contract to compile. -Example: `create.contract src/TimestampAuthority.sol` +Example: `compile.and.deploy.contract src/TimestampAuthority.sol` ## tsa-insert.sh requires: **geth** diff --git a/bin/create.contract b/bin/compile.and.deploy.contract similarity index 100% rename from bin/create.contract rename to bin/compile.and.deploy.contract diff --git a/src/contract.Sealers.sol b/src/Sealers.sol similarity index 76% rename from src/contract.Sealers.sol rename to src/Sealers.sol index 2f1b8118811f7b97bf9e4ea10a0b85b79b44e88c..0d5391880c70287c2a6e8447c4413c79e1afbc72 100644 --- a/src/contract.Sealers.sol +++ b/src/Sealers.sol @@ -19,7 +19,7 @@ contract Sealers { address[] public sealers; Proposal[] public sealerproposals; - event vote( address voter, address victim, bool promotionOrDemotion ); + event voteCast( address voter, address victim, bool promotionOrDemotion ); event adminChange( address admin, bool promotionOrDemotion ); constructor() public @@ -56,7 +56,7 @@ contract Sealers { // Beware that: // 0 = not found. // 1 = first position. - function _findAddressInList( address[] haystack, address needle ) private view returns (uint) + function _findAddressInList( address[] haystack, address needle ) private pure returns (uint) { uint i = haystack.length; while ( i-- > 0 ) @@ -130,7 +130,8 @@ contract Sealers { // needs to be removed. function _trimProposals() private { - for ( uint i = sealerproposals.length-1; i>=0; i-- ) + uint i = sealerproposals.length; + while ( i-- > 0 ) { // If a proposal is more than 30K blocks old, then remove it from the list. if ( sealerproposals[i].votestart + 30000 <= block.number ) @@ -138,6 +139,41 @@ contract Sealers { } } + // 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 + // 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 != sealerproposals.length ) + { + uint i = sealerproposals.length; + prevlength = i; + uint majority = sealers.length / 2 + 1; + // Loop over all proposals + while ( i-- > 0 ) + { + // If we have enough votes to perform the actual promotion/demotion + if ( sealerproposals[i].voters.length >= majority ) + { + // Is it a promotion or a demotion? + if ( sealerproposals[i].promotion ) + // Add victim to sealer list + sealers.push( sealerproposals[i].victim ); + else + // Remove victim from sealer list + _remove_sealer( sealerproposals[i].victim ); + + // Send notification + emit adminChange( sealerproposals[i].victim, + sealerproposals[i].promotion ); + // Remove the proposal because the voting is complete. + _remove_proposal( i ); + } + } + } + } // Returns an index to the position of the proposal inside matching the [victim,promotion] tuple // Beware that: // 0 = not found. @@ -181,14 +217,14 @@ contract Sealers { // 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 + function vote( address victim, bool promotion ) public { if ( ! mayVote(msg.sender, victim, promotion)) revert("That seems redundant or is otherwise not allowed."); _trimProposals(); // Send notification of the vote - emit vote( msg.sender, victim, promotion ); + emit voteCast( msg.sender, victim, promotion ); uint proppos = promotionIdx( victim, promotion ); if ( proppos == 0 ) @@ -202,23 +238,12 @@ contract Sealers { // Add our vote sealerproposals[proppos].voters.push( msg.sender ); - // Stop here if we do not have enough votes to perform the actual promotion/demotion - if ( sealerproposals[proppos].voters.length < sealers.length/2+1 ) - return; - - // Remove the proposal because the voting is complete. - _remove_proposal( proppos ); - - // Is it a promotion or a demotion? - if ( promotion ) - // Add victim to sealer list - sealers.push( victim ); - else - // Remove victim from sealer list - _remove_sealer( victim ); + // See if we're ready to promote/demote anyone, based on the proposals. + _promotedemote(); - // Send notification - emit adminChange( victim, promotion ); + // If we have no more sealers, we have no reason to live. + if ( sealers.length == 0 ) + selfdestruct( msg.sender ); } }