From e695b721090668e56d287999a6ed31c2684c65b9 Mon Sep 17 00:00:00 2001
From: Robert Martin-Legene <robert@nic.ar>
Date: Tue, 27 Apr 2021 15:52:03 +0000
Subject: [PATCH] Introducing command: bfa

---
 bin/bfa       | 384 ++++++++++++++++++++++++++++++++++++++++++++++++++
 bin/bfalog.sh |   8 +-
 2 files changed, 385 insertions(+), 7 deletions(-)
 create mode 100755 bin/bfa
 mode change 100755 => 120000 bin/bfalog.sh

diff --git a/bin/bfa b/bin/bfa
new file mode 100755
index 0000000..d8043a9
--- /dev/null
+++ b/bin/bfa
@@ -0,0 +1,384 @@
+#!/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
+
+declare -A commands help
+
+function    register_subcommand
+{
+    declare -g commands help
+    commands[$1]=$2
+    help[$1]=$3
+}
+
+function    _usage()
+{
+    local after=''
+    for c in $( echo ${!commands[*]} | sort )
+    do
+        after="${after}|$c"
+    done
+    echo "Usage: $(basename $0) {${after:1}}" >&2
+    for c in $( echo ${!commands[*]} | sort )
+    do
+        printf '%-15s %s\n' "$c" "${help[$c]}" >&2
+    done
+    trap - ERR
+    exit 1
+}
+
+function    _max
+{
+    test "$1" -lt "$2" && echo "$2"
+    echo "$1"
+}
+
+function    pidsfromsigfiles
+{
+    local pids=
+    local file
+    for file in \
+        ${BFANETWORKDIR}/bootnode.pid             \
+        ${BFANETWORKDIR}/start-bootnode-loop.pid  \
+        ${BFANODEDIR}/monitor.pid                 \
+        ${BFANODEDIR}/start-monitor-loop.pid      \
+        ${BFANODEDIR}/geth.pid                    \
+        ${BFANODEDIR}/start-geth-loop.pid
+    do
+        test -r "$file" || continue
+        local pid=$(< "$file")
+        if ! [[ "$pid" =~ ^[0-9]+$ ]]
+        then
+            rm -f "$file"
+            continue
+        fi
+        if ! kill -0 "$pid" >/dev/null 2>/dev/null
+        then
+            rm -f "$file"
+            continue
+        fi
+        pids="$pids $pid"
+    done
+    echo "${pids# }"
+}
+
+function    sendsig
+{
+    local signal=$1
+    shift
+    local pids="$*"
+    test -n "$pids" || return
+    ps -p ${pids// /,}
+    echo "Sending ${signal} signal to pid $pids."
+    kill "$signal" $pids || true
+}
+
+register_subcommand 'kill' 'killbfastuff' 'Kill BFA background processes (no questions asked).'
+function    killbfastuff
+{
+    local pids=$(pidsfromsigfiles)
+    if [ -z "$pids" ]
+    then
+        echo "Nothing to send signals to." >&2
+        exit 2
+    fi
+    sendsig -KILL $pids
+}
+
+register_subcommand 'stop' 'graceful' 'Ask the BFA background processes to end gracefully.'
+function    graceful
+{
+    local max=10
+    local pids=$(pidsfromsigfiles)
+    while :
+    do
+        max=$((max - 1))
+        test "$max" -eq 0 && break
+        if [ -z "$pids" ]
+        then
+            echo "Nothing to send signals to." >&2
+            break
+        fi
+        sendsig -TERM $pids
+        sleep 0.4
+        pids=$(pidsfromsigfiles)
+    done
+    test -z "$pids" || echo "This/these pids is/are still running: $f"
+}
+
+register_subcommand 'initdb' 'initdb' 'Stop geth and reset the node to block zero (genesis).'
+function    initdb
+{
+    killbfastuff
+    yes | geth --cache 0 --datadir ${BFANODEDIR} removedb
+    geth --networkid ${BFANETWORKID} --cache 0 --datadir ${BFANODEDIR} init ${BFANETWORKDIR}/genesis.json
+}
+
+register_subcommand 'exportdb' 'exportdb' 'Export blockchain in chunks of 1 million blocks per file.'
+function    exportdb
+{
+    local delta=1000000
+    graceful
+    local maxblocks=$(bfageth --exec 'eth.blockNumber' console 2> /dev/null)
+    # 0 is genesis.. shouldn't dump that
+    local toblock
+    local blockstart=1
+    while [ "$blockstart" -lt "$maxblocks" ]
+    do
+        toblock=$(( blockstart + delta - 1 ))
+        test "$toblock" -gt "$maxblocks" &&
+            toblock=$maxblocks
+        local filename
+        printf -v filename 'bfa2018.blocks.%09d-%09d.export.gz' "$blockstart" "$toblock"
+        if [ ! -e "$filename" ]
+        then
+                echo "Dumping blocks# $blockstart to $toblock to the file named $filename"
+                bfageth export "$filename" "$blockstart" "$toblock"
+        fi
+        blockstart=$(( toblock + 1 ))
+    done
+}
+
+register_subcommand 'importdb' 'importdb' 'Import blocks safely from previous block exports.'
+function    importdb
+{
+    local dumpurl="https://s3.wasabisys.com/bfa/blockdumps"
+    local delta=1000000
+    graceful
+    local toblock
+    local blockstart=1
+    while :
+    do
+        toblock=$(( blockstart + delta - 1 ))
+        printf -v filename 'bfa2018.blocks.%09d-%09d.export.gz' "$blockstart" "$toblock"
+        curl --fail "${dumpurl}/${filename}" || break
+	blockstart=$(( toblock + 1 ))
+    done
+    geth --networkid ${BFANETWORKID} --datadir "${BFANODEDIR}" --syncmode "full" --gcmode "archive" import <(
+    	n=1
+    	while gzip -dc "bfa2018-1Mblocksstartingat${n}.block.export.gz" 2>/dev/null
+    	do
+		n=$(( n + 1000000 ))
+    	done
+	true
+    )
+}
+
+register_subcommand 'syncmode' 'admin_syncmode' 'Set initial synchronization mode.'
+function    admin_syncmode
+{
+    echo "Synchronization modes can only be set for the initial "
+    echo "synchronization. Later follow-up block synchronization "
+    echo "operations will always be \"full\" and can not be changed."
+    echo "Available synchronization modes:"
+    echo "  full : verify all blocks and all transactions (most secure)"
+    echo "  fast : verify all blocks but not all transactions (faster than full, but less certain)"
+    echo "  light: Makes this node into a light node which downloads almost"
+    echo "         nothing, but relies on fast and full nodes in the network"
+    echo "         to answer it's requests. This is the fastest and uses least"
+    echo "         local resources, but outsources all trust to another node."
+    echo "         Possibly still an untested-by-BFA feature."
+    echo "Default mode is fast, because for many, it is a healthy compromise"
+    echo "between speed and paranoia. You can change the setting, according to"
+    echo "your needs."
+
+    mode=$( cat ${BFANODEDIR}/syncmode 2>/dev/null || true )
+    mode=${mode:-fast}
+    echo "Your current mode is set to ${mode}"
+    killed=0
+    orgmode=$mode
+    mode=
+
+    echo
+    while [ -z "${mode}" ]
+    do
+        read -p "Which mode do you wish? : " mode
+        modefilter "$mode"
+        if [[ "$mode" =~ ^full$|^fast$|^light$ ]]
+        then
+            :
+        else
+            echo "Unsupported synchronization mode." >&2
+            exit 1
+        fi
+    done
+    echo "Remembering your choice."
+    echo $mode > ${BFANODEDIR}/syncmode
+    if [ "$orgmode" = "fast" ] && [ "$mode" = "full" ]
+    then
+        echo "You increased your paranoia level. The proper thing to do now,"
+        echo "would be to delete your version of what you synchronized with"
+        echo "fast mode, and revalidate everything in the entire blockchain."
+        echo "This probably takes quite a long time and also requires downloading"
+        echo "all blocks from the entire blockchain again."
+        yesno n "Do you wish to delete all downloaded blocks and resynchronize?"
+        if [ "$REPLY" = "y" ]
+        then
+            if [ -r "${BFANODEDIR}/geth.pid" ]
+            then
+                pid=$( cat ${BFANODEDIR}/geth.pid )
+                kill -0 $pid 2>/dev/null &&
+                    echo "Killing running geth." &&
+                    killed=1
+                while ! kill $pid 2>/dev/null
+                do
+                    sleep 1
+                done
+            fi
+	    initdb
+            test $killed -eq 1 &&
+                echo &&
+                echo "The startup.sh should restart your geth shortly."
+        fi
+    else
+        echo "No further action taken."
+    fi
+}
+
+register_subcommand 'bootnode' 'admin_bootnode' 'Enable/disable the local bootnode.'
+function    admin_bootnode
+{
+    keyfile=${BFANETWORKDIR}/bootnode/key
+    echo "Only very few wants to actually run a boot node."
+    echo "If you have a keyfile for a bootnode, then you will"
+    echo "automatically start one, when restarting your system."
+    if [ -f $keyfile ]
+    then
+        echo "You are set up to run a boot node."
+        echo "Deleting your bootnode keyfile disables your bootnode."
+        yesno n "Do you want to delete your bootnode keyfile?"
+        if [ "$REPLY" = "y" ]
+        then
+            rm $keyfile
+        fi
+        pidfile=${BFANETWORKDIR}/bootnode/pid
+        if [ -r $pidfile ]
+        then
+            pid=`cat $pidfile`
+            kill -0 $pid &&
+            echo "Terminating your bootnode." &&
+            kill `cat $pidfile` ||
+            true
+        fi
+    else
+        echo "You are not set up to run a boot node."
+        yesno n "Do you want to create a keyfile for a bootnode?"
+        if [ "$REPLY" = "y" ]
+        then
+            bootnode -genkey $keyfile
+        fi
+        echo "You can now start your bootnode by running start.sh"
+    fi
+}
+
+register_subcommand 'account' 'bfaaccount' 'Account manipulation.'
+function    bfaaccount
+{
+    case "$1" in
+        'create')
+            exec create_account
+            ;;
+        *)
+            echo "Usage: $0 account create" >&2
+            echo ' create' 'Create an extra account locally on the node.' >&2
+            exit 1
+            ;;
+    esac
+}
+
+function    create_account
+{
+    local num=0
+    local filename
+    for filename in ${BFANODEDIR}/keystore/*
+    do
+        test -f "$filename" &&
+            num=$(( num + 1 ))
+    done
+    if [ "$num" -gt 0 ]
+    then
+        local plural=""
+        if [ "$num" -ne 1 ]
+        then
+            plural="s"
+        fi
+        yesno n "You already have ${num} account${plural}. Do you wish to create an extra?"
+        if [ "$REPLY" = "n" ]
+        then
+            return
+        fi
+    fi
+    geth --cache 0 --datadir ${BFANODEDIR} --password /dev/null account new
+}
+
+register_subcommand 'truncatelog' 'truncatelog' \
+    'Truncate the log file. You may want to stop the background processes first.'
+function    truncatelog
+{
+    true > ${BFANODEDIR}/log
+}
+
+register_subcommand 'bfageth' 'bfageth' 'Start geth for BFA.'
+function    bfageth
+{
+    exec geth --config ${BFANETWORKDIR}/conf.bfa2018.local+full+archive "$@"
+}
+
+function    bfaadmin
+{
+    case "$1" in
+        'bootnode')
+            admin_bootnode
+            ;;
+        'syncmode')
+            admin_syncmode
+            ;;
+        'account')
+            create_account
+            ;;
+        *)
+            echo Usage: `basename $0` "{bootnode|syncmode|account}"
+            trap '' ERR
+            exit 1
+    esac
+}
+
+register_subcommand 'tail' 'bfatail' 'tail -f on the logfile.'
+function    bfatail
+{
+            exec tail -n 100 -F ${BFANODEDIR}/log
+            exit 1
+}
+
+register_subcommand 'log' 'bfalog' 'Open the logfile with less(1).'
+function    bfalog
+{
+            exec less ${BFANODEDIR}/log
+            exit 1
+}
+
+function    main
+{
+    case "$(basename $0)" in
+        'bfa')
+            local cmd
+            cmd=$1
+            shift || _usage
+            test -n "$cmd" && test -n "${commands[$cmd]}" || _usage
+            eval ${commands[$cmd]} "$*"
+            ;;
+        'admin.sh')
+            bfaadmin "$*"
+            ;;
+        'bfalog.sh')
+            bfatail
+            ;;
+        'bfageth')
+            bfageth "$*"
+            exit 1
+    esac
+}
+
+main "$*"
diff --git a/bin/bfalog.sh b/bin/bfalog.sh
deleted file mode 100755
index e387b0d..0000000
--- a/bin/bfalog.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/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
-
-exec tail -n 100 -F ${BFANODEDIR}/log
diff --git a/bin/bfalog.sh b/bin/bfalog.sh
new file mode 120000
index 0000000..ff9e6d8
--- /dev/null
+++ b/bin/bfalog.sh
@@ -0,0 +1 @@
+bfa
\ No newline at end of file
-- 
GitLab