#!/bin/sh ## Short script to startup some local nodes with ## bitcoind, all running on regtest ## Makes it easier to test things out, by hand. ## Should be called by source since it sets aliases ## ## First load this file up. ## ## $ source contrib/startup_regtest.sh ## ## Start up the nodeset ## ## $ start_ln 3 ## ## Let's connect the nodes. The `connect a b` command connects node a to b. ## ## $ connect 1 2 ## { ## "id" : "030b02fc3d043d2d47ae25a9306d98d2abb7fc9bee824e68b8ce75d6d8f09d5eb7" ## } ## ## When you're finished, clean up or stop ## ## $ stop_ln ## $ destroy_ln # clean up the lightning directories ## # We've got a legacy problem is that PATH_TO_LIGHTNING is the # path to the lightningd / lightning-cli and PATH_TO_BITCOIN # is the path to the bitcoin data dir. These are not the same # things (data directories vs binary locations). # Ideally we'd let users set each of these four # things independently. Unless we rename stuff, this going to # be problematic. # # Instead we rename them and throw up # if you're using the old ones. if [ -n "$PATH_TO_LIGHTNING" ]; then echo PATH_TO_LIGHTNING is no longer supported, please use LIGHTNING_BIN return 1 fi if [ -n "$PATH_TO_BITCOIN" ]; then echo PATH_TO_BITCOIN is no longer supported, please use BITCOIN_DIR return 1 fi # Do the Right Thing if we're currently in top of srcdir. if [ -z "$LIGHTNING_BIN" ] && [ -x cli/lightning-cli ] && [ -x lightningd/lightningd ]; then LIGHTNING_BIN=$(pwd) fi if [ -z "$LIGHTNING_BIN" ]; then # Already installed maybe? Prints if ! type lightning-cli >/dev/null 2>&1 ; then echo lightning-cli: not found return 1 fi if ! type lightningd >/dev/null 2>&1 ; then echo lightningd: not found return 1 fi LCLI=lightning-cli LIGHTNINGD=lightningd else LCLI="$LIGHTNING_BIN"/cli/lightning-cli LIGHTNINGD="$LIGHTNING_BIN"/lightningd/lightningd # This mirrors "type" output above. fi if [ -z "$LIGHTNING_DIR" ]; then # Default is to use the /tmp directory LIGHTNING_DIR=/tmp fi if [ -z "$BITCOIN_DIR" ]; then if [ -d "$HOME/snap/bitcoin-core/common/.bitcoin" ]; then BITCOIN_DIR="$HOME/snap/bitcoin-core/common/.bitcoin" elif [ -d "$HOME/.bitcoin" ]; then BITCOIN_DIR="$HOME/.bitcoin" elif [ -d "$HOME/Library/Application Support/Bitcoin/" ]; then BITCOIN_DIR="$HOME/Library/Application Support/Bitcoin/" else echo "\$BITCOIN_DIR not set to a .bitcoin dir?" >&2 return fi fi # shellcheck disable=SC2153 if [ -z "$BITCOIN_BIN" ]; then # Already installed maybe? Prints if ! type bitcoin-cli >/dev/null 2>&1 ; then echo bitcoin-cli: not found return 1 fi if ! type bitcoind >/dev/null 2>&1 ; then echo bitcoind: not found return 1 fi BCLI=bitcoin-cli BITCOIND=bitcoind else BCLI="$BITCOIN_BIN"/bitcoin-cli BITCOIND="$BITCOIN_BIN"/bitcoind fi echo lightning-cli is "$LCLI" echo lightningd is "$LIGHTNINGD" echo lightning-dir is "$LIGHTNING_DIR" export LCLI="$LCLI" export LIGHTNINGD="$LIGHTNINGD" export LIGHTNING_DIR="$LIGHTNING_DIR" echo bitcoin-cli is "$BCLI" echo bitcoind is "$BITCOIND" echo bitcoin-dir is "$BITCOIN_DIR" export BCLI="$BCLI" export BITCOIND="$BITCOIND" export BITCOIN_DIR="$BITCOIN_DIR" wait_for_lightningd() { if [ -z "$1" ]; then node_count=2 else node_count=$1 fi for i in $(seq "5"); do if $LCLI --lightning-dir="$LIGHTNING_DIR"/l"$node_count" getinfo > /dev/null 2>&1; then break else sleep 1 fi done } clnrest_status() { logfile="$1" active_str="plugin-clnrest.py: REST Server is starting" disabled_str="plugin-clnrest.py: Killing plugin: disabled itself" if grep -q "$active_str" "$logfile"; then echo "active" elif grep -q "$disabled_str" "$logfile"; then echo "disabled" else echo "waiting" fi } start_nodes() { if [ -z "$1" ]; then node_count=2 else node_count=$1 fi if [ "$node_count" -gt 100 ]; then node_count=100 fi if [ -z "$2" ]; then network=regtest else network=$2 fi # This supresses db syncs, for speed. if type eatmydata >/dev/null 2>&1; then EATMYDATA=eatmydata else EATMYDATA= fi LN_NODES=$node_count for i in $(seq "$node_count"); do socket=$(( 7070 + i * 101)) mkdir -p "$LIGHTNING_DIR/l$i" # Node config cat <<- EOF > "$LIGHTNING_DIR/l$i/config" network=$network log-level=debug log-file=$LIGHTNING_DIR/l$i/log addr=localhost:$socket allow-deprecated-apis=false developer dev-fast-gossip dev-bitcoind-poll=5 experimental-dual-fund experimental-splicing experimental-offers funder-policy=match funder-policy-mod=100 funder-min-their-funding=10000 funder-per-channel-max=100000 funder-fuzz-percent=0 funder-lease-requests-only=false lease-fee-base-sat=2sat lease-fee-basis=50 invoices-onchain-fallback EOF # If clnrest loads, add the port so it will run if [ -n "$ACTIVATE_CLNREST" ]; then echo "clnrest-port=$((3109+i))" >> "$LIGHTNING_DIR/l$i/config" fi # Start the lightning nodes test -f "$LIGHTNING_DIR/l$i/lightningd-$network.pid" || \ $EATMYDATA "$LIGHTNINGD" "--network=$network" "--lightning-dir=$LIGHTNING_DIR/l$i" "--bitcoin-datadir=$BITCOIN_DIR" "--database-upgrade=true" & # shellcheck disable=SC2139 disable=SC2086 alias l$i-cli="$LCLI --lightning-dir=$LIGHTNING_DIR/l$i" # shellcheck disable=SC2139 disable=SC2086 alias l$i-log="less $LIGHTNING_DIR/l$i/log" done if [ -z "$EATMYDATA" ]; then echo "WARNING: eatmydata not found: install it for faster testing" fi # Give a hint. echo "Commands: " for i in $(seq "$node_count"); do echo " l$i-cli, l$i-log," done } start_ln() { # Start bitcoind in the background test -f "$BITCOIN_DIR/regtest/bitcoind.pid" || \ "$BITCOIND" -datadir="$BITCOIN_DIR" -regtest -txindex -fallbackfee=0.00000253 -daemon # Wait for it to start. while ! "$BCLI" -datadir="$BITCOIN_DIR" -regtest ping 2> /tmp/null; do echo "awaiting bitcoind..." && sleep 1; done # Check if default wallet exists if ! "$BCLI" -datadir="$BITCOIN_DIR" -regtest listwalletdir | jq -r '.wallets[] | .name' | grep -wqe 'default' ; then # wallet dir does not exist, create one echo "Making \"default\" bitcoind wallet." "$BCLI" -datadir="$BITCOIN_DIR" -regtest createwallet default >/dev/null 2>&1 fi # Check if default wallet is loaded if ! "$BCLI" -datadir="$BITCOIN_DIR" -regtest listwallets | jq -r '.[]' | grep -wqe 'default' ; then echo "Loading \"default\" bitcoind wallet." "$BCLI" -datadir="$BITCOIN_DIR" -regtest loadwallet default >/dev/null 2>&1 fi # Kick it out of initialblockdownload if necessary if "$BCLI" -datadir="$BITCOIN_DIR" -regtest getblockchaininfo | grep -q 'initialblockdownload.*true'; then "$BCLI" -datadir="$BITCOIN_DIR" -regtest generatetoaddress 1 "$($BCLI -datadir="$BITCOIN_DIR" -regtest getnewaddress)" > /dev/null fi alias bt-cli='"$BCLI" -datadir="$BITCOIN_DIR" -regtest' if [ -z "$1" ]; then nodes=2 else nodes="$1" fi # Are the clnrest dependencies installed? if timeout 2 python3 plugins/clnrest/clnrest.py > /dev/null 2>&1; then ACTIVATE_CLNREST=1 fi start_nodes "$nodes" regtest echo " bt-cli, stop_ln, fund_nodes" wait_for_lightningd "$nodes" active_status=$(clnrest_status "$LIGHTNING_DIR/l1/log") if [ -n "$ACTIVATE_CLNREST" ] && [ "$active_status" = "active" ] ; then node_info regtest elif [ "$active_status" = "disabled" ]; then echo "clnrest is disabled. Try installing python developer dependencies" echo "with 'poetry install'" else echo "timed out parsing log $LIGHTNING_DIR/l1/log" fi } ensure_bitcoind_funds() { if [ -z "$ADDRESS" ]; then ADDRESS=$("$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" getnewaddress) fi balance=$("$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" getbalance) if [ 1 -eq "$(echo "$balance"'<1' | bc -l)" ]; then printf "%s" "Mining into address " "$ADDRESS""... " "$BCLI" -datadir="$BITCOIN_DIR" -regtest generatetoaddress 100 "$ADDRESS" > /dev/null echo "done." fi } fund_nodes() { WALLET="default" NODES="" for var in "$@"; do case $var in -w=*|--wallet=*) WALLET="${var#*=}" ;; *) NODES="${NODES:+${NODES} }${var}" ;; esac done if [ -z "$NODES" ]; then NODES=$(seq "$node_count") fi WALLET="-rpcwallet=$WALLET" ADDRESS=$("$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" getnewaddress) ensure_bitcoind_funds echo "bitcoind balance:" "$("$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" getbalance)" last_node="" echo "$NODES" | while read -r i; do if [ -z "$last_node" ]; then last_node=$i continue fi node1=$last_node node2=$i last_node=$i L2_NODE_ID=$("$LCLI" -F --lightning-dir="$LIGHTNING_DIR"/l"$node2" getinfo | sed -n 's/^id=\(.*\)/\1/p') L2_NODE_PORT=$("$LCLI" -F --lightning-dir="$LIGHTNING_DIR"/l"$node2" getinfo | sed -n 's/^binding\[0\].port=\(.*\)/\1/p') "$LCLI" -H --lightning-dir="$LIGHTNING_DIR"/l"$node1" connect "$L2_NODE_ID"@localhost:"$L2_NODE_PORT" > /dev/null L1_WALLET_ADDR=$($LCLI -F --lightning-dir=$LIGHTNING_DIR/l"$node1" newaddr | sed -n 's/^bech32=\(.*\)/\1/p') L2_WALLET_ADDR=$($LCLI -F --lightning-dir=$LIGHTNING_DIR/l"$node2" newaddr | sed -n 's/^bech32=\(.*\)/\1/p') ensure_bitcoind_funds "$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" sendtoaddress "$L1_WALLET_ADDR" 1 > /dev/null "$BCLI" -datadir="$BITCOIN_DIR" -regtest "$WALLET" sendtoaddress "$L2_WALLET_ADDR" 1 > /dev/null "$BCLI" -datadir="$BITCOIN_DIR" -regtest generatetoaddress 1 "$ADDRESS" > /dev/null printf "%s" "Waiting for lightning node funds... " while ! "$LCLI" -F --lightning-dir="$LIGHTNING_DIR"/l"$node1" listfunds | grep -q "outputs" do sleep 1 done while ! "$LCLI" -F --lightning-dir="$LIGHTNING_DIR"/l"$node2" listfunds | grep -q "outputs" do sleep 1 done echo "found." printf "%s" "Funding channel <-> node " "$node1" " to node " "$node2"". " "$LCLI" --lightning-dir="$LIGHTNING_DIR"/l"$node1" fundchannel "$L2_NODE_ID" 1000000 > /dev/null "$BCLI" -datadir="$BITCOIN_DIR" -regtest generatetoaddress 6 "$ADDRESS" > /dev/null printf "%s" "Waiting for confirmation... " while ! "$LCLI" -F --lightning-dir=$LIGHTNING_DIR/l"$node1" listchannels | grep -q "channels" do sleep 1 done echo "done." done } stop_nodes() { network=${1:-regtest} if [ -n "$LN_NODES" ]; then for i in $(seq "$LN_NODES"); do test ! -f "$LIGHTNING_DIR/l$i/lightningd-$network.pid" || \ (kill "$(cat "$LIGHTNING_DIR/l$i/lightningd-$network.pid")"; \ rm "$LIGHTNING_DIR/l$i/lightningd-$network.pid") unalias "l$i-cli" unalias "l$i-log" done fi } stop_ln() { stop_nodes "$@" test ! -f "$BITCOIN_DIR/regtest/bitcoind.pid" || \ (kill "$(cat "$BITCOIN_DIR/regtest/bitcoind.pid")"; \ rm "$BITCOIN_DIR/regtest/bitcoind.pid") unset LN_NODES unalias bt-cli } node_info() { network=${1:-regtest} if [ -n "$LN_NODES" ]; then echo "Node Info:" for i in $(seq "$LN_NODES"); do echo " l$i rest: https://127.0.0.1:$((3109 + i))"\ " rune: $($LCLI --lightning-dir="$LIGHTNING_DIR"/l"$i" createrune | jq .rune)" done fi } destroy_ln() { rm -rf $LIGHTNING_DIR/l[0-9]* } start_elem() { if [ -z "$ELEMENTS_DIR" ]; then if [ -d "$HOME/.elements" ]; then ELEMENTS_DIR="$HOME/.elements" else echo "\$ELEMENTS_DIR not set to a .elements dir" >&2 return fi fi test -f "$ELEMENTS_DIR/liquid-regtest/bitcoin.pid" || \ elementsd -chain=liquid-regtest -printtoconsole -logtimestamps -nolisten -validatepegin=0 -con_blocksubsidy=5000000000 -daemon # Wait for it to start. while ! elements-cli -chain=liquid-regtest ping 2> /tmp/null; do echo "awaiting elementsd..." && sleep 1; done # Kick it out of initialblockdownload if necessary if elements-cli -chain=liquid-regtest getblockchaininfo | grep -q 'initialblockdownload.*true'; then elements-cli -chain=liquid-regtest generatetoaddress 1 "$(elements-cli -chain=liquid-regtest getnewaddress)" > /dev/null fi alias et-cli='elements-cli -chain=liquid-regtest' if [ -z "$1" ]; then nodes=2 else nodes="$1" fi start_nodes "$nodes" liquid-regtest echo " et-cli, stop_elem" } stop_elem() { stop_nodes "$1" liquid-regtest test ! -f "$ELEMENTS_DIR/liquid-regtest/bitcoind.pid" || \ (kill "$(cat "$ELEMENTS_DIR/liquid-regtest/bitcoind.pid")"; \ rm "$ELEMENTS_DIR/liquid-regtest/bitcoind.pid") unset LN_NODES unalias et-cli } connect() { if [ -z "$1" ] || [ -z "$2" ]; then printf "usage: connect 1 2\n" else to=$("$LCLI" --lightning-dir="$LIGHTNING_DIR/l$2" -F getinfo | grep '^\(id\|binding\[0\]\.\(address\|port\)\)' | cut -d= -f2- | tr '\n' ' ' | (read -r ID ADDR PORT; echo "$ID@${ADDR}:$PORT")) "$LCLI" --lightning-dir="$LIGHTNING_DIR"/l"$1" connect "$to" fi } echo Useful commands: echo " start_ln 3: start three nodes, l1, l2, l3" echo " connect 1 2: connect l1 and l2" echo " fund_nodes: connect all nodes with channels, in a row" echo " stop_ln: shutdown" echo " destroy_ln: remove ln directories"