diff --git a/bin/libbfa.js b/bin/libbfa.js
index bf0b61b7ab5a49878428908c75ec468f336c52b3..6cdd2e99ee9e3af22086bd9b680924e0c1c65454 100644
--- a/bin/libbfa.js
+++ b/bin/libbfa.js
@@ -96,11 +96,16 @@ module.exports = class Libbfa
                 body:           body,
                 callback:       function RPCresponse( err, obj )
                 {
+               	    var		r;
+               	    var		e;
                     if ( err )
-                        throw new Error( err );
+                        e = err;
+   		    else
                     if ( obj.body.error && obj.body.error.code && obj.body.error.message )
-                        throw new Error( 'Error ' + obj.body.error.code + ": "+ obj.body.error.message );
-                    callback(obj.body.result);
+                    	e = 'Error ' + obj.body.error.code + ": "+ obj.body.error.message;
+                    else
+                    	r = obj.body.result;
+                    callback(e, r);
                 }
             });
         };
diff --git a/bin/monitor.js b/bin/monitor.js
index 0e84360244649e9826ed43312676c81426b91a92..4414f05d625c6b32c09af25ab58ddd38bd95ba39 100755
--- a/bin/monitor.js
+++ b/bin/monitor.js
@@ -120,13 +120,15 @@ function    parsenode( node )
     return n;
 }
 
-function gotAdminPeers( nodelist )
+function gotAdminPeers( err, nodelist )
 {
     var     nowpeers            =   [];
     var     peerscache          =   readPeersCache();
     var     newoutpeers         =   [];
     var     currentnodes        =   [];
 
+    if ( err )
+	return;
     // The nodelist also contains peers which are not yet validated
     // if they even belong to this network. Parsenode returns an
     // object or nothing, based on our criteria
@@ -208,8 +210,9 @@ function    mayseal()
             // Get a list of clique.getSigners, so we can see if we are
             // in the list of authorized sealers.
             web3.bfa.clique.getSigners(
-                function gotListOfSealers(x)
+                function gotListOfSealers(e,x)
                 {
+		    if (e) return;
                     var lcsealers   =   x.map( name => name.toLowerCase() );
                     var isSigner    =   (lcsealers.indexOf(me) > -1);
                     if ( isSigner )
@@ -245,8 +248,9 @@ function    unlock()
         return;
     var	    unlockedsomething	=   false;
     web3.bfa.personal.listWallets(
-        function pushone(x)
+        function pushone(e,x)
         {
+	    if (e) return;
             var     i           =   x.length;
             var     wallets     =   new Array();
             while ( i-- > 0 )
@@ -302,7 +306,16 @@ function    unlock()
 function    timer()
 {
     if ( netid == 0 )
-        web3.eth.net.getId().then( x => {netid = x} );
+    {
+        web3.eth.net.getId()
+	.then( x => {
+            netid = x;
+        } )
+	.catch( err => {
+            console.log("monitor.js non-fatal: "+err)
+        });
+        return;
+    }
     peerlist();
     mayseal();
     unlock();
diff --git a/bin/singlestart.sh b/bin/singlestart.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a00962e11aeffb5b7eba180ba9924f8afa14369c
--- /dev/null
+++ b/bin/singlestart.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+# 20190816 Robert Martin-Legene
+# GPL2-only
+
+# BFA tiene 3 bootnodes oficiales.
+# Para levantar un bootnode hay que poner la clave en
+# este archivo. Se genera la clave con: bootnode -genkey
+bootnodekeyfile=${BFANETWORKDIR}/bootnode/key
+
+# Bail out if anything fails.
+trap "exit 1" ERR
+# Detect children dying
+trap "reaper" SIGINT SIGCHLD
+unset LOGDIR LOGPIPE PIDIDX
+declare -A PIDIDX
+
+function reaper()
+{
+    local wecare=0
+    for pid in ${!PIDIDX[*]}
+    do
+        kill -0 $pid 2>/dev/null && continue
+        local rc=0
+        wait $pid || rc=$? || true
+        echo "*** ${PIDIDX[$pid]} (pid $pid) has exited with value $rc" 
+        unset PIDIDX[$pid]
+        wecare=1
+    done
+    test $wecare = 1 || return
+    # kill all - an extra kill doesn't hurt. I hope.
+    for pid in ${!PIDIDX[*]}
+    do
+        # don't kill log.sh, because it may still be logging for us
+        if [ "${PIDIDX[$pid]}" != "log.sh" ]
+        then
+            echo "*** Killing ${PIDIDX[$pid]} (pid $pid)."
+            kill $pid || true
+        fi
+    done
+    max=30
+}
+
+if [ "$VIRTUALIZATION" = "DOCKER" ]
+then
+    echo "Some log info can be seen with: docker logs bfanode"
+fi
+
+# You can start as:
+# BFAHOME=/home/bfa/bfa singlestart.sh
+# singlestart.sh /home/bfa/bfa
+if [ -z "${BFAHOME}" -a -n "$1" -a -f "$1" ]
+then
+    BFAHOME="$1"
+fi
+if [ -z "${BFAHOME}" ]; then echo "\$BFAHOME not set. Did you source `dirname $0`/env ?" >&2; exit 1; fi
+#
+if [ -r "${BFAHOME}/bin/env" ]
+then
+    source ${BFAHOME}/bin/env
+else
+    if [ "$VIRTUALIZATION" = "DOCKER" ]
+    then
+        # The idea is that the environment already is set by the Docker environment.
+        touch ${BFAHOME}/bin/env
+    else
+        echo "Can't do much without a \$BFAHOME/bin/env file. Maybe you can copy one of these?" >&2
+        ls -1 ${BFAHOME}/*/env >&2
+        exit 1
+    fi
+fi
+source ${BFAHOME}/bin/libbfa.sh
+
+echo "Logging mostly everything to ${BFANODEDIR}/log"
+echo "Consider running: tail -n 1000 -F ${BFANODEDIR}/log"
+if [ "$VIRTUALIZATION" = "DOCKER" ]
+then
+    echo "or: docker exec -i bfanode bfalog.sh"
+fi
+
+echo "*** Setting up logging."
+# Clean up logging
+LOGDIR=$( mktemp -d )
+trap "rm -rf ${LOGDIR}" EXIT
+LOGPIPE=${LOGDIR}/logpipe
+mknod ${LOGPIPE} p
+${BFAHOME}/bin/log.sh ${BFANODEDIR}/log < ${LOGPIPE} &
+PIDIDX[$!]="log.sh"
+exec > ${LOGPIPE} 2>&1
+
+echo "*** Starting geth."
+geth --config ${BFATOML} --gcmode archive --verbosity ${BFAVERBOSITY:-3} --allow-insecure-unlock &
+PIDIDX[$!]="geth"
+
+# bootnode
+if [ -r "$bootnodekeyfile" ]
+then
+    echo "*** Starting bootnode."
+    bootnode --nodekey $bootnodekeyfile &
+    PIDIDX[$!]="bootnode"
+fi
+
+echo "*** Starting monitor.js"
+monitor.js &
+PIDIDX[$!]="monitor.js"
+
+max=-1
+# Exit if only 1 process remains - we hope it is log.sh, but either way,
+# it is time to end.
+while [ "${#PIDIDX[*]}" -gt 1 -a $max -ne 0 ]
+do
+    sleep 1
+    max=$(( $max - 1 ))
+done
+if [ ${#PIDIDX[*]} -gt 0 ]
+then
+    echo "*** Killing all remaining processes: ${PIDIDX[*]} (${!PIDIDX[*]})."
+    kill -KILL ${!PIDIDX[*]} 2>/dev/null || true
+fi
diff --git a/network/config.toml b/network/config.toml
new file mode 100644
index 0000000000000000000000000000000000000000..a414c48626596514c5fe46215a1753fda1fc7ecd
--- /dev/null
+++ b/network/config.toml
@@ -0,0 +1,88 @@
+[Eth]
+NetworkId = 47525974938
+SyncMode = "full"
+NoPruning = true
+NoPrefetch = false
+LightPeers = 100
+UltraLightFraction = 75
+DatabaseCache = 2048
+DatabaseFreezer = ""
+TrieCleanCache = 1024
+TrieDirtyCache = 1024
+TrieTimeout = 3600000000000
+EnablePreimageRecording = false
+EWASMInterpreter = ""
+EVMInterpreter = ""
+
+[Eth.Miner]
+GasFloor = 8000000
+GasCeil = 8000000
+GasPrice = 1000000000
+Recommit = 3000000000
+Noverify = false
+
+[Eth.Ethash]
+CacheDir = "ethash"
+CachesInMem = 2
+CachesOnDisk = 3
+DatasetDir = "/home/bfa/.ethash"
+DatasetsInMem = 1
+DatasetsOnDisk = 2
+PowMode = 0
+
+[Eth.TxPool]
+Locals = []
+NoLocals = true
+Journal = "transactions.rlp"
+Rejournal = 3600000000000
+PriceLimit = 1
+PriceBump = 10
+AccountSlots = 16
+GlobalSlots = 4096
+AccountQueue = 64
+GlobalQueue = 1024
+Lifetime = 10800000000000
+
+[Eth.GPO]
+Blocks = 20
+Percentile = 60
+
+[Shh]
+MaxMessageSize = 1048576
+MinimumAcceptedPOW = 2e-01
+RestrictConnectionBetweenLightClients = true
+
+[Node]
+DataDir = "/home/bfa/bfa/network/node"
+HTTPHost = "127.0.0.1"
+HTTPCors = ["*"]
+omitempty = ""
+IPCPath = "geth.ipc"
+HTTPPort = 8545
+HTTPVirtualHosts = ["localhost"]
+HTTPModules = ["net", "web3", "eth", "shh", "clique", "admin", "miner", "personal"]
+WSHost = "127.0.0.1"
+WSPort = 8546
+WSModules = ["net", "web3", "eth", "shh", "clique", "admin", "miner", "personal"]
+GraphQLPort = 8547
+GraphQLVirtualHosts = ["localhost"]
+
+[Node.P2P]
+MaxPeers = 50
+NoDiscovery = false
+BootstrapNodes = ["enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@[2800:110:44:6300::aad2:2db3]:30301", "enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@170.210.45.179:30301", "enode://82b66b13d7addcf9ffe1e4e972a105f6ccf50557161c4a0978a5d9ce595ababde609ea8a49897ae89b1d41e90551cb2e9241363238593e950ca68bd5af7c24d6@200.16.28.28:30301", "enode://59ae768ecdee632e0daceccb6f71b215392eba89230d626573f2fb4e9c0786c9a661027ab7343820ca63d96fe48ffd81ed1bf6e4d512f0ba50ec072c9efd9e4e@200.108.146.100:30301"]
+BootstrapNodesV5 = ["enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@[2800:110:44:6300::aad2:2db3]:30301", "enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@170.210.45.179:30301", "enode://82b66b13d7addcf9ffe1e4e972a105f6ccf50557161c4a0978a5d9ce595ababde609ea8a49897ae89b1d41e90551cb2e9241363238593e950ca68bd5af7c24d6@200.16.28.28:30301", "enode://59ae768ecdee632e0daceccb6f71b215392eba89230d626573f2fb4e9c0786c9a661027ab7343820ca63d96fe48ffd81ed1bf6e4d512f0ba50ec072c9efd9e4e@200.108.146.100:30301"]
+StaticNodes = []
+TrustedNodes = []
+ListenAddr = ":30303"
+EnableMsgEvents = false
+
+[Node.HTTPTimeouts]
+ReadTimeout = 30000000000
+WriteTimeout = 30000000000
+IdleTimeout = 120000000000
+
+[Dashboard]
+Host = "localhost"
+Port = 8080
+Refresh = 5000000000
diff --git a/test2network/config.toml b/test2network/config.toml
new file mode 100644
index 0000000000000000000000000000000000000000..e94490c8fec451628446f3767b82b9e161f0e3c7
--- /dev/null
+++ b/test2network/config.toml
@@ -0,0 +1,88 @@
+[Eth]
+NetworkId = 55555000000
+SyncMode = "full"
+NoPruning = true
+NoPrefetch = false
+LightPeers = 100
+UltraLightFraction = 75
+DatabaseCache = 2048
+DatabaseFreezer = ""
+TrieCleanCache = 1024
+TrieDirtyCache = 1024
+TrieTimeout = 3600000000000
+EnablePreimageRecording = false
+EWASMInterpreter = ""
+EVMInterpreter = ""
+
+[Eth.Miner]
+GasFloor = 8000000
+GasCeil = 8000000
+GasPrice = 1000000000
+Recommit = 3000000000
+Noverify = false
+
+[Eth.Ethash]
+CacheDir = "ethash"
+CachesInMem = 2
+CachesOnDisk = 3
+DatasetDir = "/home/bfa/.ethash"
+DatasetsInMem = 1
+DatasetsOnDisk = 2
+PowMode = 0
+
+[Eth.TxPool]
+Locals = []
+NoLocals = true
+Journal = "transactions.rlp"
+Rejournal = 3600000000000
+PriceLimit = 1
+PriceBump = 10
+AccountSlots = 16
+GlobalSlots = 4096
+AccountQueue = 64
+GlobalQueue = 1024
+Lifetime = 10800000000000
+
+[Eth.GPO]
+Blocks = 20
+Percentile = 60
+
+[Shh]
+MaxMessageSize = 1048576
+MinimumAcceptedPOW = 2e-01
+RestrictConnectionBetweenLightClients = true
+
+[Node]
+DataDir = "/home/bfa/bfa/test2network/node"
+HTTPHost = "127.0.0.1"
+HTTPCors = ["*"]
+omitempty = ""
+IPCPath = "geth.ipc"
+HTTPPort = 8545
+HTTPVirtualHosts = ["localhost"]
+HTTPModules = ["net", "web3", "eth", "shh", "clique", "admin", "miner", "personal"]
+WSHost = "127.0.0.1"
+WSPort = 8546
+WSModules = ["net", "web3", "eth", "shh", "clique", "admin", "miner", "personal"]
+GraphQLPort = 8547
+GraphQLVirtualHosts = ["localhost"]
+
+[Node.P2P]
+MaxPeers = 50
+NoDiscovery = false
+BootstrapNodes = ["enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@[2800:110:44:6300::aad2:2db3]:30301", "enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@170.210.45.179:30301", "enode://82b66b13d7addcf9ffe1e4e972a105f6ccf50557161c4a0978a5d9ce595ababde609ea8a49897ae89b1d41e90551cb2e9241363238593e950ca68bd5af7c24d6@200.16.28.28:30301", "enode://59ae768ecdee632e0daceccb6f71b215392eba89230d626573f2fb4e9c0786c9a661027ab7343820ca63d96fe48ffd81ed1bf6e4d512f0ba50ec072c9efd9e4e@200.108.146.100:30301"]
+BootstrapNodesV5 = ["enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@[2800:110:44:6300::aad2:2db3]:30301", "enode://7ec4dd9d5e1a2b29d6b60aa9f95677c0c3a5f9306e73d65dd3bcbfda3737a8c509b02d1eab763ce39f18cfe96423df7ee544d6c36191ec17f59ade75bc99d358@170.210.45.179:30301", "enode://82b66b13d7addcf9ffe1e4e972a105f6ccf50557161c4a0978a5d9ce595ababde609ea8a49897ae89b1d41e90551cb2e9241363238593e950ca68bd5af7c24d6@200.16.28.28:30301", "enode://59ae768ecdee632e0daceccb6f71b215392eba89230d626573f2fb4e9c0786c9a661027ab7343820ca63d96fe48ffd81ed1bf6e4d512f0ba50ec072c9efd9e4e@200.108.146.100:30301"]
+StaticNodes = []
+TrustedNodes = []
+ListenAddr = ":30303"
+EnableMsgEvents = false
+
+[Node.HTTPTimeouts]
+ReadTimeout = 30000000000
+WriteTimeout = 30000000000
+IdleTimeout = 120000000000
+
+[Dashboard]
+Host = "localhost"
+Port = 8080
+Refresh = 5000000000