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

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

parents 38d4c753 1af2b2be
No related branches found
No related tags found
No related merge requests found
......@@ -12,3 +12,5 @@ test2network*/bootnode
test2network*/contracts/*
test2network/*.pid
node_modules
src/*/*.bin
src/*/*.abi
......@@ -259,7 +259,7 @@ grep -q Ubuntu /etc/issue && apt-add-repository multiverse
#
apt update
# development tools
aptinstall dirmngr apt-transport-https curl git curl build-essential sudo
aptinstall dirmngr apt-transport-https curl git curl build-essential sudo software-properties-common
aptinstall jq libjson-perl libwww-perl libclass-accessor-perl
userconfig
nodejsinstall
......
// Robert Martin-Legene <robert@nic.ar>
// vim:syntax:filetype=javascript:ai:sm
pragma solidity ^0.5;
// This contract is supposed to maintain a list of accounts authorized
// to control members of "the club" using a majority (n/1+1).
// For instance, could be useful for
// - a list of sealers
// - a board of directors
// - a local chess club
// - even outsourcing this kind of management from another smart contract.
contract Majority {
// 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?
bool promotion; // true=promotion, false=demotion
address[] voters; // List of voters.
}
address[] public voters;
Proposal[] public voterproposals;
event voteCast( address voter, address victim, bool promotionOrDemotion );
event adminChange( address admin, bool promotionOrDemotion );
constructor() public
{
// Don't want anyone to find a way to trigger the constructor again.
if ( voters.length == 0 )
voters.push( msg.sender );
}
// This function is used to know how many voters exist.
function votersLength() public view returns (uint)
{
return voters.length;
}
// This function is to be used to get the address from a specific position in the list.
// Remember first position is 0.
// Last position is voters.length-1.
function voterPosition( uint idx ) public view returns (address)
{
require( idx < voters.length, "There are not that many entries in the list." );
return voters[idx];
}
function isVoter( address subject ) public view returns (bool)
{
return ( _findAddressInList( voters, subject ) > 0 );
}
// Returns an index to the position of the needle inside haystack.
// Beware that:
// 0 = not found.
// 1 = first position in a list (so this is actually the real list position + 1).
function _findAddressInList( address[] memory 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.
uint max = voterproposals.length;
while ( ++idx < max )
voterproposals[idx-1] = voterproposals[idx];
// "pop" the end of the list, making the list shorter.
voterproposals.length--;
}
function _del_votes( address victim ) private
{
uint i_max = voterproposals.length;
uint i = i_max;
// check all proposals
while ( i-- > 0 )
{
// check all voters for every proposal
uint j_max = voterproposals[i].voters.length;
uint j = j_max;
while ( j-- > 0 )
if ( voterproposals[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 )
voterproposals[i].voters[k-1] = voterproposals[i].voters[k];
voterproposals[i].voters.length--;
j_max--;
if ( voterproposals[i].voters.length == 0 )
{
_remove_proposal( i );
i_max--;
}
}
}
}
function _remove_voter( 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 = voters.length;
uint i = max;
while ( i-- > 0 )
if ( voters[i] == victim )
{
// We could have recycled 'i' here, but for clarity, we don't.
uint j = i;
while ( ++j < max )
voters[j-1] = voters[j];
// "pop" the end of the list, making the list shorter.
voters.length--;
return;
}
}
// This function sees if any proposals have overstayed their welcome and thus
// needs to be removed. This is a bit like spring cleaning. We remove proposals
// that are over 30k blocks old.
function _trimProposals() private
{
uint i = voterproposals.length;
while ( i-- > 0 )
{
// If a proposal is more than 30K blocks old, then remove it from the list.
if ( voterproposals[i].votestart + 30000 <= block.number )
_remove_proposal( i );
}
}
// We run through the entire list of proposals, checking if they fulfill the
// requirements. Why the whole list? Because if a voter has been 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 != voterproposals.length )
{
uint i = voterproposals.length;
prevlength = i;
uint majority = voters.length / 2 + 1;
// Loop over all proposals
while ( i-- > 0 )
{
// If we have enough votes to perform the actual promotion/demotion
if ( voterproposals[i].voters.length >= majority )
{
// Is it a promotion or a demotion?
if ( voterproposals[i].promotion )
// Add victim to member list
voters.push( voterproposals[i].victim );
else
// Remove victim from member list
_remove_voter( voterproposals[i].victim );
// Send notification
emit adminChange( voterproposals[i].victim,
voterproposals[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 = voterproposals.length;
while ( i-- > 0)
if ( voterproposals[i].victim == victim && voterproposals[i].promotion == promotion )
return i+1;
return 0;
}
// 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 voter?
if ( !isVoter(voter) )
return false;
// Can't promote someone who is already a voter.
bool victimVoter = isVoter( victim );
if ( victimVoter && promotion )
return false;
// Can't demote someone who is not a member.
if ( !victimVoter && !promotion )
return false;
// 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( voterproposals[proppos-1].voters, voter ) > 0 )
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 member
// and false if you want to remove one.
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 voteCast( msg.sender, victim, promotion );
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 = voterproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
}
proppos--;
// Add our vote
voterproposals[proppos].voters.push( msg.sender );
// See if we're ready to promote/demote anyone, based on the proposals.
_promotedemote();
// If we have no more voters, we have no reason to live.
if ( voters.length == 0 )
selfdestruct( msg.sender );
}
}
#!/usr/bin/node
"use strict"
const Libbfa = require( process.env.BFAHOME + '/bin/libbfa.js');
const BigInteger = require( 'big-integer' );
const fs = require( 'fs' );
var bfa = new Libbfa();
var web3 = bfa.newweb3();
// default
var gasprice = BigInteger(10).pow(9);
// globals
var accounts;
var thecontract;
function cat(filename)
{
try {
return fs.readFileSync( filename ).toString();
} catch (err) {
throw( 'Errors: ' + err.syscall + ' ' + err.path + ': ' + err.code);
}
}
function plural(num, one, many)
{
if (num == 1)
return one;
return many;
}
function isittrue( thebool, errortext )
{
return new Promise((resolve,reject) => {
if ( undefined == thebool )
reject( "thebool is undefined: " + errortext );
else
if ( thebool == true )
{
console.log( "Test OK: " + errortext );
resolve();
}
else
reject( errortext );
})
}
function echo( txt )
{
return new Promise((resolve,reject) => {
console.log( txt );
resolve();
})
}
function getgasprice()
{
return new Promise( (resolve, reject) => {
web3.eth.getGasPrice()
.then(
(sat) => {
gasprice = BigInteger(sat);
resolve();
},
reject
)
})
}
function unlockall()
{
return new Promise((resolve,reject) => {
var proms = new Array();
accounts.forEach(
(addr) => {
proms.push(
web3.eth.personal.unlockAccount( addr, '', 600 )
);
}
)
Promise.all( proms )
.then( resolve )
.catch( reject );
})
}
function gettestaccountnames()
{
return new Promise( (resolve, reject) => {
accounts = new Array();
web3.bfa.personal.listWallets(
( walletlist ) => {
walletlist.forEach(
( wallet ) => {
wallet.accounts.forEach(
( account ) => {
var addr = account.address;
if ( addr.startsWith('0x7e57') )
accounts.push( addr );
}
)
}
)
accounts.sort();
resolve();
}
);
})
}
function getaccountbalances()
{
return new Promise((resolve,reject) => {
if ( accounts.length < 4 )
throw( "Too few test accounts (found " + accounts.length + ", but need 4)." );
var proms = new Array();
var minimum = BigInteger(10).pow(9);
var failtxt;
accounts.forEach(
( acct ) => {
proms.push(
web3.eth.getBalance(acct)
.then(
( bal ) => {
var val = BigInteger( bal );
if ( val.lesser( minimum ) )
{
if ( undefined == failtxt )
failtxt +=
"The minimum balance on each test account must be at least "
+ minimum
+ " satoshi.\n"
failtxt +=
"The account balance of "
+ accounts[i]
+ " is "
+ val
+ " satoshi.\n"
}
}
)
)
}
);
Promise.all( proms )
.then(
() => {
if ( undefined == failtxt )
resolve();
else
reject(
failtxt +
"Tests can not be performed without balance on the accounts."
);
}
);
});
}
function councillistdetails()
{
return new Promise((resolve,reject) => {
thecontract.methods.councilLength.call()
.then(
(howmany) => {
console.log(
'The council has '
+ howmany
+ ' member'
+ plural(howmany,'','s')
+ '.');
return( howmany );
}
)
.then(
(howmany) => {
var proms = new Array();
for ( var i=0 ; i<howmany ; i++ )
proms.push( thecontract.methods.council(i).call() );
Promise.all( proms )
.then( (addrlist) => {
addrlist.forEach( (addr)=>{console.log("Council member: "+addr)} );
resolve( howmany );
});
}
);
})
}
function voteslistdetails()
{
return new Promise((resolve,reject) => {
thecontract.methods.votesLength.call()
.then(
(howmany) => {
console.log(
'There '
+ plural(howmany,'is ','are ')
+ howmany
+ ' vote'
+ plural(howmany,'','s')
+ ' registered.');
return( howmany );
}
)
.then(
(howmany) => {
var proms = new Array();
for ( var i=0 ; i<howmany ; i++ )
proms.push( thecontract.methods.votes(i).call() );
Promise.all( proms )
.then( (list) => {
list.forEach( (obj)=>{
console.log(
'Lodged vote: '
+ obj.voter
+ ' has voted to '
+ (obj.promotion?'promote':'demote')
+ ' '
+ obj.victim
);
} );
resolve( howmany );
});
}
);
})
}
function deploynew()
{
return new Promise((resolve, reject) => {
var abi = JSON.parse( cat('Majority.abi').trim() );
var bin = cat('Majority.bin').trim();
var cAddress;
var fetus = new web3.eth.Contract( abi );
console.log( "Deploying contract." );
var timeout = BigInteger( 86400 );
fetus.deploy(
{
data: '0x'+bin,
arguments: [ '0x'+timeout.toString(16) ]
}
)
.send(
{
from: accounts[0],
gas: 3000000,
gasPrice: '0x'+gasprice.toString(16),
}
)
.on( 'transactionHash', (hash) => {
console.log( "Deployed in txhash " + hash + "." );
})
.on( 'confirmation', (num,obj) => {
if ( undefined == cAddress )
{
cAddress = obj.contractAddress;
thecontract = new web3.eth.Contract( abi, cAddress );
console.log( "Contract is at " + cAddress );
resolve();
}
})
.on( 'error', reject );
});
}
function isCouncil( acctpos )
{
return new Promise((resolve,reject) => {
var acct = accounts[acctpos];
thecontract.methods.isCouncil(acct).call()
.then(
(yesno) => {
var not = 'not ';
if (yesno)
not = '';
console.log( acct + ' is ' + not + 'a council member.' );
resolve(yesno);
}
)
.catch( reject )
})
}
function vote( voterpos, victimpos, promotion )
{
return new Promise((resolve,reject) => {
var voter = accounts[voterpos];
var victim = accounts[victimpos];
var confirmed = false;
var demote = 'demote';
if (promotion)
demote = 'promote';
console.log( voter + " voting to " + demote + " " + victim );
thecontract.methods.vote( victim, promotion ).send({
from: voter,
gasPrice: "0x"+gasprice.toString(16),
gas: '0x'+BigInteger(10).pow(6).toString(16)
})
.on( 'transactionHash', (txhash) => {
console.log( ' - txhash ' + txhash );
})
.on( 'receipt', (rcpt) => {
console.log( ' - got a receipt' );
})
.on( 'confirmation', (num,obj) => {
if ( ! confirmed )
{
confirmed = true;
resolve();
}
})
.on( 'error', reject )
})
}
function mayVote(voterpos, victimpos, promotion)
{
return new Promise((resolve,reject) => {
var voter = accounts[voterpos];
var victim = accounts[victimpos];
var demote = 'demote';
if (promotion)
demote = 'promote';
thecontract.methods.mayVote( voter, victim, promotion ).call()
.then( (may) => {
var not = 'not ';
if ( may )
not = '';
console.log( voter + " may " + not + "vote to " + demote + " " + victim );
resolve( may );
},
reject
);
})
}
getgasprice()
.then( gettestaccountnames )
.then( getaccountbalances )
.then( unlockall )
.then( deploynew )
// initial conditions after deploying the contract
.then( councillistdetails )
.then( (n) => {return isittrue( n==1, "There should be 1 account in the council list." )})
.then( voteslistdetails )
.then( (n) => {return isittrue( n==0, "There should be no entries in the list of registered votes." )})
.then( () => {return isCouncil(0)} )
.then( (b) => {return isittrue( b, "Account should be a voter." )})
.then( () => {return isCouncil(1)} )
.then( (b) => {return isittrue( !b, "Account should not be a voter." )})
// Adding second account to the council - takes effect immediately, so votes.length == 0
.then( () => {return mayVote(0,1,true)} )
.then( (b) => {return isittrue( b, "Account should be allowed to vote for the approval of the new account." )})
.then( () => {return vote(0,1,true)} )
.then( voteslistdetails )
.then( (n) => {return isittrue( n==0, "There should be no entries in the list of registered votes." )})
.then( councillistdetails )
.then( (n) => {return isittrue( n==2, "There should be 2 accounts in the council list." )})
// Start voting to include third account
.then( () => {return mayVote(1,2,true)} )
.then( (b) => {return isittrue( b, "Account should be allowed to vote for the approval of the new account." )})
.then( () => {return vote(1,2,true)} )
.then( voteslistdetails )
.then( (n) => {return isittrue( n==1, "There should be 1 entry in the list of registered votes." )})
.then( councillistdetails )
.then( (n) => {return isittrue( n==2, "There should be 2 accounts in the council list." )})
// Start voting to remove second account (using second account)
.then( () => {return mayVote(1,1,false)} )
.then( (b) => {return isittrue( b, "Account should be allowed to vote for the removal of the account." )})
.then( () => {return vote(1,1,false)} )
.then( voteslistdetails )
.then( (n) => {return isittrue( n==2, "There should be 2 entries in the list of registered votes." )})
.then( councillistdetails )
.then( (n) => {return isittrue( n==2, "There should be 2 accounts in the council list." )})
// Finalizing vote to remove second account
.then( () => {return mayVote(0,1,false)} )
.then( (b) => {return isittrue( b, "Account should be allowed to vote for the removal of the account." )})
.then( () => {return vote(0,1,false)} )
.then( voteslistdetails )
.then( (n) => {return isittrue( n==0, "There should be no entries in the list of registered votes." )})
.then( councillistdetails )
.then( (n) => {return isittrue( n==1, "There should be 1 account in the council list." )})
// Vote to remove 3rd account.
.then( () => {return mayVote(0,2,true)} )
.then( (b) => {return isittrue( b, "Account should be allowed to vote for the approval of the new account." )})
.then( () => {return vote(0,2,true)} )
.then( voteslistdetails )
.then( (n) => {return isittrue( n==0, "There should be no entries in the list of registered votes." )})
.then( councillistdetails )
.then( (n) => {return isittrue( n==2, "There should be 1 account in the council list." )})
// this should self-destruct the contract
.then( () => {return vote(0,0,false)} )
.catch( (x) => {bfa.fatal("Test FAIL: " + x)})
.finally( () => {
console.log('** All tests completed successfully **');
process.exit();
});
// Robert Martin-Legene <robert@nic.ar>
// vim:syntax:filetype=javascript:ai:sm
pragma solidity ^0.5;
// This contract is supposed to maintain a list of accounts authorized
// to control members of "the club" using a majority (n/1+1). We call
// that group the "council".
// For instance, could be useful for
// - a list of sealers
// - a board of directors
// - a local chess club
// - even outsourcing this kind of management from another smart contract.
contract Majority {
// This struct contains a list of votes and who has voted for each victim/beneficiary.
struct Vote {
address voter; // Voter.
address victim; // Whom are we voting about.
uint voteStart; // When was the vote cast
bool promotion; // true=promotion, false=demotion
}
address[] public council;
Vote[] public votes;
uint public votetimeout = 604800; // default a week
event voteCast( address voter, address victim, bool promotion );
event adminChange( address admin, bool promotion );
constructor( uint timeout ) public
{
if ( timeout >= 3600 )
votetimeout = timeout;
council.push( address(msg.sender) );
}
function setTimeout( uint timeout ) public
{
if ( ! isCouncil(msg.sender) )
revert("Only council members may use this function.");
if ( timeout >= 3600 )
votetimeout = timeout;
}
function councilLength() public view returns (uint)
{
return council.length;
}
function votesLength() public view returns (uint)
{
return votes.length;
}
// True or false if the subject is a member of the council.
function isCouncil( address subject ) public view returns (bool)
{
uint i = council.length;
while ( i-- > 0 )
if ( subject == council[i] )
return true;
return false;
}
// Move all items in the list (after idx) one step closer to the
// front of the list.
function _remove_vote( uint idx ) private
{
uint max = votes.length;
while ( ++idx < max )
votes[idx-1] = votes[idx];
// "pop" the end of the list, making the list shorter.
votes.length--;
}
function _remove_council_member( address exmember ) private
{
// Remove votes that the exmember has already cast.
uint i = votes.length;
while ( i-- > 0 )
if ( votes[i].voter == exmember )
_remove_vote( i );
// Move all items in the council list (after match) one step closer to the
// front of the list.
i = council.length;
while ( i-- > 0 )
{
if ( council[i] == exmember )
{
uint idx = i;
uint max = council.length;
while ( ++idx < max )
council[idx-1] = council[idx];
// "pop" the end of the list, making the list shorter.
council.length--;
return;
}
}
}
// We run through the entire list of votes, checking if they fulfill the
// requirements.
function _promotedemote( address victim, bool promotion ) private
{
uint numvotes = 0;
uint majority = council.length / 2 + 1;
uint i = votes.length;
while ( i-- > 0 )
if (( votes[i].victim == victim )
&& ( votes[i].promotion == promotion )
)
numvotes++;
// If we don't have enough votes to perform the actual promotion/demotion
if ( numvotes < majority )
return;
// Is it a promotion or a demotion?
if ( promotion )
// Add victim to member list
council.push( victim );
else
// Remove victim from member list
_remove_council_member( victim );
// Send notification
emit adminChange( victim, promotion );
// Remove the vote because the voting is complete.
i = votes.length;
while ( i-- > 0 )
if (( votes[i].victim == victim )
&& ( votes[i].promotion == promotion )
)
_remove_vote( i );
}
// 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)
{
bool voterIsOnCouncil = isCouncil( voter );
bool victimIsOnCouncil = isCouncil( victim );
if ( ! voterIsOnCouncil )
return false;
// Can't promote someone who is already on the council
if ( victimIsOnCouncil && promotion )
return false;
// Can't demote someone who is not a council member.
if ( !victimIsOnCouncil && !promotion )
return false;
// See if he is trying to cast a vote already registered
uint ancient = block.timestamp - votetimeout;
uint i = votes.length;
while ( i-- > 0 )
{
if ( (votes[i].voter == voter)
&& (votes[i].victim == victim)
&& (votes[i].promotion == promotion)
&& (votes[i].voteStart > ancient)
)
return false;
}
return true;
}
// Calling this function will vote for adding an additional or
// removing an existing member of council.
// This requires n/2+1 votes (more than 50%).
// The boolean must be true if you want to add a member
// and false if you want to remove one.
function vote( address victim, bool promotion ) public
{
if ( ! mayVote(msg.sender, victim, promotion))
revert("That seems redundant or is otherwise not allowed.");
// A little house keeping - if a vote is too old, then remove it
uint ancient = block.timestamp - votetimeout;
uint i = votes.length;
while ( i-- > 0 )
if ( votes[i].voteStart < ancient )
_remove_vote( i );
// End of house keeping
// Store the vote
votes.push(
Vote(
msg.sender,
victim,
block.timestamp,
promotion
)
);
// Send notification of the vote
emit voteCast( address(msg.sender), victim, promotion );
// See if we're ready to promote/demote anyone, based on the votes.
_promotedemote( victim, promotion );
// If we have no more council members, then we have no reason to continue living.
if ( council.length == 0 )
selfdestruct( msg.sender );
}
}
# Majority
This contract maintains a list of accounts authorized
to control members of "the club" using a majority (n/1+1).
We call that group the "council".
For instance, could be useful for
* a list of sealers
* a board of directors
* a local chess club
* even outsourcing this kind of management from another smart contract.
There are a few functions that can be used to see the contents of the
data structures used. Usually, you probably only need to **vote()** and
to ask if some account **isCouncil()**
See the test suite for examples of how to extract information from the
different datastructures, if you feel you really need that.
## Events
### voteCast
**voteCast( address voter, address victim, bool promotion )**
Gives the address of who voted, who they voted for and if it should
be a promotion (true) or demotion (false).
A promotion means to become a member of the council.
A demotion means to be removed from the list of council members.
### adminChange
**adminChange( address admin, bool promotion )**
This event is emitted when an address has received enough votes to be
promoted or demoted and that action is taken.
## Functions
### constructor
**constructor( uint timeout )**
This function is called when the contract is getting deployed.
The deploying address automatically becomes the only council member and
needs to vote to include other's. The contract creator has no special
powers other than other council members, and as such can be voted out
and lose all control over the contract.
If you specify an integer when deploying the contract, you can change
the time it takes for a vote to time out. The timeout can not be set
lower than one hour. The default is 7 days.
### setTimeout
**setTimeout( uint timeout )**
Change the timeout (in seconds) for validity of votes cast.
Any council member can change the timeout.
The timeout can not be set lower than one hour.
### councilLength
**councilLength()**
Returns a uint telling how many entries are in the council list.
### votesLength
**votesLength()**
Returns a uint telling how many structs are in the votes array.
### isCouncil
**isCouncil( address subject )**
Returns true or false whether the given address is a member of the
council.
### mayVote
**mayVote( address voter, address victim, bool promotion )**
Returns true or false if a certain address may vote a certain vote for
a certain address.
### vote
**vote( address victim, bool promotion )**
Performs actual voting on including (true) or removing (false) an address
from the council.
If the final member of the council votes to remove itself, the contract
will self-destruct.
../test/test-harness-v1.sh
\ No newline at end of file
Esta carpeta contiene llaves privadas.
Cuidado usar las llavas para algo importante (fuera de pruebas).
#!/bin/bash
true ${BFAHOME:=$( echo ~bfa/bfa )}
source ${BFAHOME}/bin/libbfa.sh || exit 1
function testfatal
{
test -n "$1" && echo $*
exit 1
}
function testcleanup
{
for filename in ${keyfiles}
do
test -f "${filename}"
rm "${filename}"
done
}
function writetestkeysto
{
local destinationdirectory=$1
for i in {1..4}
do
case $i in
1)
set 7e5705d6e4fd660ad6d2d6533f3b4b6647dbb0a2 ac6c3c3e7351f858a3ffd9db00dc70b72a16e5ab0723be0a3da6da228778ce29 717f2930a84107df56fcb3308c116cfe 64fc98daae4a96777b8c08396a92bc8dde1117d439c7eb0b9a016a11e512dc0a 89e869cae11f4a9b3d1f8d684119a64d6c1b25451152b5fb413c531813f83b0d 0643d804-b9df-4df9-8819-d38463480f15
;;
2)
set 7e57105001438399e318753387b061993753a545 3d3f422c4c227a37db5728e72c91e43cbd391f7e338fe6aaeb68b65416b33b48 676cf0e07562c52f6c933de714c0506f 8e9869dc6aab090ff389ecc84815d0abc108f437d11c1d56a91c83277c77acd5 87237d3a481ab6a1c50b9ef07b24c0118644e7bf3b27170766ec6b860300890d ee0c6421-b0f1-41db-934e-3cab0c419875
;;
3)
set 7e57215a8af47c70baca431c45ecf14199f4bd9a 84c5a655cdd6a402ef88ea1f64a4c427ce3cdaec88f352c0194254095b8b71c4 80e54ea9307624e2d4ec7179f2fcfa3c 9aaeba47fbb5e7ba8d327a1a544712184424021db8e4d238f60bdba81f02a4ca 7ef19ab55611ea649b65de754fb68d5f810550fe9ccfcfd2f067d3e56b4aee04 4b1c00d1-292f-4610-bbc0-2bb4d6489ea4
;;
4)
set 7e57348aec1b1fd574ef2c0702acaa197c46d613 2d6e3b21ab6c69ad789703acc967f93955690626333c667bc34e48650bf95d59 fc98dd18e1292cb5c6578ecbbc29cbb3 75cc35ea980da5b70aa146ac02fa9c3fd9d0015cdda8b6737ba17ba95f24cd8a fcb3ed29dfe7ec444c929e880ecc822af894ee497de7e29484ecccfcd7187b8b 05d45b22-185e-49d4-bc91-9ab684e8e75a
;;
*)
false
;;
esac
local address=$1
local ciphertext=$2
local iv=$3
local salt=$4
local mac=$5
local id=$6
local cipherparams="{\"iv\":\"${iv}\"}"
local kdfparams="{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"${salt}\"}"
local crypto="{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"${ciphertext}\",\"cipherparams\":${cipherparams},\"kdf\":\"scrypt\",\"kdfparams\":${kdfparams},\"mac\":\"${mac}\"}"
local thisfilename="${destinationdirectory}/UTC--2018-12-24T12-00-00.000000000Z--${address}"
echo "{\"address\":\"${address}\",\"crypto\":${crypto},\"id\":\"${id}\",\"version\":3}" > ${thisfilename}
keyfiles="${keyfiles} ${thisfilename}"
done
}
keyfiles=
trap testfatal ERR
trap testcleanup EXIT
contractname=$( ls -1 *.sol | head -1 | sed 's/\.sol$//' )
test -f ${contractname}.sol
test -r ${contractname}.sol
solc --combined-json abi,bin ${contractname}.sol > ${contractname}.json
jq -r ".contracts.\"${contractname}.sol:${contractname}\".abi" < ${contractname}.json > ${contractname}.abi
jq -r ".contracts.\"${contractname}.sol:${contractname}\".bin" < ${contractname}.json > ${contractname}.bin
rm ${contractname}.json
writetestkeysto ${BFANODEDIR}/keystore
for tester in ${contractname}-test*
do
if [ -n "${tester}" -a -x "${tester}" -a -r "${tester}" ]
then
./${tester}
fi
done
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