#!/bin/sh _command_exist() { if command -v "$1" >/dev/null 2>&1; then return 0 else echo "error: $1 command not found" >&2 return 1 fi } _function_exist() { if command -V "$1" 2>/dev/null | grep -qwi function >/dev/null 2>&1; then return 0 else echo "error: function $1 not set" >&2 return 1 fi } _create_dir() { if [ ! -e "$1" ]; then mkdir -p "$1" || return "$?" elif [ ! -d "$1" ]; then echo "error: $1 is not a directory" >&2 return 1 fi } # if $2 is provided use it as default # otherwise return error when not found _get_env_var() { if ! env_var="$(dotenv -f ".env" get "$1" 2>/dev/null)"; then if [ "$#" -ge 2 ]; then env_var="$2" else echo "error: getting $1 from .env" >&2 return 1 fi fi printf "%s\n" "$env_var" return 0 } # transform relative path into absolute and remove trailing slashes _get_env_var_path() { env_var="$(_get_env_var "$@")" || return "$?" real_path="$(realpath -m "$env_var")" || return "$?" printf "%s\n" "$real_path" return 0 } # extract the port from an env variable _get_env_var_port() { env_var="$(_get_env_var "$@")" || return "$?" printf "%s\n" "$env_var" | rev | cut -d ":" -f 1 | rev return 0 } _nodes_environment_set() { if [ ! -f "scripts/traditional/regtest-nodes" ]; then echo "error: source this script from the project root" >&2 return 1 fi if [ ! -f ".env" ]; then echo "error: .env is not present" >&2 return 1 fi if ! _command_exist dotenv; then return 1 fi TESTING="$(_get_env_var TESTING false)" || return "$?" case "$(printf "%s\n" "$TESTING" | tr '[:upper:]' '[:lower:]')" in true|yes|on|1) TESTING=true ;; *) TESTING=false ;; esac RUNSERVER_PORT="$(_get_env_var "RUNSERVER_PORT")" || return "$?" cln_set=false lnd_set=false LNVENDOR_COORD="$(_get_env_var LNVENDOR)" || return "$?" LNVENDOR_COORD="$(printf "%s\n" "$LNVENDOR_COORD" | tr '[:upper:]' '[:lower:]')" case "$LNVENDOR_COORD" in cln) cln_set=true ;; lnd) lnd_set=true ;; *) echo "error: LNVENDOR can be cln or lnd" >&2 return 1 ;; esac LNVENDOR_USER="$(_get_env_var LNVENDOR_USER)" || return "$?" LNVENDOR_USER="$(printf "%s\n" "$LNVENDOR_USER" | tr '[:upper:]' '[:lower:]')" case "$LNVENDOR_USER" in cln) cln_set=true ;; lnd) lnd_set=true ;; *) echo "error: LNVENDOR_USER can be cln or lnd" >&2 return 1 ;; esac if [ "$TESTING" = true ] && [ "$LNVENDOR_USER" != "lnd" ]; then echo "error: LNVENDOR_USER should be lnd when running tests" >&2 return 1 fi BITCOIND_BIN="$(_get_env_var_path "BITCOIND_BIN")" || return "$?" BITCOIN_CLI_BIN="$(_get_env_var_path "BITCOIN_CLI_BIN")" || return "$?" if [ "$cln_set" = true ]; then LIGHTNINGD_BIN="$(_get_env_var_path "LIGHTNINGD_BIN")" || return "$?" LIGHTNING_CLI_BIN="$(_get_env_var_path "LIGHTNING_CLI_BIN")" || return "$?" HOLDINVOICE_PLUGIN_BIN="$(_get_env_var_path "HOLDINVOICE_PLUGIN_BIN")" || return "$?" fi if [ "$lnd_set" = true ]; then LND_BIN="$(_get_env_var_path "LND_BIN")" || return "$?" LNCLI_BIN="$(_get_env_var_path "LNCLI_BIN")" || return "$?" fi REGTEST_NODES_DIR="$(_get_env_var_path "TRADITIONAL_NODES_DIR")" || return "$?" REGTEST_LOGS_DIR="$(_get_env_var_path "TRADITIONAL_LOGS_DIR")" || return "$?" ROBOAUTO_GIT_DIR="$(_get_env_var_path "ROBOAUTO_GIT_DIR" false)" || return "$?" BITCOIN_REGTEST_RPC_PORT="$(_get_env_var_port "BITCOIND_RPCURL")" || return "$?" BITCOIN_REGTEST_RPC_USER="$(_get_env_var "BITCOIND_RPCUSER")" || return "$?" BITCOIN_REGTEST_RPC_PASS="$(_get_env_var "BITCOIND_RPCPASSWORD")" || return "$?" BITCOIN_REGTEST_ZMQ_BLOCK_PORT="$(_get_env_var "BITCOIN_TEST_ZMQ_BLOCK_PORT")" || return "$?" BITCOIN_REGTEST_ZMQ_TX_PORT="$(_get_env_var "BITCOIN_TEST_ZMQ_TX_PORT")" || return "$?" if [ "$cln_set" = true ]; then CLN_COORD_GRPC_PORT="$(_get_env_var_port "CLN_GRPC_HOST")" || return "$?" CLN_COORD_HOLD_PORT="$(_get_env_var_port "CLN_GRPC_HOLD_HOST")" || return "$?" CLN_COORD_LISTEN_PORT="$(_get_env_var "CLN_TEST_COORD_LISTEN_PORT")" || return "$?" CLN_USER_GRPC_PORT="$(_get_env_var "CLN_TEST_USER_GRPC_PORT")" || return "$?" CLN_USER_LISTEN_PORT="$(_get_env_var "CLN_TEST_USER_LISTEN_PORT")" || return "$?" fi if [ "$lnd_set" = true ]; then LND_COORD_RPC_PORT="$(_get_env_var_port "LND_GRPC_HOST")" || return "$?" LND_COORD_LISTEN_PORT="$(_get_env_var "LND_TEST_COORD_LISTEN_PORT")" || return "$?" LND_COORD_REST_PORT="$(_get_env_var "LND_TEST_COORD_REST_PORT")" || return "$?" LND_USER_RPC_PORT="$(_get_env_var "LND_TEST_USER_GRPC_PORT")" || return "$?" LND_USER_LISTEN_PORT="$(_get_env_var "LND_TEST_USER_LISTEN_PORT")" || return "$?" LND_USER_REST_PORT="$(_get_env_var "LND_TEST_USER_REST_PORT")" || return "$?" fi if [ -z "$BITCOIND_BIN" ]; then BITCOIND_BIN="bitcoind" fi if ! _command_exist "$BITCOIND_BIN"; then return 1 fi if [ -z "$BITCOIN_CLI_BIN" ]; then BITCOIN_CLI_BIN="bitcoin-cli" fi if ! _command_exist "$BITCOIN_CLI_BIN"; then return 1 fi if [ "$cln_set" = true ]; then if [ -z "$LIGHTNINGD_BIN" ]; then LIGHTNINGD_BIN="lightningd" fi if ! _command_exist "$LIGHTNINGD_BIN"; then return 1 fi if [ -z "$LIGHTNING_CLI_BIN" ]; then LIGHTNING_CLI_BIN="lightning-cli" fi if ! _command_exist "$LIGHTNING_CLI_BIN"; then return 1 fi if [ -z "$HOLDINVOICE_PLUGIN_BIN" ]; then echo "error: $HOLDINVOICE_PLUGIN_BIN not set" >&2 return 1 fi if [ ! -f "$HOLDINVOICE_PLUGIN_BIN" ]; then echo "error: $HOLDINVOICE_PLUGIN_BIN plugin not found" >&2 return 1 fi fi if [ "$lnd_set" = true ]; then if [ -z "$LND_BIN" ]; then LND_BIN="lnd" fi if ! _command_exist "$LND_BIN"; then return 1 fi if [ -z "$LNCLI_BIN" ]; then LNCLI_BIN="lncli" fi if ! _command_exist "$LNCLI_BIN"; then return 1 fi fi if [ -z "$REGTEST_NODES_DIR" ]; then echo "error: REGTEST_NODES_DIR not set" >&2 return 1 fi _create_dir "$REGTEST_NODES_DIR" || return "$?" if [ -z "$REGTEST_LOGS_DIR" ]; then echo "error: REGTEST_LOGS_DIR not set" >&2 return 1 fi _create_dir "$REGTEST_LOGS_DIR" || return "$?" BITCOIN_DIR="$REGTEST_NODES_DIR/bitcoin" ROBOAUTO_DIR="$REGTEST_NODES_DIR/roboauto" if [ "$cln_set" = true ]; then CLN_COORD_DIR="$REGTEST_NODES_DIR/cln-coord" CLN_USER_DIR="$REGTEST_NODES_DIR/cln-user" cln_coor_dir_env="$(_get_env_var_path "CLN_DIR")" || return "$?" if [ "$cln_coor_dir_env" != "$CLN_COORD_DIR/regtest" ]; then echo "error: CLN_DIR not consistent with REGTEST_NODES_DIR" >&2 return 1 fi fi if [ "$lnd_set" = true ]; then LND_COORD_DIR="$REGTEST_NODES_DIR/lnd-coord" LND_USER_DIR="$REGTEST_NODES_DIR/lnd-user" lnd_coord_dir_env="$(_get_env_var_path "LND_DIR")" || return "$?" if [ "$lnd_coord_dir_env" != "$LND_COORD_DIR" ]; then echo "error: LND_DIR not consistent with REGTEST_NODES_DIR" >&2 return 1 fi correct_macaroon_path="data/chain/bitcoin/regtest/admin.macaroon" macaroon_path="$( _get_env_var "MACAROON_PATH" )" || return "$?" if [ "$macaroon_path" != "$correct_macaroon_path" ]; then echo "error: MACAROON_PATH should be $correct_macaroon_path" >&2 return 1 fi lnd_test_coord_macaroon_path="$( _get_env_var_path "LND_TEST_COORD_MACAROON_PATH" )" || return "$?" if [ \ "$lnd_test_coord_macaroon_path" != \ "$LND_COORD_DIR/$correct_macaroon_path" \ ]; then echo "error: LND_TEST_COORD_MACAROON_PATH not consistent with REGTEST_NODES_DIR" >&2 return 1 fi lnd_test_user_macaroon_path="$( _get_env_var_path "LND_TEST_USER_MACAROON_PATH" )" || return "$?" if [ \ "$lnd_test_user_macaroon_path" != \ "$LND_USER_DIR/$correct_macaroon_path" \ ]; then echo "error: LND_TEST_USER_MACAROON_PATH not consistent with REGTEST_NODES_DIR" >&2 return 1 fi fi } _pgrep_bitcoin_regtest() { pgrep -f "$BITCOIND_BIN -datadir=$BITCOIN_DIR -regtest -daemon" >/dev/null } _bitcoin_regtest_check_started() { if ! _pgrep_bitcoin_regtest; then echo "error: bitcoin regtest not started" >&2 return 1 fi if ! _function_exist btc_reg; then return 1 fi return 0 } bitcoin_regtest_mine() { _bitcoin_regtest_check_started || return "$?" if [ "$#" -lt 2 ]; then return 1 fi if [ "$2" = "new" ]; then if ! new_address="$(btc_reg getnewaddress)"; then echo "error: could not create new address" >&2 return 1 fi else new_address="$2" fi if ! new_block_hash="$( btc_reg -named generatetoaddress nblocks="$1" address="$new_address" | jq -r '.[-1]' )"; then echo "error: could not generate to $new_address" >&2 return 1 fi while [ "$(btc_reg getbestblockhash)" != "$new_block_hash" ]; do echo "waiting for $1 blocks to be mined..." sleep 1 done unset new_block_hash echo "mined $1 blocks to $new_address" unset new_address } bitcoin_regtest_start() { _create_dir "$BITCOIN_DIR" || return "$?" echo "writing bitcoin regtest config" cat << EOF > "$BITCOIN_DIR/bitcoin.conf" txindex=1 rest=1 server=1 logips=1 listenonion=0 zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT [regtest] rpcport=$BITCOIN_REGTEST_RPC_PORT rpcuser=$BITCOIN_REGTEST_RPC_USER rpcpassword=$BITCOIN_REGTEST_RPC_PASS EOF if ! _pgrep_bitcoin_regtest; then echo "starting bitcoin regtest" if ! "$BITCOIND_BIN" -datadir="$BITCOIN_DIR" -regtest -daemon >/dev/null; then echo "error: starting bitcoind regtest daemon" >&2 return 1 fi else echo "bitcoin regtest already started" fi btc_reg() { "$BITCOIN_CLI_BIN" \ -datadir="$BITCOIN_DIR" \ -regtest \ -rpcuser="$BITCOIN_REGTEST_RPC_USER" \ -rpcpassword="$BITCOIN_REGTEST_RPC_PASS" \ "$@" } # wait for bitcoin to start while ! btc_reg ping >/dev/null 2>&1; do echo "waiting for bitcoind regtes to start..." sleep 1 done # check if default wallet exists if ! btc_reg listwalletdir | jq -r '.wallets[] | .name' | grep "^default$" >/dev/null 2>&1 then if ! btc_reg -named createwallet \ wallet_name=default \ disable_private_keys=false \ blank=false \ avoid_reuse=false \ descriptors=true \ load_on_startup=true \ external_signer=false >/dev/null then echo "error: could not create default wallet" >&2 return 1 fi echo "default bitcoind wallet successfully created" fi # check if default wallet is loaded if ! btc_reg listwallets | jq -r '.[]' | grep "^default$" >/dev/null 2>&1 then if ! btc_reg loadwallet default; then echo "error: could not load default wallet" >&2 return 1 fi echo "default bitcoind wallet successfully loaded" fi bitcoin_regtest_mine 1 "new" || return "$?" while [ "$(btc_reg getblockchaininfo | jq -r '.initialblockdownload')" != false ]; do echo "waiting for bitcoind regtes to download blocks..." sleep 1 done echo "bitcoin regtest started, data directory is $BITCOIN_DIR" echo "btc_reg function set" } _bitcoin_regtest_stop() { if ! _pgrep_bitcoin_regtest; then echo "bitcoin regtest already stopped" else if ! "$BITCOIN_CLI_BIN" \ -datadir="$BITCOIN_DIR" \ -regtest \ stop >/dev/null then echo "error: bitcoin regtest not stopped" >&2 fi while _pgrep_bitcoin_regtest; do echo "waiting for bitcoin regtest to stop..." sleep 1 done echo "bitcoin regtest stopped" fi } bitcoin_regtest_stop_and_remove() { _bitcoin_regtest_stop || return "$?" if [ ! -e "$BITCOIN_DIR" ]; then echo "bitcoin directory not present" else if ! rm -rf "$BITCOIN_DIR"; then echo "error: removing bitcoin directory $BITCOIN_DIR" return 1 fi echo "removed bitcoin directory $BITCOIN_DIR" fi } _pgrep_cln_coord() { pgrep -f \ "$LIGHTNINGD_BIN --lightning-dir=$CLN_COORD_DIR --regtest --daemon" \ >/dev/null } cln_coord_start() { _bitcoin_regtest_check_started || return "$?" _create_dir "$CLN_COORD_DIR" || return "$?" echo "writing cln coordinator config" cat << EOF > "$CLN_COORD_DIR/config" bitcoin-cli=$BITCOIN_CLI_BIN bitcoin-datadir=$BITCOIN_DIR bitcoin-rpcuser=$BITCOIN_REGTEST_RPC_USER bitcoin-rpcpassword=$BITCOIN_REGTEST_RPC_PASS bitcoin-rpcport=$BITCOIN_REGTEST_RPC_PORT alias=cln-coordinator rgb=100000 fee-base=0 fee-per-satoshi=0 min-capacity-sat=990000 ignore-fee-limits=true funding-confirms=1 max-concurrent-htlcs=64 max-dust-htlc-exposure-msat=1000000000 cltv-delta=144 cltv-final=144 bitcoin-retry-timeout=120 database-upgrade=true log-file=lightning.log addr=localhost:$CLN_COORD_LISTEN_PORT grpc-port=$CLN_COORD_GRPC_PORT important-plugin=$HOLDINVOICE_PLUGIN_BIN grpc-hold-port=$CLN_COORD_HOLD_PORT disable-plugin=clnrest disable-plugin=wss-proxy EOF if ! _pgrep_cln_coord; then echo "starting cln coordinator" if ! "$LIGHTNINGD_BIN" \ --lightning-dir="$CLN_COORD_DIR" \ --regtest \ --daemon \ >/dev/null then echo "error: starting cln coordinator daemon" >&2 return 1 fi else echo "cln coordinator already started" fi cln_coord() { "$LIGHTNING_CLI_BIN" \ --lightning-dir="$CLN_COORD_DIR" \ --regtest \ "$@" } while [ \ "$(cln_coord getinfo | jq -r '.blockheight')" -ne \ "$(btc_reg getblockcount)" \ ]; do echo "waiting for cln coordinator to sync with the chain..." sleep 1 done echo "cln coordinator started, data directory is $CLN_COORD_DIR" echo "cln_coord function set" } _cln_coord_stop() { if ! _pgrep_cln_coord; then echo "cln coordinator already stopped" else if ! "$LIGHTNING_CLI_BIN" \ --lightning-dir="$CLN_COORD_DIR" \ --regtest \ stop >/dev/null then echo "error: cln coordinator not stopped" >&2 fi while _pgrep_cln_coord; do echo "waiting for cln coordinator to stop..." sleep 1 done echo "cln coordinator stopped" fi } cln_coord_stop_and_remove() { _cln_coord_stop || return "$?" if [ ! -e "$CLN_COORD_DIR" ]; then echo "cln coordinator directory not present" else if ! rm -rf "$CLN_COORD_DIR"; then echo "error: removing cln coordinator directory $CLN_COORD_DIR" return 1 fi echo "removed cln coordinator directory $CLN_COORD_DIR" fi } _pgrep_cln_user() { pgrep -f \ "$LIGHTNINGD_BIN --lightning-dir=$CLN_USER_DIR --regtest --daemon" \ >/dev/null } cln_user_start() { _bitcoin_regtest_check_started || return "$?" _create_dir "$CLN_USER_DIR" || return "$?" echo "writing cln user config" cat << EOF > "$CLN_USER_DIR/config" bitcoin-cli=$BITCOIN_CLI_BIN bitcoin-datadir=$BITCOIN_DIR bitcoin-rpcuser=$BITCOIN_REGTEST_RPC_USER bitcoin-rpcpassword=$BITCOIN_REGTEST_RPC_PASS bitcoin-rpcport=$BITCOIN_REGTEST_RPC_PORT alias=cln-user rgb=200000 fee-base=0 fee-per-satoshi=0 min-capacity-sat=990000 ignore-fee-limits=true funding-confirms=1 max-concurrent-htlcs=64 max-dust-htlc-exposure-msat=1000000000 cltv-delta=144 cltv-final=144 bitcoin-retry-timeout=120 database-upgrade=true log-file=lightning.log addr=localhost:$CLN_USER_LISTEN_PORT grpc-port=$CLN_USER_GRPC_PORT disable-plugin=clnrest disable-plugin=wss-proxy EOF if ! _pgrep_cln_user; then echo "starting cln user" if ! "$LIGHTNINGD_BIN" \ --lightning-dir="$CLN_USER_DIR" \ --regtest \ --daemon \ >/dev/null then echo "error: starting cln user daemon" >&2 return 1 fi else echo "cln user already started" fi cln_user() { "$LIGHTNING_CLI_BIN" \ --lightning-dir="$CLN_USER_DIR" \ --regtest \ "$@" } while [ \ "$(cln_user getinfo | jq -r '.blockheight')" -ne \ "$(btc_reg getblockcount)" \ ]; do echo "waiting for cln user to sync with the chain..." sleep 1 done echo "cln user started, data directory is $CLN_USER_DIR" echo "cln_user function set" } _cln_user_stop() { if ! _pgrep_cln_user; then echo "cln user already stopped" else if ! "$LIGHTNING_CLI_BIN" \ --lightning-dir="$CLN_USER_DIR" \ --regtest \ stop >/dev/null then echo "error: cln user not stopped" >&2 fi while _pgrep_cln_user; do echo "waiting for cln user to stop..." sleep 1 done echo "cln user stopped" fi } cln_user_stop_and_remove() { _cln_user_stop || return "$?" if [ ! -e "$CLN_USER_DIR" ]; then echo "cln user directory not present" else if ! rm -rf "$CLN_USER_DIR"; then echo "error: removing cln user directory $CLN_USER_DIR" return 1 fi echo "removed cln user directory $CLN_USER_DIR" fi } _pgrep_lnd_coord() { pgrep -f "$LND_BIN --lnddir=$LND_COORD_DIR --bitcoin.regtest" >/dev/null } lnd_coord_start() { _bitcoin_regtest_check_started || return "$?" _create_dir "$LND_COORD_DIR" || return "$?" echo "writing lnd coordinator config" cat << EOF > "$LND_COORD_DIR/lnd.conf" [Application Options] listen=localhost:$LND_COORD_LISTEN_PORT rpclisten=localhost:$LND_COORD_RPC_PORT restlisten=localhost:$LND_COORD_REST_PORT no-rest-tls=true tlsdisableautofill=true noseedbackup=true maxpendingchannels=16 minchansize=20000 alias=lnd-coordinator color=#300000 [Bitcoin] bitcoin.node=bitcoind bitcoin.defaultchanconfs=1 bitcoin.basefee=0 bitcoin.feerate=0 [Bitcoind] bitcoind.dir=$BITCOIN_DIR bitcoind.config=$BITCOIN_DIR/bitcoin.conf bitcoind.rpchost=localhost:$BITCOIN_REGTEST_RPC_PORT bitcoind.rpcuser=$BITCOIN_REGTEST_RPC_USER bitcoind.rpcpass=$BITCOIN_REGTEST_RPC_PASS bitcoind.zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT bitcoind.zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT [protocol] protocol.wumbo-channels=true EOF if ! _pgrep_lnd_coord; then echo "starting lnd coordinator" "$LND_BIN" \ --lnddir="$LND_COORD_DIR" \ --bitcoin.regtest \ >"$REGTEST_LOGS_DIR/lnd-coord" 2>&1 & else echo "lnd coordinator already started" fi lnd_coord() { "$LNCLI_BIN" \ --lnddir="$LND_COORD_DIR" \ --network regtest \ --rpcserver localhost:"$LND_COORD_RPC_PORT" \ "$@" } while [ "$(lnd_coord getinfo 2>/dev/null | jq -r '.synced_to_chain')" != true ]; do echo "waiting for lnd coordinator to sync with the chain..." sleep 1 done # while [ "$(lnd_coord getinfo 2>/dev/null | jq -r '.synced_to_graph')" != true ]; do # echo "waiting for lnd coordinator to sync with the graph..." # sleep 1 # done echo "lnd coordinator started, data directory is $LND_COORD_DIR" echo "lnd_coord function set" } _lnd_coord_stop() { if ! _pgrep_lnd_coord; then echo "lnd coordinator already stopped" else if ! "$LNCLI_BIN" \ --lnddir="$LND_COORD_DIR" \ --network regtest \ --rpcserver localhost:"$LND_COORD_RPC_PORT" \ stop >/dev/null then echo "error: lnd coordinator not stopped" >&2 fi while _pgrep_lnd_coord; do echo "waiting for lnd coordinator to stop..." sleep 1 done echo "lnd coordinator stopped" fi } lnd_coord_stop_and_remove() { _lnd_coord_stop || return "$?" if [ ! -e "$LND_COORD_DIR" ]; then echo "lnd coordinator directory not present" else if ! rm -rf "$LND_COORD_DIR"; then echo "error: removing lnd coordinator directory $LND_COORD_DIR" return 1 fi echo "removed lnd coordinator directory $LND_COORD_DIR" fi } _pgrep_lnd_user() { pgrep -f "$LND_BIN --lnddir=$LND_USER_DIR --bitcoin.regtest" >/dev/null } lnd_user_start() { _bitcoin_regtest_check_started || return "$?" _create_dir "$LND_USER_DIR" || return "$?" echo "writing lnd user config" cat << EOF > "$LND_USER_DIR/lnd.conf" [Application Options] listen=localhost:$LND_USER_LISTEN_PORT rpclisten=localhost:$LND_USER_RPC_PORT restlisten=localhost:$LND_USER_REST_PORT no-rest-tls=true tlsdisableautofill=true noseedbackup=true maxpendingchannels=16 minchansize=20000 alias=lnd-user color=#400000 [Bitcoin] bitcoin.node=bitcoind bitcoin.defaultchanconfs=1 bitcoin.basefee=0 bitcoin.feerate=0 [Bitcoind] bitcoind.dir=$BITCOIN_DIR bitcoind.config=$BITCOIN_DIR/bitcoin.conf bitcoind.rpchost=localhost:$BITCOIN_REGTEST_RPC_PORT bitcoind.rpcuser=$BITCOIN_REGTEST_RPC_USER bitcoind.rpcpass=$BITCOIN_REGTEST_RPC_PASS bitcoind.zmqpubrawblock=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_BLOCK_PORT bitcoind.zmqpubrawtx=tcp://127.0.0.1:$BITCOIN_REGTEST_ZMQ_TX_PORT [protocol] protocol.wumbo-channels=true EOF if ! _pgrep_lnd_user; then echo "starting lnd user" "$LND_BIN" \ --lnddir="$LND_USER_DIR" \ --bitcoin.regtest \ >"$REGTEST_LOGS_DIR/lnd-user" 2>&1 & else echo "lnd user already started" fi lnd_user() { "$LNCLI_BIN" \ --lnddir="$LND_USER_DIR" \ --network regtest \ --rpcserver localhost:"$LND_USER_RPC_PORT" \ "$@" } while [ "$(lnd_user getinfo 2>/dev/null | jq -r '.synced_to_chain')" != true ]; do echo "waiting for lnd user to sync with the chain..." sleep 1 done # while [ "$(lnd_user getinfo 2>/dev/null | jq -r '.synced_to_graph')" != true ]; do # echo "waiting for lnd user to sync with the graph..." # sleep 1 # done echo "lnd user started, data directory is $LND_USER_DIR" echo "lnd_user function set" } _lnd_user_stop() { if ! _pgrep_lnd_user; then echo "lnd user already stopped" else if ! "$LNCLI_BIN" \ --lnddir="$LND_USER_DIR" \ --network regtest \ --rpcserver localhost:"$LND_USER_RPC_PORT" \ stop >/dev/null then echo "error: lnd user not stopped" >&2 fi while _pgrep_lnd_user; do echo "waiting for lnd user to stop..." sleep 1 done echo "lnd user stopped" fi } lnd_user_stop_and_remove() { _lnd_user_stop || return "$?" if [ ! -e "$LND_USER_DIR" ]; then echo "lnd user directory not present" else if ! rm -rf "$LND_USER_DIR"; then echo "error: removing lnd user directory $LND_USER_DIR" return 1 fi echo "removed lnd user directory $LND_USER_DIR" fi } _mine_blocks_coordinator() { coord_node="$1" case "$coord_node" in cln) if ! coord_address="$( cln_coord -k newaddr addresstype=p2tr | jq -r '.p2tr' )"; then echo "error: generating cln coordinator address" >&2 return 1 fi ;; lnd) if ! coord_address="$( lnd_coord newaddress p2tr | jq -r '.address' )"; then echo "error: generating lnd coordinator address" >&2 return 1 fi ;; esac bitcoin_regtest_mine 101 "$coord_address" || return "$?" unset user_address } _robosats_regtest_channel_create_cln_user() { if [ "$#" -lt 1 ]; then echo "error: insert coordinator node" >&2 return 1 fi coord_node="$1" shift 1 _bitcoin_regtest_check_started || return "$?" case "$coord_node" in cln) if ! _pgrep_cln_coord; then echo "error: cln coordinator not started" >&2 return 1 fi if ! _function_exist cln_coord; then return 1 fi coord_id="$(cln_coord getinfo | jq -r '.id')" coord_port="$CLN_COORD_LISTEN_PORT" ;; lnd) if ! _pgrep_lnd_coord; then echo "error: cln coordinator not started" >&2 return 1 fi if ! _function_exist lnd_coord; then return 1 fi coord_id="$(lnd_coord getinfo | jq -r '.identity_pubkey')" coord_port="$LND_COORD_LISTEN_PORT" ;; *) echo "error: coordinator node can only be cln and lnd" >&2 return 1 ;; esac if ! _pgrep_cln_user; then echo "error: cln user not started" >&2 return 1 fi if ! _function_exist cln_user; then return 1 fi if ! cln_user connect "$coord_id"@localhost:"$coord_port" >/dev/null; then echo "error: connection lightning nodes" >&2 return 1 fi echo "lightning nodes connected" # check if channel not already present if [ "$( cln_user listpeerchannels "$coord_id" | jq -r '.channels | length' )" -ge 1 ]; then echo "lightning nodes already have a channel, not opening a new one" else echo "mining blocks to coordinator $coord_node" _mine_blocks_coordinator "$coord_node" || return "$?" previous_output_number="$(cln_user listfunds | jq -r '.outputs | length')" if ! user_address="$(cln_user -k newaddr addresstype=p2tr | jq -r '.p2tr')"; then echo "error: generating user address" >&2 return 1 fi echo "mining blocks to user cln" bitcoin_regtest_mine 101 "$user_address" || return "$?" unset user_address while [ \ "$(cln_user listfunds | jq -r '.outputs | length')" -le \ "$previous_output_number" \ ]; do echo "waiting for cln user to see the new blocks..." sleep 5 done while [ "$(cln_user listfunds | jq -r '.outputs[0].status')" != "confirmed" ]; do echo "waiting for cln user funds to mature..." sleep 1 done unset previous_output_number if ! cln_user -k fundchannel \ id="$coord_id" \ amount=1btc \ feerate=10000perkb \ announce=true \ >/dev/null then echo "error: funding lightning channel" >&2 return 1 fi echo "lightning channel created" bitcoin_regtest_mine 10 "new" || return "$?" while [ "$( cln_user listpeerchannels "$coord_id" | jq -r '.channels | length' )" -lt 1 ]; do echo "waiting for channel to confirm..." sleep 1 done echo "lightning channel opened" fi while [ "$( cln_user listpeerchannels "$coord_id" | jq -r '.channels[].state' )" != "CHANNELD_NORMAL" ]; do echo "waiting for channel to be active..." sleep 5 done echo "lightning channel is active" unset coord_port unset coord_id unset coord_node } _robosats_regtest_channel_create_lnd_user() { if [ "$#" -lt 1 ]; then echo "error: insert coordinator node" >&2 return 1 fi coord_node="$1" shift 1 _bitcoin_regtest_check_started || return "$?" case "$coord_node" in cln) if ! _pgrep_cln_coord; then echo "error: cln coordinator not started" >&2 return 1 fi if ! _function_exist cln_coord; then return 1 fi coord_id="$(cln_coord getinfo | jq -r '.id')" coord_port="$CLN_COORD_LISTEN_PORT" ;; lnd) if ! _pgrep_lnd_coord; then echo "error: cln coordinator not started" >&2 return 1 fi if ! _function_exist lnd_coord; then return 1 fi coord_id="$(lnd_coord getinfo | jq -r '.identity_pubkey')" coord_port="$LND_COORD_LISTEN_PORT" ;; *) echo "error: coordinator node can only be cln and lnd" >&2 return 1 ;; esac if ! _pgrep_lnd_user; then echo "error: lnd user not started" >&2 return 1 fi if ! _function_exist lnd_user; then return 1 fi already_connected=false for pub_key in $(lnd_user listpeers | jq -r '.peers[].pub_key'); do if [ "$pub_key" = "$coord_id" ]; then already_connected=true break fi done unset pub_key if [ "$already_connected" = false ]; then if ! lnd_user connect "$coord_id"@localhost:"$coord_port" >/dev/null; then echo "error: connection lightning nodes" >&2 return 1 fi fi unset already_connected echo "lightning nodes connected" # check if channel not already present if [ "$( lnd_user listchannels --peer "$coord_id" | jq -r '.channels | length' )" -ge 1 ]; then echo "lightning nodes already have a channel, not opening a new one" else echo "mining blocks to coordinator $coord_node" _mine_blocks_coordinator "$coord_node" || return "$?" previous_output_number="$(lnd_user listunspent | jq -r '.utxos | length')" if ! user_address="$(lnd_user newaddress p2tr | jq -r '.address')"; then echo "error: generating user address" >&2 return 1 fi echo "mining blocks to user lnd" bitcoin_regtest_mine 101 "$user_address" || return "$?" unset user_address while [ \ "$(lnd_user listunspent | jq -r '.utxos | length')" -le \ "$previous_output_number" \ ]; do echo "waiting for lnd user to see the new blocks..." sleep 5 done while [ "$(lnd_user listunspent | jq -r '.utxos[0].confirmations')" -lt 100 ]; do echo "waiting for lnd user funds to mature..." sleep 1 done unset previous_output_number if ! lnd_user openchannel \ --node_key "$coord_id" \ --local_amt "100000000" \ --sat_per_vbyte "10" \ --min_confs "1" \ --channel_type "anchors" \ >/dev/null then echo "error: funding lightning channel" >&2 return 1 fi echo "lightning channel created" bitcoin_regtest_mine 10 "new" || return "$?" while [ "$( lnd_user listchannels --peer "$coord_id" | jq -r '.channels | length' )" -lt 1 ]; do echo "waiting for channel to confirm..." sleep 1 done echo "lightning channel opened" fi while [ "$( lnd_user listchannels --peer "$coord_id" | jq -r '.channels[].active' )" != true ]; do echo "waiting for channel to be active..." sleep 5 done echo "lightning channel is active" unset coord_port unset coord_id unset coord_node } robosats_regtest_channel_create() { if [ "$#" -lt 1 ]; then echo "error: insert coordinator node" >&2 return 1 fi coord_node="$1" shift 1 if [ "$#" -lt 1 ]; then echo "error: insert user node" >&2 return 1 fi user_node="$1" shift 1 case "$coord_node" in cln|lnd) ;; *) echo "error: $coord_node should be cln or lnd" >&2 return 1 ;; esac case "$user_node" in cln) _robosats_regtest_channel_create_cln_user "$coord_node" ;; lnd) _robosats_regtest_channel_create_lnd_user "$coord_node" ;; *) echo "error: $user_node should be cln or lnd" >&2 return 1 ;; esac unset user_node unset coord_node } roboauto_regtest_setup() { if [ "$ROBOAUTO_GIT_DIR" = false ]; then echo "error: roboauto is disable, set ROBOAUTO_GIT_DIR in .env to activate it" >&2 return 1 fi _command_exist roboauto || return "$?" _create_dir "$ROBOAUTO_DIR" || return "$?" ra_reg() { roboauto \ --config-dir "$REGTEST_NODES_DIR/roboauto" \ --data-dir "$REGTEST_NODES_DIR/roboauto" \ "$@" } echo "writing roboauto regtest config" cat << EOF > "$ROBOAUTO_DIR/config.ini" [federation] exp = None sau = None tos = None tbl = None bve = None loc = "http://127.0.0.1:$RUNSERVER_PORT" EOF case "$LNVENDOR_USER" in cln) roboauto_cln_script="$ROBOAUTO_GIT_DIR/data/lightning-node-core-lightning" if [ ! -f "$roboauto_cln_script" ]; then echo "error: roboauto cln script not found in $ROBOAUTO_GIT_DIR" >&2 return 1 fi search_data=$(cat << EOF lightning-cli "\$@" EOF ) new_data=$(cat << EOF "$LIGHTNING_CLI_BIN" \ --lightning-dir="$CLN_USER_DIR" \ --regtest \ "\$@" EOF ) sed "s|$search_data|$new_data|" \ "$roboauto_cln_script" > "$ROBOAUTO_DIR/lightning-node" || \ return "$?" echo "roboauto cln node script set up" ;; lnd) roboauto_lnd_script="$ROBOAUTO_GIT_DIR/data/lightning-node-lnd" if [ ! -f "$roboauto_lnd_script" ]; then echo "error: roboauto lnd script not found in $ROBOAUTO_GIT_DIR" >&2 return 1 fi search_data=$(cat << EOF lncli "\$@" EOF ) new_data=$(cat << EOF "$LNCLI_BIN" \ --lnddir="$LND_USER_DIR" \ --network regtest \ --rpcserver localhost:"$LND_USER_RPC_PORT" \ "\$@" EOF ) sed "s|$search_data|$new_data|" \ "$roboauto_lnd_script" > "$ROBOAUTO_DIR/lightning-node" || \ return "$?" echo "roboauto lnd node script set up" ;; esac if ! chmod u+x "$ROBOAUTO_DIR/lightning-node"; then echo "error: changing file mode on roboauto lightning-node" >&2 return 1 fi } roboauto_regtest_remove() { if ! rm -rf "$ROBOAUTO_DIR"; then echo "error: removing roboauto directory $ROBOAUTO_DIR" >&2 return 1 fi } robosats_regtest_stop_all() { _lnd_user_stop _lnd_coord_stop _cln_user_stop _cln_coord_stop _bitcoin_regtest_stop } robosats_regtest_stop_and_remove_all() { roboauto_regtest_remove lnd_user_stop_and_remove lnd_coord_stop_and_remove cln_user_stop_and_remove cln_coord_stop_and_remove bitcoin_regtest_stop_and_remove } _node_test_setup() { bitcoin_regtest_start || return "$?" bitcoin_regtest_mine 1 "new" || return "$?" printf "\n" case "$LNVENDOR_COORD" in cln) cln_coord_start || return "$?" ;; lnd) lnd_coord_start || return "$?" ;; esac printf "\n" case "$LNVENDOR_USER" in cln) cln_user_start || return "$?" ;; lnd) lnd_user_start || return "$?" ;; esac } _node_server_setup() { _node_test_setup || return "$?" printf "\n" robosats_regtest_channel_create \ "$LNVENDOR_COORD" "$LNVENDOR_USER" || return "$?" if [ "$ROBOAUTO_GIT_DIR" != false ]; then printf "\n" roboauto_regtest_setup fi } _robosats_regtest_info_print() { cat << EOF regtest nodes directory is $REGTEST_NODES_DIR available command: bitcoin_regtest_start bitcoin_regtest_stop_and_remove bitcoin_regtest_mine number-of-blocks
|new cln_coord_start cln_coord_stop_and_remove cln_user_start cln_user_stop_and_remove lnd_coord_start lnd_coord_stop_and_remove lnd_user_start lnd_user_stop_and_remove roboauto_regtest_setup roboauto_regtest_remove robosats_regtest_stop_all robosats_regtest_stop_and_remove_all robosats_regtest_channel_create cln|lnd cln|lnd EOF } _nodes_main() { _nodes_environment_set || return "$?" # if shell is bash and script is sourced source also bash completions if [ -n "$BASH_VERSION" ]; then case "$0" in /*|./*|../*) ;; *) if [ -f "scripts/traditional/robosats.bash-completion" ]; then # shellcheck disable=SC1091 . scripts/traditional/robosats.bash-completion fi if [ "$ROBOAUTO_GIT_DIR" != false ] && [ -f "$ROBOAUTO_GIT_DIR/completions/roboauto.bash-completion" ] then # shellcheck disable=SC1091 # shellcheck disable=SC3044 . "$ROBOAUTO_GIT_DIR/completions/roboauto.bash-completion" && complete -F __roboauto_completion ra_reg fi ;; esac fi if [ "$#" -lt 1 ]; then _robosats_regtest_info_print || return "$?" else case "$1" in -h|--help) cat << EOF regtest-nodes [server|test] EOF return 0 ;; test) _robosats_regtest_info_print || return "$?" printf "\n" _node_test_setup || return "$?" ;; server) _robosats_regtest_info_print || return "$?" printf "\n" _node_server_setup || return "$?" ;; *) echo "error: action $1 not recognized" >&2 return 1 ;; esac fi } _nodes_main "$@"