diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..411cbdf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,15 @@ +name: ci +on: [push] +jobs: + regtest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run tests + run: | + git clone https://github.com/lnbits/lnbits-legend + cd lnbits-legend + docker build -t lnbits-legend . + cd .. + chmod +x ./tests + ./tests diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c542600 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +data +!data/boltz +data/boltz/* +!data/boltz/boltz.conf +!data/electrs +data/electrs/* +!data/electrs/config.toml diff --git a/README.md b/README.md index 5cd8bcb..1857ba4 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,51 @@ +![TESTS](https://github.com/lnbits/legend-regtest-enviroment/actions/workflows/ci.yml/badge.svg) + # requirements * docker compose v2: https://docs.docker.com/compose/install/compose-plugin/ * jq +* curl -# setup -clone it into your lnbits-legend repository +# testing ```console -mkdir ~/repos/lnbits-legend/docker -git clone git@github.com:lnbits/legend-regtest-enviroment.git ~/repos/lnbits-legend/docker - + chmod +x ./tests + ./tests + # short answer :) + ./tests && echo "PASSED" || echo "FAILED" > /dev/null ``` + +# developement +uncomment following line in docker-compose.yaml, if you wanna use the source code of you current +lnbits-legend repo inside the docker +```yaml +4 volumes: +5 #- ../lnbits:/app/lnbits +``` + # usage +build the lnbits docker image ```console -# build the lnbits docker image +git clone git@github.com:lnbits/lnbits-legend.git ~/repos/lnbits-legend cd ~/repos/lnbits-legend docker build -t lnbits-legend . +``` -# source the scripts +get the regtest enviroment ready +```console +git clone git@github.com:lnbits/legend-regtest-enviroment.git ~/repos/lnbits-legend +mkdir ~/repos/lnbits-legend/docker cd ~/repos/lnbits-legend/docker source docker-scripts.sh - +``` +start the regtest +```console # start docker-compose with logs lnbits-regtest-start-log # start docker-compose in background lnbits-regtest-start +``` -# errors on startup are normal! wait at least 60 seconds -# for all services to come up before you start initializing -sleep 60 - -# initialize blockchain, -# fund lightning wallets -# connect peers -# create channels -# balance channels -lnbits-regtest-init - +usage of the `bitcoin-cli-sim`, `lightning-cli-sim` and `lncli-sim` aliases +```console # use bitcoin core, mine a block bitcoin-cli-sim -generate 1 diff --git a/docker-compose.yml b/docker-compose.yml index 7311fdc..88d0832 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,10 @@ version: "3.7" services: lnbits: hostname: lnbits + depends_on: + - boltz + - mempool-api + - lnd-2 image: lnbits-legend restart: on-failure user: "0:0" @@ -17,12 +21,14 @@ services: ports: - 5000:5000 volumes: - - ../lnbits:/app/lnbits + #- ../lnbits:/app/lnbits - lnbits-data:/app/data - ./data/lnd-2:/app/lnd:uid=1000,gid=1000 boltz: hostname: boltz + depends_on: + - lnd-1 image: boltz/backend entrypoint: "sh -c 'sleep 40; /boltz-backend/bin/boltzd'" ports: @@ -44,6 +50,8 @@ services: clightning-1: hostname: clightning-1 + depends_on: + - bitcoind image: michael1011/cln:latest entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'" expose: @@ -53,6 +61,8 @@ services: clightning-2: hostname: clightning-2 + depends_on: + - bitcoind image: michael1011/cln:latest entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'" expose: @@ -60,15 +70,6 @@ services: volumes: - ./data/clightning-2:/root/.lightning/ - clightning-3: - hostname: clightning-3 - image: michael1011/cln:latest - entrypoint: "sh -c 'sleep 15 && lightningd --network regtest --bind-addr=0.0.0.0:9735 --bitcoin-rpcconnect=bitcoind --bitcoin-rpcport=18443 --bitcoin-rpcuser=lnbits --bitcoin-rpcpassword=lnbits'" - expose: - - 9735 - volumes: - - ./data/clightning-3:/root/.lightnind/ - lnd-1: hostname: lnd-1 depends_on: @@ -117,6 +118,8 @@ services: mempool-web: restart: on-failure + depends_on: + - mempool-api environment: FRONTEND_HTTP_PORT: "8080" BACKEND_MAINNET_HTTP_HOST: "mempool-api" @@ -127,6 +130,7 @@ services: mempool-api: depends_on: - electrs + - mempool-db environment: MEMPOOL_BACKEND: "electrum" ELECTRUM_HOST: electrs diff --git a/docker-scripts.sh b/docker-scripts.sh index a9329a4..d72fd37 100644 --- a/docker-scripts.sh +++ b/docker-scripts.sh @@ -1,7 +1,7 @@ #!/bin/sh export COMPOSE_PROJECT_NAME=lnbits-legend -bitcoin-cli-sim(){ +bitcoin-cli-sim() { docker exec lnbits-legend-bitcoind-1 bitcoin-cli -rpcuser=lnbits -rpcpassword=lnbits -regtest $@ } @@ -36,25 +36,27 @@ fund_lnd_node() { # args(i, j) connect_clightning_node() { pubkey=$(lightning-cli-sim $2 getinfo | jq -r '.id') - lightning-cli-sim $1 connect $pubkey@lnbits-legend-clightning-$2-1 + lightning-cli-sim $1 connect $pubkey@lnbits-legend-clightning-$2-1 | jq -r '.id' } lnbits-regtest-start(){ lnbits-regtest-stop docker compose up -d --remove-orphans + lnbits-regtest-init } lnbits-regtest-start-log(){ lnbits-regtest-stop docker compose up --remove-orphans + lnbits-regtest-init } lnbits-regtest-stop(){ docker compose down --volumes # clean up lightning node data - sudo rm -rf ./data/clightning-1 ./data/clightning-2 ./data/clightning-3 ./data/lnd-1 ./data/lnd-2 ./data/boltz/boltz.db + sudo rm -rf ./data/clightning-1 ./data/clightning-2 ./data/lnd-1 ./data/lnd-2 ./data/boltz/boltz.db # recreate lightning node data folders preventing permission errors - mkdir ./data/clightning-1 ./data/clightning-2 ./data/clightning-3 ./data/lnd-1 ./data/lnd-2 + mkdir ./data/clightning-1 ./data/clightning-2 ./data/lnd-1 ./data/lnd-2 } lnbits-regtest-restart(){ @@ -62,69 +64,101 @@ lnbits-regtest-restart(){ lnbits-regtest-start } -lnbits-regtest-init(){ +lnbits-bitcoin-init(){ echo "init_bitcoin_wallet..." - bitcoin-cli-sim createwallet lnbits || bitcoin-cli-sim loadwallet lnbits echo "mining 150 blocks..." + bitcoin-cli-sim createwallet lnbits || bitcoin-cli-sim loadwallet lnbits + echo "mining 150 blocks..." bitcoin-cli-sim -generate 150 > /dev/null +} + +lnbits-regtest-init(){ + lnbits-bitcoin-init + lnbits-lightning-sync + lnbits-lightning-init + wait-for-lnbits +} + +lnbits-lightning-sync(){ + wait-for-clightning-sync 1 + wait-for-clightning-sync 2 + wait-for-lnd-sync 1 + wait-for-lnd-sync 2 +} + +lnbits-lightning-init(){ # create 10 UTXOs for each node - for i in 0 1 2 3 4 5 6 7 8 9; do + for i in 0 1 2 3 4; do fund_clightning_node 1 fund_clightning_node 2 - fund_clightning_node 3 fund_lnd_node 1 fund_lnd_node 2 done - echo "mining 5 blocks... and waiting for the nodes to catch up" - bitcoin-cli-sim -generate 5 > /dev/null - wait-for-lnd-sync 1 - wait-for-lnd-sync 2 + echo "mining 10 blocks..." + bitcoin-cli-sim -generate 10 > /dev/null + + echo "wait for 15s..." + sleep 15 # else blockheight tests fail for cln + + lnbits-lightning-sync channel_size=16000000 # 0.016 btc - balance_size_msat=7000000000 # 0.07 btc + balance_size=8000000 # 0.08 btc + balance_size_msat=8000000000 # 0.08 btc - # open channels 1 -> 2, 2 -> 3, 3 -> 1 - # TODO: quickfix, https://github.com/lnbits/legend-regtest-enviroment/issues/2 - # connect_clightning_node 1 3 - # lightning-cli-sim 1 fundchannel -k id=$(connect_clightning_node 1 2 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat - # connect_clightning_node 2 1 - # lightning-cli-sim 2 fundchannel -k id=$(connect_clightning_node 2 3 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat - # connect_clightning_node 3 2 - # lightning-cli-sim 3 fundchannel -k id=$(connect_clightning_node 3 1 | jq -r '.id') amount=$channel_size push_msat=$balance_size_msat - # lnd node for boltz - lncli-sim 1 connect $(lightning-cli-sim 1 getinfo | jq -r '.id')@lnbits-legend-clightning-1-1 - lncli-sim 1 openchannel $(lncli-sim 1 listpeers | jq -r '.peers[0].pub_key') $channel_size 8000000 - - # lnd doesnt like more than 1 pending channel? + # lnd-1 -> lnd-2 + lncli-sim 1 connect $(lncli-sim 2 getinfo | jq -r '.identity_pubkey')@lnbits-legend-lnd-2-1 > /dev/null + echo "open channel from lnd-1 to lnd-2" + lncli-sim 1 openchannel $(lncli-sim 2 getinfo | jq -r '.identity_pubkey') $channel_size $balance_size > /dev/null bitcoin-cli-sim -generate 10 > /dev/null - echo "waiting for lnd to catch up..." wait-for-lnd-channel 1 - # fund lnbits lnd channel - lncli-sim 1 connect $(lncli-sim 2 getinfo | jq -r '.identity_pubkey')@lnbits-legend-lnd-2-1 - lncli-sim 1 openchannel $(lncli-sim 1 listpeers | jq -r '.peers[1].pub_key') $channel_size 8000000 - + # lnd-1 -> cln-1 + lncli-sim 1 connect $(lightning-cli-sim 1 getinfo | jq -r '.id')@lnbits-legend-clightning-1-1 > /dev/null + echo "open channel from lnd-1 to cln-1" + lncli-sim 1 openchannel $(lightning-cli-sim 1 getinfo | jq -r '.id') $channel_size $balance_size > /dev/null bitcoin-cli-sim -generate 10 > /dev/null - echo "waiting for lnd to catch up..." wait-for-lnd-channel 1 - - # lnd node for lnbits - lncli-sim 2 connect $(lightning-cli-sim 1 getinfo | jq -r '.id')@lnbits-legend-clightning-1-1 - lncli-sim 2 openchannel $(lncli-sim 2 listpeers | jq -r '.peers[0].pub_key') $channel_size 8000000 - - echo "waiting for lnd to catch up..." + # lnd-2 -> cln-2 + lncli-sim 2 connect $(lightning-cli-sim 2 getinfo | jq -r '.id')@lnbits-legend-clightning-2-1 > /dev/null + echo "open channel from lnd-2 to cln-2" + lncli-sim 2 openchannel $(lightning-cli-sim 2 getinfo | jq -r '.id') $channel_size $balance_size > /dev/null bitcoin-cli-sim -generate 10 > /dev/null wait-for-lnd-channel 2 - # TODO: eclair nodes? + # cln-1 -> cln-2 + peerid=$(connect_clightning_node 1 2) + echo "open channel from cln-1 to cln-2" + lightning-cli-sim 1 fundchannel -k id=$peerid amount=$channel_size push_msat=$balance_size_msat > /dev/null + + bitcoin-cli-sim -generate 10 > /dev/null + + wait-for-clightning-channel 1 + wait-for-clightning-channel 2 + + lnbits-lightning-sync + +} + +wait-for-lnbits(){ + while true; do + statuscode=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:5000") + if [[ "$statuscode" == "200" ]]; then + break + echo "lnbits is online!" + fi + echo "waiting for lnbits to come online..." + sleep 1 + done } wait-for-lnd-channel(){ while true; do pending=$(lncli-sim $1 pendingchannels | jq -r '.pending_open_channels | length') + echo "lnd-$1 pendingchannels: $pending" if [[ "$pending" == "0" ]]; then break fi @@ -134,10 +168,41 @@ wait-for-lnd-channel(){ wait-for-lnd-sync(){ while true; do - if [[ "$(lncli-sim $1 getinfo 2>&1 | jq -r '.synced_to_chain')" == "true" ]]; then + if [[ "$(lncli-sim $1 getinfo 2>&1 | jq -r '.synced_to_chain' 2> /dev/null)" == "true" ]]; then + echo "lnd-$1 is synced!" break fi + echo "waiting for lnd-$1 to sync..." + sleep 1 + done +} + +wait-for-clightning-channel(){ + while true; do + pending=$(lightning-cli-sim $1 getinfo | jq -r '.num_pending_channels | length') + echo "cln-$1 pendingchannels: $pending" + if [[ "$pending" == "0" ]]; then + if [[ "$(lightning-cli-sim $1 getinfo 2>&1 | jq -r '.warning_bitcoind_sync' 2> /dev/null)" == "null" ]]; then + if [[ "$(lightning-cli-sim $1 getinfo 2>&1 | jq -r '.warning_lightningd_sync' 2> /dev/null)" == "null" ]]; then + break + fi + fi + fi + sleep 1 + done +} + +wait-for-clightning-sync(){ + while true; do + if [[ ! "$(lightning-cli-sim $1 getinfo 2>&1 | jq -r '.id' 2> /dev/null)" == "null" ]]; then + if [[ "$(lightning-cli-sim $1 getinfo 2>&1 | jq -r '.warning_bitcoind_sync' 2> /dev/null)" == "null" ]]; then + if [[ "$(lightning-cli-sim $1 getinfo 2>&1 | jq -r '.warning_lightningd_sync' 2> /dev/null)" == "null" ]]; then + echo "cln-$1 is synced!" + break + fi + fi + fi + echo "waiting for cln-$1 to sync..." sleep 1 done - sleep 5 } diff --git a/tests b/tests new file mode 100755 index 0000000..38cb4af --- /dev/null +++ b/tests @@ -0,0 +1,68 @@ +#!/bin/bash +print_success() { + printf "\033[;1;32mPASSED\033[;0m $1\n" +} + +print_error() { + printf "\033[;1;31mFAILED\033[;0m $1\n" +} + +run(){ + label=$1 + value=$2 + cmd=$3 + if [[ "$cmd" == "$value" ]]; then + print_success "$label is $cmd" + else + print_error "$label is $cmd, should be $value" + failed="true" + fi +} + +failed="false" +blockheight=200 +utxos=5 +channel_size=16000000 # 0.016 btc +balance_size=8000000 # 0.08 btc + +source $(pwd)/docker-scripts.sh +lnbits-regtest-start +echo "==================================" +printf "\033[;1;36mregtest started! starting tests...\033[;0m\n" +echo "==================================" +echo "" + +run "boltz service status" "200" $(curl -s -o /dev/null --head -w "%{http_code}" "http://localhost:9001/version") +run "mempool service status" "200" $(curl -s -o /dev/null --head -w "%{http_code}" "http://localhost:8080/") +run "lnbits service status" "200" $(curl -s -o /dev/null -w "%{http_code}" "http://localhost:5000") +for i in 1 2; do + run "lnd-$i .synced_to_chain" "true" $(lncli-sim $i getinfo | jq -r ".synced_to_chain") + run "lnd-$i utxo count" $utxos $(lncli-sim $i listunspent | jq -r ".utxos | length") + run "lnd-$i .block_height" $blockheight $(lncli-sim $i getinfo | jq -r ".block_height") + run "lnd-$i openchannels" 2 $(lncli-sim $i listchannels | jq -r ".channels | length") + run "lnd-$i .channels[0].active_channel" true $(lncli-sim $i listchannels | jq -r ".channels[0].active") + run "lnd-$i .channels[0].capacity" $channel_size $(lncli-sim $i listchannels | jq -r ".channels[0].capacity") + run "lnd-$i .channels[0].push_amount_sat" $balance_size $(lncli-sim $i listchannels | jq -r ".channels[0].push_amount_sat") +done +for i in 1 2; do + run "cln-$i blockheight" $blockheight $(lightning-cli-sim $i getinfo | jq -r ".blockheight") + run "cln-$i utxo count" $utxos $(lightning-cli-sim $i listfunds | jq -r ".outputs | length") + run "cln-$i openchannels" 2 $(lightning-cli-sim $i getinfo | jq -r ".num_active_channels") + run "cln-$i channel[0].state" "CHANNELD_NORMAL" $(lightning-cli-sim $i listfunds | jq -r ".channels[0].state") + run "cln-$i channel[0].channel_total_sat" $channel_size $(lightning-cli-sim $i listfunds | jq -r ".channels[0].channel_total_sat") + run "cln-$i channel[0].channel_sat" $balance_size $(lightning-cli-sim $i listfunds | jq -r ".channels[0].channel_sat") +done + +# return non-zero exit code if a test fails +if [[ "$failed" == "true" ]]; then + echo "" + echo "==================================" + print_error "one more more tests failed" + echo "==================================" + exit 1 +else + echo "" + echo "==================================" + print_success "all tests passed! yay!" + echo "==================================" +fi