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

Merge branch 'master' into ballot

parents a1022748 5608b730
No related branches found
No related tags found
No related merge requests found
......@@ -12,23 +12,26 @@ Esta guía debería funcionar en Debian o sus derivados. Testeado en *Debian* y
- como root: `apt install git`
2. Cloná el repositorio oficial BFA
- `git clone https://gitlab.bfa.ar/blockchain/nucleo.git bfa`
3. Ejecutá el script de instalación. Esto cambiará algunas configuraciones en tu sistema. Si te preocupa (¿debería?), podés ejecutar este paso manualmente.
3. Ejecutá el script de instalación. Esto cambiará algunas configuraciones en tu sistema. Si te preocupa (¿debería?), podés ejecutar este escript paso a paso manualmente.
- como root: `bfa/bin/installbfa.sh`
Van a aparecer varios *warnings* mientras se instala web3. Esto parece ser "normal". Ignorarlo no parece causar problemas.
Van a aparecer varios **warnings** mientras se instala web3. Esto parece ser "normal". Ignorarlo no parece causar problemas.
4. Cambiá al usuario `bfa`
- como root: `su - bfa`
5. Comenzá la sincronización. Esto puede llevar un rato largo (este script se ejecuta automáticamente cuando se reinicia el sistema).
5. Comenzá la sincronización. **Esto puede llevar un rato largo** (este script se ejecuta automáticamente cuando se reinicia el sistema).
- como bfa: `start.sh`
6. Monitoreá los logs con `bfalog.sh`. Apretá CTRL-C en cualquier momento para detener el `tail -f`.
7. Cambiá la configuración de tu nodo usando `admin.sh syncmode`
- Hacé esto antes de haber sincronizado mucho en el paso anterior, ya que esto podría remover todos los datos de la cadena que hayas bajado y reiniciar la sincronización de la cadena.
8. Esperá a aque termine de sincronizar
9. Ejecutá `maymine.sh` para actualizar tu configuración (detecta si estás autorizado a sellar/minar o no). Podés ejecutar esto todas las veces que quieras. Si tratás de sellar y no tenés permiso, van a aparecer errores en el log (pero no se rompe nada).
10. Herramientas simples super básicas (más bien pruebas de concepto, para inspirar a los programadores):
9. Herramientas simples super básicas (más bien pruebas de concepto, para inspirar a los programadores):
- `explorer.sh` : Sigue el bloque más nuevo "*lastest*" por default, pero podés especificar un número de bloque cualquiera como argumento, por ejemplo `explorer.sh 0` permite ver el génesis (bloque 0).
- `walker.pl` : También toma un número de bloque para iniciar. Sigue esperando nuevos bloques.
Hay otros programas "interesantes" en los directorios `bin/` y `src/`, pero para los desarrolladores, el branch `dev` es más intersante.
Hay otros programas "interesantes" en los directorios `bin/` y `src/`,
pero para los desarrolladores, el branch `dev` es más intersante y tambien el
([repositorio contrib](https://gitlab.bfa.ar/blockchain/contrib)).
**Puede tardarse alrededor de una hora conectarse la primera vez. En el log no se ve nada. Hay que tener paciencia.**
## start.sh
......@@ -84,7 +87,14 @@ Cuando un operador de un sellador vota para promover o remover un sellador,
este script hace la mayor parte. Toma un solo argumento, el número de la
cuenta del sellador por el cual se vota.
## monitor.sh
## unlock.js
Debloqua las cuentas del sistema (vease tambien `monitor.js`). Si una cuenta
tiene clave, se puede poner la clave con este script.
## monitor.js
Esto se corre cada minuto desde `cron.sh`. Actualizará el un archivo
en `network/status` que muestra información de la red muy básica.
Esto se corre desde `cron.sh`. Cada minuto actualizará el archivo
`network/status` que muestra información del estado del nodo muy básica.
Tambien habilita sellar/minar si la cuenta (eth.accounts[0]) esta permitido
segun la red. Desbloqua cuentas si no tienen passwords.
\ No newline at end of file
......@@ -9,7 +9,7 @@ const rl = require('readline').createInterface(
var web3;
var Distillery;
var bfa;
var notation = [ 6 ];
var notation = [ 15 ];
function init()
{
......@@ -21,14 +21,36 @@ function init()
case 9:
notation.push( "Gwei" );
break;
case 12:
notation.push( "micro" );
break;
case 15:
notation.push( "finney" );
break;
case 18:
notation.push( "ether" );
break;
case 21:
notation.push( "kether" );
break;
case 24:
notation.push( "grand" );
break;
case 27:
notation.push( "mether" );
break;
case 30:
notation.push( "gether" );
break;
case 33:
notation.push( "tether" );
break;
default:
notation = [ 6, Math.pow(10, 6), "Mwei" ];
notation = [ 15, Math.pow(10, 15), "finney" ];
}
bfa = new Libbfa();
web3 = bfa.newweb3();
Distillery = bfa.contract( web3, 'Distillery' );
if ( undefined == Distillery )
fatal('Can not initialise Distillery contact.');
web3.eth.getBalance( Distillery.contractaddress ).then(
function receivedOwnBalance(val) {
Distillery.contractbalance = val;
......
#!/bin/bash
# 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
set -x
cd ${BFAHOME}
git pull
npm rebuild
#!/bin/bash
trap 'exit 1' ERR
# Go $HOME
cd
# Log in home directory
exec < /dev/null > bfa-cron-output.log 2>&1
exec < /dev/null > ${HOME}/bfa-cron-output.log 2>&1
# Go to script bin, 'cause we expect to find $BFAHOME/bin/env there
cd `dirname $0`
source ./env
......
......@@ -52,16 +52,16 @@ module.exports = class Libbfa
{
var contractdir = [ this.networkdir, 'contracts', name ].join('/');
if ( ! this.fs.existsSync( contractdir ) )
return;
this.fatal( 'The directory containing this contract ("' + contractdir + '") does not exist.' );
var contractaddress = this.fs.realpathSync( contractdir ).replace(/^.*\//, '');
if ( undefined == contractaddress )
return;
this.fatal( 'Contract address for "' + name + '" not found.' );
var abistr = this.fs.readFileSync( contractdir + '/abi' ).toString();
if ( undefined == abistr )
return;
this.fatal( 'ABI for contract "' + name + '" not found' );
var abi = JSON.parse( abistr );
if ( undefined == abi )
return;
this.fatal( 'Failed to convert ABI for contract "' + name + '" into JSON.' );
var c = new w3.eth.Contract( abi, contractaddress );
c.abi = abi;
c.contractaddress = contractaddress;
......@@ -81,32 +81,46 @@ module.exports = class Libbfa
w3.eth.extend({
//property: 'bfaclique',
methods: [{
name: 'getSigners',
name: 'bfaGetSigners',
call: 'clique_getSigners',
params: 0
}]
});
w3.eth.extend({
methods: [{
name: 'minerstart',
name: 'bfaMinerstart',
call: 'miner_start',
params: 0
}]
});
w3.eth.extend({
methods: [{
name: 'minerstop',
name: 'bfaMinerstop',
call: 'miner_stop',
params: 0
}]
});
w3.eth.extend({
methods: [{
name: 'adminpeers',
name: 'bfaAdminpeers',
call: 'admin_peers',
params: 0
}]
});
w3.eth.extend({
methods: [{
name: 'bfaAdminaddPeer',
call: 'admin_addPeer',
params: 1
}]
});
w3.eth.personal.extend({
methods: [{
name: 'bfalistWallets',
call: 'personal_listWallets',
params: 0
}]
});
if ( undefined != process.env.BFAACCOUNT ) {
w3.eth.defaultAccount = this.account;
}
......
......@@ -5,41 +5,207 @@
"use strict"
const Libbfa = require( process.env.BFAHOME + '/bin/libbfa.js');
var bfa = new Libbfa();
var web3 = bfa.newweb3();
var lastUnlock = 0;
function monitor()
function peerlist()
{
var bfa = new Libbfa();
var web3 = bfa.newweb3();
var now = new Date();
//console.log(web3.eth);
web3.eth.adminpeers().then(
function(nodelist) {
var peers = [];
web3.eth.bfaAdminpeers().then(
function gotAdminPeers( nodelist ) {
var now = new Date();
var nowpeers = [];
var peers = [];
var newpeers = [];
if ( bfa.fs.existsSync( bfa.networkdir + '/peers.cache' ) )
{
var data = bfa.fs.readFileSync( bfa.networkdir + '/peers.cache' ).toString();
if ( data.length > 0 )
peers = data.split(/\r?\n/);
var i = peers.length;
// for some odd reason, I keep seeing empty entries
while ( i-- > 0 )
if ( peers[i] == '' )
peers.splice(i,1);
}
nodelist.forEach(
function(node) {
if ( typeof(node.protocols.eth) == 'object' )
{
var dir = "out";
if ( node.network.inbound )
dir = "in";
peers.push( "peer "+dir+": "+node.enode );
if ( 'object' == typeof(node.protocols.eth) )
{
// default info - likely to get overwritten.
var info = "<" + node.id + ">";
var dir = "";
if ( undefined != node.network )
{
if ( 'boolean' == typeof(node.network.inbound) )
{
if ( node.network.inbound )
dir = "in";
else
dir = "out";
}
if ( 'string' == typeof(node.enode) )
{
info = node.enode;
if (peers.indexOf( node.enode ) == -1 && dir == "out" )
newpeers.push( node.enode );
}
else
{
info = "";
if ( undefined != node.id )
info += "<" + node.id + ">";
if ( undefined != node.network.remoteAddress )
{
if ( info != "" )
info+= "@";
info += node.network.remoteAddress;
}
}
}
nowpeers.push( "peer " + dir + ": " + info );
}
}
);
// write network/status
bfa.fs.writeFileSync(
bfa.networkdir + '/status',
"UTC: " + now.toUTCString() + "\n"
+ "BFA peers: " + peers.length + "\n"
+ peers.sort().join("\n") + "\n",
+ "BFA peers: " + nowpeers.length + "\n"
+ nowpeers.sort().join("\n") + "\n",
{ mode: 0o644 }
);
// Try to connect to a random node if we have very few peers
if ( nowpeers.length < 5 && peers.length > 0 )
{
var i = Math.floor( Math.random() * peers.length );
var enode = peers[i];
console.log(
"We have "
+ nowpeers.length
+ " peer" + ( nowpeers.length==1 ? '' : 's' ) + ", so will try to connect to "
+ enode
);
web3.eth.bfaAdminaddPeer( enode );
}
// write network/peers.cache
// peers.cache is a list of peers we have connected out to in the past.
peers = peers.concat( newpeers );
if (peers.length > 100)
peers.splice( 0, peers.length - 100 );
bfa.fs.writeFileSync(
bfa.networkdir + '/peers.cache',
peers.join("\n") + "\n",
{ mode: 0o644 }
);
},
function failedToGetAdminPeers(x)
{
// ignore connection problems?
}
);
}
// Function to determine if our defaultAccount is allowed to seal/mine.
// It will adjust the behaviour accordingly, i.e. stop or start mining.
function mayseal()
{
var me = web3.eth.defaultAccount;
if ( undefined == me )
{
console.log( "Failed to get default account information." );
return;
}
me = me.toLowerCase();
web3.eth.isMining().
then(
// returns a boolean whether or not we are currently mining/sealing.
function( isMining )
{
// Get a list of clique.getSigners, so we can see if we are
// in the list of authorized sealers.
web3.eth.bfaGetSigners()
.then(
function gotListOfSealers(x)
{
var lcsealers = x.map( name => name.toLowerCase() );
var isSigner = (lcsealers.indexOf(me) > -1);
if ( isSigner )
{
if ( ! isMining )
{
console.log( 'Started to seal.' );
web3.eth.bfaMinerstart();
}
}
else
{
if ( isMining )
{
console.log( 'I was trying to seal, but am not authorized. Stopped trying.' );
web3.eth.bfaMinerstop();
}
}
},
function failedToGetListOfSealers(x)
{
console.log(x);
}
);
},
function(x)
function failedToGetIsMiningBool(x)
{
console.log( x );
process.exit(1)
// Probably geth is not running.
//console.log(x);
}
);
}
monitor();
function unlock()
{
if ( lastUnlock + 600 > Date.now() / 1000 )
return;
web3.eth.personal.bfalistWallets()
.then(
function pushone(x)
{
var i = x.length;
var wallets = new Array();
while ( i-- > 0 )
if ( x[i].status == "Locked" )
wallets.push( x[i] );
i = wallets.length;
if ( i == 0 )
return;
var promises = new Array();
while ( i-- > 0 )
{
var j = wallets[i].accounts.length;
while ( j-- > 0 )
{
var addr = wallets[i].accounts[j].address;
var promise =
web3.eth.personal.unlockAccount( addr, "", 0 )
.catch( error => { } );
promises.push( promise );
}
}
lastUnlock = Date.now() / 1000;
}
,
function err(x)
{
// we don't care?
}
)
}
function timer()
{
peerlist();
mayseal();
unlock();
}
setTimeout( timer, 5 * 1000 );
setInterval( timer, 60 * 1000 );
......@@ -14,39 +14,11 @@ enodeDGSI="59ae768ecdee632e0daceccb6f71b215392eba89230d626573f2fb4e9c0786c9a6610
bootDGSIv4="enode://${enodeDGSI}@[200.108.146.100]:30301"
bootnodes="${bootARIUv6},${bootARIUv4},${bootUNCv4},${bootDGSIv4}"
function accountlist
{
local accts=
local filename
for filename in ${BFANODEDIR}/keystore/*--*
do
if [ -r "$filename" -a ${#filename} -ge 40 ]
then
acct=${filename:$(( ${#filename} - 40 ))}
accts="${accts},${acct}"
fi
done
# strip leading comma
accts=${accts#,}
if [ ${#accts} -ge 40 ]
then
echo "--password /dev/null --unlock ${accts}"
fi
}
# touch the "miner" file if you are authorized to mine
# If you don't want to restart after touching the file,
# you can use attach.sh and issue the command:
# miner.start()
function getminer
{
if [ -e "${BFANODEDIR}/miner" ]
then
echo "--mine"
fi
}
function getsyncmode
{
local syncmode=$( cat "${BFANODEDIR}/syncmode" 2>/dev/null || true )
......@@ -96,17 +68,11 @@ function startmonitor
echo "A monitor is already running."
false
) || exit
if [ -t 1 ]
then
echo Running monitor every 60 seconds.
fi
while :
do
(
monitor.js &
echo $! > $pidfile
wait
sleep 60
done &
) 2>&1 | ${BFAHOME}/bin/log.sh ${BFANODEDIR}/log &
) 9>> $pidfile
}
......@@ -134,12 +100,11 @@ function startgeth
echo '***'
echo
# (re)configure parameters (you never know if they changed)
flexargs="$( accountlist) $( getminer ) $( getsyncmode ) --extradata $( extradata )"
flexargs="$( getsyncmode ) --extradata $( extradata )"
set -x
geth \
--datadir ${BFANODEDIR} \
--networkid ${BFANETWORKID} \
--bootnodes "${bootnodes}" \
--rpc \
--rpcport $rpcport \
--rpcapi "eth,net,web3,admin,clique,miner,personal" \
......@@ -148,7 +113,8 @@ function startgeth
--gcmode archive \
--cache 512 \
--verbosity ${BFAVERBOSITY:-3} \
${flexargs} &
${flexargs} \
--bootnodes "${bootnodes}" &
set +x
echo $! > ${BFANODEDIR}/geth.pid
wait
......
#!/usr/bin/node
const Libbfa = require( process.env.BFAHOME + '/bin/libbfa.js');
const bfa = new Libbfa();
const Writable = require('stream').Writable;
var mutableStdout = new Writable(
{
write: function( chunk, encoding, callback )
{
if ( ! this.muted )
process.stdout.write(chunk, encoding);
callback();
}
} );
mutableStdout.muted = false;
const rl = require('readline').createInterface(
{
input: process.stdin,
output: mutableStdout,
terminal: true,
historySize: 0
} );
var web3 = bfa.newweb3();
// First time we try to unlock, we will use this empty passphrase.
// Do not edit.
var passphrase = "";
function atLeastOneFailedSoGetNewPass(x)
{
if ( !process.stdin.isTTY )
bye( 0, "Stdin is not a tty. Will not try with other passwords." );
// first we print the question
mutableStdout.muted = false;
rl.question(
"Enter another password to try: ",
(answer) => {
process.stdout.write( "\n" );
mutableStdout.muted = false;
passphrase = answer;
if ( answer == "" )
bye( 0, "Bye." );
unlockall();
}
);
// Asking the question is an async event, so
// we set the object to mute output while the
// user types his password.
mutableStdout.muted = true;
}
function bye( exitcode, msg )
{
console.log( msg );
rl.close();
process.exit( exitcode );
}
function unlockall()
{
var wallets = new Array();
web3.eth.personal.bfalistWallets()
.then(
function pushone(x)
{
var failures = 0;
var promises = new Array();
var i = x.length;
while ( i-- > 0 )
if ( x[i].status == "Locked" )
wallets.push( x[i] );
i = wallets.length;
if ( i == 0 )
bye( 0, "List of accounts to unlock is empty." );
while ( i-- > 0 )
{
var j = wallets[i].accounts.length;
while ( j-- > 0 )
{
var addr = wallets[i].accounts[j].address;
//console.log( "Trying to unlock " + addr + "." );
var promise =
web3.eth.personal.unlockAccount( addr, passphrase, 0 )
.catch(
error =>
{
failures++;
return error;
}
);
promises.push( promise );
}
}
var empty = "";
if ( passphrase == "" )
empty = " with an empty passphrase";
console.log(
"Attempting to unlock "
+ promises.length
+ " account" + ( promises.length == 1 ? '' : 's' )
+ empty + "."
);
Promise.all( promises )
.then(
function(x)
{
if ( failures == 0 )
bye( 0, "OK." );
console.log( failures + " account" + (failures==1 ? " is" : "s are") + " still locked." );
atLeastOneFailedSoGetNewPass();
},
function(x)
{
console.log( x );
bye( 1, "I can't imagine this text will ever be shown." );
}
);
},
function errWalletList(x)
{
bye( 1, x );
}
)
}
unlockall();
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