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

Bugs weeded out. Sealers.sol now needs testnet trials.

parent 07b58ff8
No related branches found
No related tags found
No related merge requests found
#!/bin/bash
# 20180618 Robert Martin-Legene <robert@nic.ar>
if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source bfa/bin/env ?" >&2; exit 1; fi
source ${BFAHOME}/bin/libbfa.sh || exit 1
function create
{
workdir=$( mktemp -p . -d )
cleanup "$workdir"
json=$( solc --optimize --combined-json abi,bin $filename ); test $? = 0
prefix=$( echo "$json" | jq -M '.contracts | keys | .[0]' );
abi=$( echo "$json" | jq -rM ".contracts.${prefix}.abi" ); test $? = 0
bin=$( echo "$json" | jq -rM ".contracts.${prefix}.bin" ); test $? = 0
# Save abi for future use
echo $abi > ${workdir}/abi
# We could save the bin, but we don't actually use it later, plus
# it gets stored in the blockchain
#echo $bin > ${workdir}/bin
js=$( mktemp )
cleanup "$js"
cat > $js <<EOT
var mycontract = eth.contract($abi)
var transaction = mycontract.new( { from: eth.accounts[0], data: "0x${bin}", gas: 1000000 } )
var rcpt
while ( !rcpt )
{
admin.sleepBlocks( 1 )
rcpt = eth.getTransactionReceipt( transaction.transactionHash )
}
var address = rcpt.contractAddress
var pubcontract = mycontract.at(address)
console.log( pubcontract.address )
EOT
echo '*** Creating contract. This will take at least 16 seconds.'
outfile=$( mktemp )
cleanup "$outfile"
geth_exec_file $js > $outfile
if [ ` wc -l < $outfile ` = 2 -a `tail -1 < $outfile` = "true" ]
then
addr=` head -1 < $outfile `
mkdir -p ${BFANETWORKDIR}/contracts
mv ${workdir} ${BFANETWORKDIR}/contracts/${addr}
echo Your new contract can be found in ${BFANETWORKDIR}/contracts/${addr}
ln -snf ${addr} ${BFANETWORKDIR}/contracts/${contractname}
else
echo
echo ' *** INPUT ***'
echo
cat $js
echo
echo ' *** OUTPUT ***'
echo
cat $outfile
fi
}
filename="$1"
if [ -z "$filename" -o ! -r "$filename" ]
then
echo "Specify a filename of a contract you wish to compile."
false
fi
contractname=${filename%%.sol}
contractname=${contractname##*/}
contractname=${contractname##contract.}
contractname=${contractname%.*}
bfaconfig max
prereq jq solc geth
create
......@@ -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 );
}
}
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