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

Merge branch 'sealers' of https://gitlab.bfa.ar/blockchain/nucleo

parents 3de7a8fe 996b109d
No related branches found
No related tags found
No related merge requests found
......@@ -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**
......
File moved
pragma solidity ^0.4.22;
// 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 occasionally (every 5 minutes) run the related SealerSync.js
// must, say, 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.
uint256 votestart; // In which block did this vote begin?
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
address victim; // Whom are we voting about.
uint votestart; // In which block did this vote begin?
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
}
address[] public sealers;
Proposal[] public sealerproposals;
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 {
sealers[0] = msg.sender;
constructor() public
{
sealers.push( msg.sender );
}
// 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;
}
function sealerIdx( address needle ) public view returns (int256) {
return findAddressInList( sealers, needle );
}
// This function is to be used to know how many sealers are in the sealers list.
function sealerLength() public view returns (uint256) {
// This function is used to know how many sealers are in the sealers list.
function sealerLength() public view returns (uint)
{
return sealers.length;
}
// 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) {
function sealerPosition( uint 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 isSealer( address subject ) public view returns (bool)
{
return ( _findAddressInList( sealers, subject ) > 0 );
}
function requireSealer( address subject ) public view {
function requireSealer( address subject ) public view
{
require( isSealer(subject), "Not sealer" );
}
function _remove_entry( uint256 idx, list alist ) private returns (list) {
uint256 pos = idx;
// Returns an index to the position of the needle inside haystack.
// Beware that:
// 0 = not found.
// 1 = first position.
function _findAddressInList( address[] haystack, address needle ) private pure returns (uint)
{
uint i = haystack.length;
while ( i-- > 0 )
if ( needle == haystack[i] )
return i+1;
return 0;
}
function _remove_proposal( uint idx ) private
{
// 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];
uint max = sealerproposals.length;
while ( ++idx < max )
sealerproposals[idx-1] = sealerproposals[idx];
// "pop" the end of the list, making the list shorter.
alist.length--;
return alist;
sealerproposals.length--;
}
function _del_votes( address victim ) private
{
uint i_max = sealerproposals.length;
uint i = i_max;
// check all proposals
while ( i-- > 0 )
{
// check all voters for every proposal
uint j_max = sealerproposals[i].voters.length;
uint j = j_max;
while ( j-- > 0 )
if ( sealerproposals[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 )
sealerproposals[i].voters[k-1] = sealerproposals[i].voters[k];
sealerproposals[i].voters.length--;
j_max--;
if ( sealerproposals[i].voters.length == 0 )
{
_remove_proposal( i );
i_max--;
}
}
}
}
function _remove_sealer( 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 = sealers.length;
uint i = max;
while ( i-- > 0 )
if ( sealers[i] == victim )
{
// We could have recycled 'i' here, but for clarity, we don't.
uint j = i;
while ( ++j < max )
sealers[j-1] = sealers[j];
// "pop" the end of the list, making the list shorter.
sealers.length--;
return;
}
}
// This function sees if any proposals have overstayed their welcome and thus
// needs to be removed.
function _trimProposals() private {
for ( uint256 i = sealerproposals.length-1; i>=0; i-- )
function _trimProposals() private
{
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 )
sealerproposals = _remove_entry( i, sealerproposals );
_remove_proposal( i );
}
}
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;
// 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.
// 1 = first position.
function promotionIdx( address victim, bool promotion ) public view returns (uint)
{
uint i = sealerproposals.length;
while ( i-- > 0)
if ( sealerproposals[i].victim == victim && sealerproposals[i].promotion == promotion )
return i+1;
return 0;
}
// You can call this for free and know if your promote call
......@@ -104,9 +205,9 @@ contract Sealers {
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 )
// 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( sealerproposals[proppos-1].voters, voter ) > 0 )
return false;
return true;
}
......@@ -116,48 +217,33 @@ 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.");
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 );
// signed as opposed to unsigned (int)
int256 signedretval = promotionIdx( victim, promotion );
uint proppos;
if ( signedretval == -1 )
uint proppos = promotionIdx( victim, promotion );
if ( proppos == 0 )
{
// 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 ) );
}
else
proppos = uint256( signedretval & 0x7fffffffffffffffffffffffffffffff );
// Make things a bit more easy to read by using a shorter variable name
Proposal memory prop = sealerproposals[proppos];
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;
sealerproposals[proppos].voters.push( msg.sender );
// Remove the proposal because the voting is complete.
sealerproposals = _remove_entry( proppos, sealerproposals );
// See if we're ready to promote/demote anyone, based on the proposals.
_promotedemote();
// Is it a promotion or a demotion?
if ( promotion )
// Add victim to sealer list
sealers.push( victim );
else
// Remove victim from sealer list
sealers = _remove_entry( sealerIdx(victim), sealers );
// 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 );
}
}
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