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
e83f5ac2
Commit
e83f5ac2
authored
6 years ago
by
Robert Martin-Legene
Browse files
Options
Downloads
Plain Diff
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
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
README.md
+2
-2
2 additions, 2 deletions
README.md
bin/compile.and.deploy.contract
+0
-0
0 additions, 0 deletions
bin/compile.and.deploy.contract
src/Sealers.sol
+163
-77
163 additions, 77 deletions
src/Sealers.sol
with
165 additions
and
79 deletions
README.md
+
2
−
2
View file @
e83f5ac2
...
...
@@ -47,14 +47,14 @@ request: **geth**
Connects you to your running local geth.
## c
reate
.contract
## c
ompile.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:
`c
reate
.contract src/TimestampAuthority.sol`
Example:
`c
ompile.and.deploy
.contract src/TimestampAuthority.sol`
## tsa-insert.sh
requires:
**geth**
...
...
This diff is collapsed.
Click to expand it.
bin/c
reate
.contract
→
bin/c
ompile.and.deploy
.contract
+
0
−
0
View file @
e83f5ac2
File moved
This diff is collapsed.
Click to expand it.
src/Sealers.sol
+
163
−
77
View file @
e83f5ac2
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.
uint
256
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 vote
Cast
( 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, sealer
proposal
s
);
_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] tup
p
le
int
256
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
u
int
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 vote
Cast
( 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 );
}
}
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