diff --git a/.gitignore b/.gitignore index d8a7c692f..9f10b34e1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .vscode dist/** !dist/setup.sh -!dist/sr.sh +!dist/sr.sh \ No newline at end of file diff --git a/api_auth_docker/tests/test-gatekeeper.sh b/api_auth_docker/tests/test-gatekeeper.sh index abb9b1b7e..1c58f45f9 100755 --- a/api_auth_docker/tests/test-gatekeeper.sh +++ b/api_auth_docker/tests/test-gatekeeper.sh @@ -17,7 +17,7 @@ # action_installation_info=stats # action_getmempoolinfo=stats # action_getblockhash=stats -# +# # # Watcher can do what the stats can do, plus: # action_watch=watcher # action_unwatch=watcher @@ -47,7 +47,7 @@ # action_ln_listpays=watcher # action_ln_paystatus=watcher # action_bitcoin_estimatesmartfee=watcher -# +# # # Spender can do what the watcher can do, plus: # action_get_txns_spending=spender # action_getbalance=spender @@ -78,10 +78,10 @@ # action_listbatchers=spender # action_getbatcher=spender # action_getbatchdetails=spender -# +# # # Admin can do what the spender can do, plus: -# -# +# +# # # Should be called from inside the Docker network only: # action_conf=internal # action_newblock=internal @@ -558,7 +558,7 @@ exec_in_test_container_leave_lf apk add --update curl coreutils openssl # Copy keys to test container trace 1 "\n\n[test_gatekeeper] ${BCyan}Copying keys and certs to test container...${Color_Off}\n" -gatekeeperid=$(docker ps -q -f "name=cyphernode_gatekeeper") +gatekeeperid=$(docker ps -q -f "name=cyphernode.gatekeeper") testid=$(docker ps -q -f "name=tests-gatekeeper") docker cp ${gatekeeperid}:/etc/nginx/conf.d/keys.properties - | docker cp - ${testid}:/ docker cp ${gatekeeperid}:/etc/ssl/certs/cert.pem - | docker cp - ${testid}:/ diff --git a/build.sh b/build.sh index ef27e1355..481531d19 100755 --- a/build.sh +++ b/build.sh @@ -2,15 +2,15 @@ TRACING=1 -# CYPHERNODE VERSION "v0.8.0" -CONF_VERSION="v0.8.0-local" -GATEKEEPER_VERSION="v0.8.0-local" -TOR_VERSION="v0.8.0-local" -PROXY_VERSION="v0.8.0-local" -NOTIFIER_VERSION="v0.8.0-local" -PROXYCRON_VERSION="v0.8.0-local" -OTSCLIENT_VERSION="v0.8.0-local" -PYCOIN_VERSION="v0.8.0-local" +# CYPHERNODE VERSION "v0.8.1" +CONF_VERSION="v0.8.1-local" +GATEKEEPER_VERSION="v0.8.1-local" +TOR_VERSION="v0.8.1-local" +PROXY_VERSION="v0.8.1-local" +NOTIFIER_VERSION="v0.8.1-local" +PROXYCRON_VERSION="v0.8.1-local" +OTSCLIENT_VERSION="v0.8.1-local" +PYCOIN_VERSION="v0.8.1-local" trace() { diff --git a/cyphernodeconf_docker/package-lock.json b/cyphernodeconf_docker/package-lock.json index 89048b9c3..9e4b52a6a 100644 --- a/cyphernodeconf_docker/package-lock.json +++ b/cyphernodeconf_docker/package-lock.json @@ -485,11 +485,11 @@ "dev": true }, "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" @@ -873,6 +873,13 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "optional": true + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -1702,9 +1709,9 @@ "dev": true }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.0.0", @@ -1824,6 +1831,16 @@ "map-cache": "^0.2.2" } }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1886,9 +1903,7 @@ }, "chownr": { "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true + "bundled": true }, "code-point-at": { "version": "1.1.0", @@ -1944,8 +1959,6 @@ "fs-minipass": { "version": "1.2.5", "bundled": true, - "dev": true, - "optional": true, "requires": { "minipass": "^2.2.1" } @@ -2026,12 +2039,6 @@ "dev": true, "optional": true }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, @@ -2065,7 +2072,6 @@ "minipass": { "version": "2.3.5", "bundled": true, - "dev": true, "optional": true, "requires": { "safe-buffer": "^5.1.2", @@ -2075,8 +2081,6 @@ "minizlib": { "version": "1.2.1", "bundled": true, - "dev": true, - "optional": true, "requires": { "minipass": "^2.2.1" } @@ -2265,7 +2269,6 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, "optional": true }, "safer-buffer": { @@ -2333,21 +2336,6 @@ "dev": true, "optional": true }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, "util-deprecate": { "version": "1.0.2", "bundled": true, @@ -2372,7 +2360,6 @@ "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, "optional": true } } @@ -2628,6 +2615,13 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "optional": true + }, "inquirer": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", @@ -3729,6 +3723,27 @@ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -5019,6 +5034,48 @@ } } }, + "tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "optional": true + } + } + }, "test-exclude": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", @@ -5251,9 +5308,9 @@ } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } @@ -5457,6 +5514,13 @@ "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", "dev": true }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "optional": true + }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", diff --git a/cyphernodeconf_docker/package.json b/cyphernodeconf_docker/package.json index 992bfea75..382b2a017 100644 --- a/cyphernodeconf_docker/package.json +++ b/cyphernodeconf_docker/package.json @@ -16,7 +16,7 @@ ], "dependencies": { "@rauschma/stringio": "^1.4.0", - "ajv": "^6.10.0", + "ajv": "^6.12.3", "chalk": "^2.4.2", "coinstring": "^2.3.0", "colorsys": "^1.0.22", diff --git a/cyphernodeconf_docker/prompters/800_proxycron.js b/cyphernodeconf_docker/prompters/800_proxycron.js new file mode 100644 index 000000000..017d7b1d9 --- /dev/null +++ b/cyphernodeconf_docker/prompters/800_proxycron.js @@ -0,0 +1,15 @@ +const chalk = require('chalk'); + +const name = 'proxycron'; + +module.exports = { + name: function() { + return name; + }, + prompts: function( utils ) { + return []; + }, + templates: function( props ) { + return [ 'proxycron.env' ]; + } +}; \ No newline at end of file diff --git a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml index 6250e3260..120026408 100644 --- a/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml +++ b/cyphernodeconf_docker/templates/installer/docker/docker-compose.yaml @@ -245,9 +245,8 @@ services: proxycron: image: cyphernode/proxycron:<%= proxycron_version %> - environment: - - "TX_CONF_URL=proxy:8888/executecallbacks" - - "OTS_URL=proxy:8888/ots_backoffice" + env_file: + - .env/proxycron.env networks: - cyphernodenet depends_on: diff --git a/cyphernodeconf_docker/templates/installer/start.sh b/cyphernodeconf_docker/templates/installer/start.sh index 647cab43f..2d8502d95 100644 --- a/cyphernodeconf_docker/templates/installer/start.sh +++ b/cyphernodeconf_docker/templates/installer/start.sh @@ -1,6 +1,8 @@ #!/bin/bash -. ./.cyphernodeconf/installer/config.sh +current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)" + +. ${current_path}/.cyphernodeconf/installer/config.sh # be aware that randomly downloaded cyphernode apps will have access to # your configuration and filesystem. @@ -14,7 +16,7 @@ start_apps() { local APP_START_SCRIPT_PATH local APP_ID - for i in $current_path/apps/* + for i in ${current_path}/apps/* do APP_SCRIPT_PATH=$(echo $i) if [ -d "$APP_SCRIPT_PATH" ] && [ ! -f "$APP_SCRIPT_PATH/ignoreThisApp" ]; then @@ -39,7 +41,7 @@ start_apps() { if [ "$DOCKER_MODE" = "swarm" ]; then docker stack deploy -c $APP_SCRIPT_PATH/docker-compose.yaml $APP_ID elif [ "$DOCKER_MODE" = "compose" ]; then - docker-compose -f $APP_SCRIPT_PATH/docker-compose.yaml up -d --remove-orphans + docker-compose -p $APP_ID -f $APP_SCRIPT_PATH/docker-compose.yaml up -d --remove-orphans fi fi fi @@ -58,15 +60,13 @@ fi export USER=$(id -u <%= default_username %>):$(id -g <%= default_username %>) <% } %> -current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)" - # Let's make sure the container readyness files are deleted before starting the stack docker run --rm -v cyphernode_container_monitor:/container_monitor alpine sh -c 'rm -f /container_monitor/*_ready' <% if (docker_mode == 'swarm') { %> docker stack deploy -c $current_path/docker-compose.yaml cyphernode <% } else if(docker_mode == 'compose') { %> -docker-compose -f $current_path/docker-compose.yaml up -d --remove-orphans +docker-compose -p cyphernode -f $current_path/docker-compose.yaml up -d --remove-orphans <% } %> start_apps @@ -80,4 +80,4 @@ else printf " It's pretty fast!\r\n" fi -. ./testdeployment.sh +. ${current_path}/testdeployment.sh diff --git a/cyphernodeconf_docker/templates/installer/stop.sh b/cyphernodeconf_docker/templates/installer/stop.sh index 6096e5760..a3dee20da 100644 --- a/cyphernodeconf_docker/templates/installer/stop.sh +++ b/cyphernodeconf_docker/templates/installer/stop.sh @@ -2,7 +2,6 @@ current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)" - # be aware that randomly downloaded cyphernode apps will have access to # your configuration and filesystem. # !!!!!!!!! DO NOT INCLUDE APPS WITHOUT REVIEW !!!!!!!!!! @@ -15,7 +14,7 @@ stop_apps() { local APP_START_SCRIPT_PATH local APP_ID - for i in $current_path/apps/* + for i in ${current_path}/apps/* do APP_SCRIPT_PATH=$(echo $i) if [ -d "$APP_SCRIPT_PATH" ] && [ ! -f "$APP_SCRIPT_PATH/ignoreThisApp" ]; then @@ -38,7 +37,7 @@ stop_apps() { if [ "$DOCKER_MODE" = "swarm" ]; then docker stack rm $APP_ID elif [ "$DOCKER_MODE" = "compose" ]; then - docker-compose -f $APP_SCRIPT_PATH/docker-compose.yaml down + docker-compose -p $APP_ID -f $APP_SCRIPT_PATH/docker-compose.yaml down fi fi @@ -46,7 +45,7 @@ stop_apps() { done } -. ./.cyphernodeconf/installer/config.sh +. ${current_path}/.cyphernodeconf/installer/config.sh stop_apps export USER=$(id -u):$(id -g) @@ -54,5 +53,5 @@ export USER=$(id -u):$(id -g) <% if (docker_mode == 'swarm') { %> docker stack rm cyphernode <% } else if(docker_mode == 'compose') { %> -docker-compose -f $current_path/docker-compose.yaml down +docker-compose -p cyphernode -f ${current_path}/docker-compose.yaml down <% } %> diff --git a/cyphernodeconf_docker/templates/installer/testdeployment.sh b/cyphernodeconf_docker/templates/installer/testdeployment.sh index 2cfa327d0..60755d217 100644 --- a/cyphernodeconf_docker/templates/installer/testdeployment.sh +++ b/cyphernodeconf_docker/templates/installer/testdeployment.sh @@ -1,6 +1,8 @@ #!/bin/bash -. ./.cyphernodeconf/installer/config.sh +current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)" + +. ${current_path}/.cyphernodeconf/installer/config.sh # be aware that randomly downloaded cyphernode apps will have access to # your configuration and filesystem. @@ -17,7 +19,7 @@ test_apps() { local TRAEFIK_HTTP_PORT=<%= traefik_http_port %> local TRAEFIK_HTTPS_PORT=<%= traefik_https_port %> - for i in $current_path/apps/* + for i in ${current_path}/apps/* do APP_SCRIPT_PATH=$(echo $i) if [ -d "$APP_SCRIPT_PATH" ]; then @@ -37,7 +39,7 @@ test_apps() { fi fi done - return $returncode + return ${returncode} } <% if (run_as_different_user) { %> @@ -51,8 +53,6 @@ fi export USER=$(id -u <%= default_username %>):$(id -g <%= default_username %>) <% } %> -current_path="$(cd "$(dirname "$0")" >/dev/null && pwd)" - # Will test if Cyphernode is fully up and running... docker run --rm -it -v $current_path/testfeatures.sh:/testfeatures.sh \ -v <%= gatekeeper_datapath %>:/gatekeeper \ @@ -60,9 +60,9 @@ docker run --rm -it -v $current_path/testfeatures.sh:/testfeatures.sh \ -v cyphernode_container_monitor:/container_monitor:ro \ --network cyphernodenet eclipse-mosquitto:<%= mosquitto_version %> /testfeatures.sh -if [ -f $current_path/exitStatus.sh ]; then - . $current_path/exitStatus.sh - rm -f $current_path/exitStatus.sh +if [ -f ${current_path}/exitStatus.sh ]; then + . ${current_path}/exitStatus.sh + rm -f ${current_path}/exitStatus.sh fi if [ "$EXIT_STATUS" -ne "0" ]; then diff --git a/cyphernodeconf_docker/templates/installer/testfeatures.sh b/cyphernodeconf_docker/templates/installer/testfeatures.sh index 6a2b045db..0c516b29a 100644 --- a/cyphernodeconf_docker/templates/installer/testfeatures.sh +++ b/cyphernodeconf_docker/templates/installer/testfeatures.sh @@ -84,7 +84,7 @@ checkpostgres() { echo -en "\r\n\e[1;36mTesting Postgres... " > /dev/console local rc - pg_isready -h postgres -U cyphernode + pg_isready -h postgres -U cyphernode > /dev/null [ "${?}" -ne "0" ] && return 105 echo -e "\e[1;36mPostgres rocks!" > /dev/console @@ -109,7 +109,7 @@ checknotifier() { local response local returncode - nc -vlp1111 -e sh -c 'echo -en "HTTP/1.1 200 OK\\r\\n\\r\\n" ; date >&2 ; timeout 1 tee /dev/tty | cat ; ' & + nc -lp1111 -e sh -c 'echo -en "HTTP/1.1 200 OK\\r\\n\\r\\n" ; timeout 1 tee /dev/null ;' > /dev/null & response=$(mosquitto_rr -h broker -W 15 -t notifier -e "response/$$" -m "{\"response-topic\":\"response/$$\",\"cmd\":\"web\",\"url\":\"http://$(hostname):1111/notifiertest\",\"tor\":false}") returncode=$? [ "${returncode}" -ne "0" ] && return 115 diff --git a/cyphernodeconf_docker/templates/proxycron/proxycron.env b/cyphernodeconf_docker/templates/proxycron/proxycron.env new file mode 100644 index 000000000..4d5497e3a --- /dev/null +++ b/cyphernodeconf_docker/templates/proxycron/proxycron.env @@ -0,0 +1,2 @@ +TX_CONF_URL=proxy:8888/executecallbacks +OTS_URL=proxy:8888/ots_backoffice \ No newline at end of file diff --git a/dist/setup.sh b/dist/setup.sh index 91e204359..0813e3aa6 100755 --- a/dist/setup.sh +++ b/dist/setup.sh @@ -139,7 +139,7 @@ modify_permissions() { } modify_owner() { - local directories=("$BITCOIN_DATAPATH" "$LIGHTNING_DATAPATH" "$PROXY_DATAPATH" "$GATEKEEPER_DATAPATH" "$OTSCLIENT_DATAPATH" "$POSTGRES_DATAPATH" "$LOGS_DATAPATH" "$TRAEFIK_DATAPATH" "$TOR_DATAPATH") + local directories=("${current_path}/.env" "$BITCOIN_DATAPATH" "$LIGHTNING_DATAPATH" "$PROXY_DATAPATH" "$GATEKEEPER_DATAPATH" "$OTSCLIENT_DATAPATH" "$POSTGRES_DATAPATH" "$LOGS_DATAPATH" "$TRAEFIK_DATAPATH" "$TOR_DATAPATH") local user=$(id -u $RUN_AS_USER):$(id -g $RUN_AS_USER) for d in "${directories[@]}" do @@ -474,10 +474,17 @@ install_docker() { next fi + if [ ! -d $current_path/.env ]; then + step " create ${current_path}/.env" + sudo_if_required mkdir -p ${current_path}/.env + next + fi + copy_file $cyphernodeconf_filepath/installer/config.sh $PROXY_DATAPATH/config.sh 1 $SUDO_REQUIRED copy_file $cyphernodeconf_filepath/cyphernode/info.json $PROXY_DATAPATH/info.json 1 $SUDO_REQUIRED copy_file $cyphernodeconf_filepath/postgres/pgpass $PROXY_DATAPATH/pgpass 1 $SUDO_REQUIRED sudo_if_required chmod 0600 $PROXY_DATAPATH/pgpass + copy_file $cyphernodeconf_filepath/proxycron/proxycron.env ${current_path}/.env/proxycron.env 1 $SUDO_REQUIRED if [[ $BITCOIN_INTERNAL == true ]]; then if [ ! -d $BITCOIN_DATAPATH ]; then @@ -669,7 +676,7 @@ install_docker() { check_directory_owner() { # if one directory does not have access rights for $RUN_AS_USER, we echo 1, else we echo 0 - local directories=("$BITCOIN_DATAPATH" "$LIGHTNING_DATAPATH" "$PROXY_DATAPATH" "$GATEKEEPER_DATAPATH" "$POSTGRES_DATAPATH" "$LOGS_DATAPATH" "$TRAEFIK_DATAPATH" "$TOR_DATAPATH") + local directories=("${current_path}/.env" "$BITCOIN_DATAPATH" "$LIGHTNING_DATAPATH" "$PROXY_DATAPATH" "$GATEKEEPER_DATAPATH" "$POSTGRES_DATAPATH" "$LOGS_DATAPATH" "$TRAEFIK_DATAPATH" "$TOR_DATAPATH") local status=0 for d in "${directories[@]}" do @@ -859,17 +866,17 @@ ALWAYSYES=0 SUDO_REQUIRED=0 AUTOSTART=0 -# CYPHERNODE VERSION "v0.8.0" -SETUP_VERSION="v0.8.0" -CONF_VERSION="v0.8.0" -GATEKEEPER_VERSION="v0.8.0" -TOR_VERSION="v0.8.0" -PROXY_VERSION="v0.8.0" -NOTIFIER_VERSION="v0.8.0" -PROXYCRON_VERSION="v0.8.0" -OTSCLIENT_VERSION="v0.8.0" -PYCOIN_VERSION="v0.8.0" -CYPHERAPPS_VERSION="v0.8.0" +# CYPHERNODE VERSION "v0.8.1" +SETUP_VERSION="v0.8.1" +CONF_VERSION="v0.8.1" +GATEKEEPER_VERSION="v0.8.1" +TOR_VERSION="v0.8.1" +PROXY_VERSION="v0.8.1" +NOTIFIER_VERSION="v0.8.1" +PROXYCRON_VERSION="v0.8.1" +OTSCLIENT_VERSION="v0.8.1" +PYCOIN_VERSION="v0.8.1" +CYPHERAPPS_VERSION="v0.8.1" BITCOIN_VERSION="v22.0" LIGHTNING_VERSION="v0.10.2" TRAEFIK_VERSION="v1.7.9-alpine" diff --git a/doc/release-notes/release-notes-v0.8.1.md b/doc/release-notes/release-notes-v0.8.1.md new file mode 100644 index 000000000..91a537985 --- /dev/null +++ b/doc/release-notes/release-notes-v0.8.1.md @@ -0,0 +1,9 @@ +# Cyphernode v0.8.1 + +This is a minor release of a few fixes and improvements: + +- Fixed: full compatibility with docker-compose was lost in v0.8.0 (thanks @bhodl) +- Improved: `ln_pay` now pays using the pay plugin first (with MPP), then `legacypay` on failure +- Improved: moved env variables from docker-compose.yaml to env files, for proxycron only for now (thanks @phillamy) +- Small improvements in the startup scripts +- Removed inserting previous txs in database when computing a tx fees diff --git a/docker-build.sh b/docker-build.sh index 4431aeb41..f5e1800ed 100755 --- a/docker-build.sh +++ b/docker-build.sh @@ -61,7 +61,7 @@ aarch64_docker="arm64" v1="v0" v2="v0.8" -v3="v0.8.0" +v3="v0.8.1" # Build amd64 and arm64 first, building for arm will trigger the manifest creation and push on hub diff --git a/proxy_docker/app/script/call_lightningd.sh b/proxy_docker/app/script/call_lightningd.sh index 4754d7d2f..e1e223201 100644 --- a/proxy_docker/app/script/call_lightningd.sh +++ b/proxy_docker/app/script/call_lightningd.sh @@ -303,8 +303,8 @@ ln_connectfund() { ln_pay() { trace "Entering ln_pay()..." - # Let's try to legacypay (MPP disabled) for 30 seconds. - # If this doesn't work for a routing reason, let's try to pay (MPP enabled) for 30 seconds. + # Let's try to pay (MPP enabled) for 85 seconds. + # If this doesn't work for a routing reason, let's try to legacypay (MPP disabled) for 85 seconds. # If this doesn't work, return an error. local result @@ -347,14 +347,39 @@ ln_pay() { trace "[ln_pay] Expected description <> Invoice description" returncode=1 else - # Amount and description are as expected (or empty description), let's pay! - trace "[ln_pay] Amount and description are as expected, let's try to pay without MPP!" + # Amount and description are as expected (or empty description), let's see if already paid + trace "[ln_pay] Amount and description are as expected, let's see if already paid" + result=$(ln_listpays "${bolt11}") + returncode=$? + trace_rc ${returncode} + trace "[ln_pay] result=${result}" + local complete pending failed + complete=$(echo "${result}" | jq -er '.pays | map(select(.status == "complete")) | last') + trace "[ln_pay] complete=${complete}" + pending=$(echo "${result}" | jq -er '.pays | map(select(.status == "pending")) | last') + trace "[ln_pay] pending=${pending}" + failed=$(echo "${result}" | jq -er '.pays | map(select(.status == "failed")) | last') + trace "[ln_pay] failed=${failed}" + + if [ "${complete}" != "null" ]; then + trace "[ln_pay] responding complete" + echo "${complete}" + return 0 + fi + if [ "${pending}" != "null" ]; then + trace "[ln_pay] responding pending" + echo "${pending}" + return 1 + fi + + # Payment not previously done, let's pay! + trace "[ln_pay] Payment not previously done, let's try to pay with MPP!" if [ "${invoice_msatoshi}" = "null" ]; then # "any" amount on the invoice, we force paying the expected_msatoshi provided to ln_pay by the user - result=$(ln_call_lightningd legacypay -k bolt11=${bolt11} msatoshi=${expected_msatoshi} retry_for=30) + result=$(ln_call_lightningd pay -k bolt11=${bolt11} msatoshi=${expected_msatoshi} retry_for=85) else - result=$(ln_call_lightningd legacypay -k bolt11=${bolt11} retry_for=30) + result=$(ln_call_lightningd pay -k bolt11=${bolt11} retry_for=85) fi returncode=$? trace_rc ${returncode} @@ -363,34 +388,31 @@ ln_pay() { # Successful payment example: # # { - # "id": 16, - # "payment_hash": "f00877afeec4d771c2db68af80b8afa5dad3b495dad498828327e484c93f67d5", - # "destination": "021ec6ccede19caa0bc7d7f9699c73e63cb2b79a4877529a60d7ac6a4ebb03487a", - # "msatoshi": 1234, - # "amount_msat": "1234msat", - # "msatoshi_sent": 1235, - # "amount_sent_msat": "1235msat", - # "created_at": 1633373202, - # "status": "complete", - # "payment_preimage": "373cd9a0f83426506f1535f6ca1f08f279f0bd82d257fd3fc8cd49fbc25750f2", - # "bolt11": "lntb1ps4kjlrpp57qy80tlwcnthrskmdzhcpw905hdd8dy4mt2f3q5ryljgfjflvl2sdq9u2d2zxqr3jscqp2sp5c2qykk0pdaeh2yrvn4cpkchsnyxwjnaptujggsd6ldqjfd8jhh3qrzjqwyx8nu2hygyvgc02cwdtvuxe0lcxz06qt3lpsldzcdr46my5epmj85hhvqqqtsqqqqqqqlgqqqqqqgq9q9qyyssqpnwtw6mzxu8pr5mrm8677ke8p5fjcu6dyrrvuy8j5f5p8mzv2phr2y0yx3z7mvgf5uqzzdytegg04u7hcu8ma50692cg69cdtsgw9hsph0xeha" + # "destination": "029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb", + # "payment_hash": "0d1e62210e7af9a4146258652fd4cfecd2638086850583e994a103884e2b4e78", + # "created_at": 1631200188.550, + # "parts": 1, + # "msatoshi": 530114, + # "amount_msat": "530114msat", + # "msatoshi_sent": 530114, + # "amount_sent_msat": "530114msat", + # "payment_preimage": "2672c5fa280367222bf30db82566b78909927a67d5756d5ae0227b2ff8f3a907", + # "status": "complete" # } - - # Failure response examples: # - # { - # "code": -32602, - # "message": "03c05f973d9c7218e7aec4f52c2c8ab395f51f41d627c398237b5ff056f46faf09: unknown destination node_id (no public channels?)" - # } # + # Failed payment example: # { - # "code": 206, - # "message": "Route wanted fee of 16101625msat" - # } - # - # { - # "code": 207, - # "message": "Invoice expired" + # "code": 210, + # "message": "Destination 029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb is not reachable directly and all routehints were unusable.", + # "attempts": [ + # { + # "status": "failed", + # "failreason": "Destination 029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb is not reachable directly and all routehints were unusable.", + # "partid": 0, + # "amount": "528214msat" + # } + # ] # } # @@ -413,18 +435,20 @@ ln_pay() { # Let's try pay if code NOT 207 or 201. - if [ "${code}" -eq "201" ] || [ "${code}" -eq "207" ] || [ "${code}" -lt "0" ]; then + if [ "${code}" -eq "201" ] || [ "${code}" -eq "207" ]; then trace "[ln_pay] Failure code, response will be the cli result." else - trace "[ln_pay] Ok let's deal with potential routing failures and retry with MPP..." + trace "[ln_pay] Ok let's deal with potential routing failures and retry without MPP..." if [ "${invoice_msatoshi}" = "null" ]; then # "any" amount on the invoice, we force paying the expected_msatoshi provided to ln_pay by the user - result=$(ln_call_lightningd pay -k bolt11=${bolt11} msatoshi=${expected_msatoshi} retry_for=30) + result=$(ln_call_lightningd legacypay -k bolt11=${bolt11} msatoshi=${expected_msatoshi} retry_for=85) else - result=$(ln_call_lightningd pay -k bolt11=${bolt11} retry_for=30) + result=$(ln_call_lightningd legacypay -k bolt11=${bolt11} retry_for=85) fi returncode=$? + trace_rc ${returncode} + trace "[ln_pay] result=${result}" if [ "${returncode}" -ne "0" ]; then trace "[ln_pay] Failed!" @@ -435,34 +459,36 @@ ln_pay() { # Successful payment example: # # { - # "destination": "029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb", - # "payment_hash": "0d1e62210e7af9a4146258652fd4cfecd2638086850583e994a103884e2b4e78", - # "created_at": 1631200188.550, - # "parts": 1, - # "msatoshi": 530114, - # "amount_msat": "530114msat", - # "msatoshi_sent": 530114, - # "amount_sent_msat": "530114msat", - # "payment_preimage": "2672c5fa280367222bf30db82566b78909927a67d5756d5ae0227b2ff8f3a907", - # "status": "complete" + # "id": 16, + # "payment_hash": "f00877afeec4d771c2db68af80b8afa5dad3b495dad498828327e484c93f67d5", + # "destination": "021ec6ccede19caa0bc7d7f9699c73e63cb2b79a4877529a60d7ac6a4ebb03487a", + # "msatoshi": 1234, + # "amount_msat": "1234msat", + # "msatoshi_sent": 1235, + # "amount_sent_msat": "1235msat", + # "created_at": 1633373202, + # "status": "complete", + # "payment_preimage": "373cd9a0f83426506f1535f6ca1f08f279f0bd82d257fd3fc8cd49fbc25750f2", + # "bolt11": "lntb1ps4kjlrpp57qy80tlwcnthrskmdzhcpw905hdd8dy4mt2f3q5ryljgfjflvl2sdq9u2d2zxqr3jscqp2sp5c2qykk0pdaeh2yrvn4cpkchsnyxwjnaptujggsd6ldqjfd8jhh3qrzjqwyx8nu2hygyvgc02cwdtvuxe0lcxz06qt3lpsldzcdr46my5epmj85hhvqqqtsqqqqqqqlgqqqqqqgq9q9qyyssqpnwtw6mzxu8pr5mrm8677ke8p5fjcu6dyrrvuy8j5f5p8mzv2phr2y0yx3z7mvgf5uqzzdytegg04u7hcu8ma50692cg69cdtsgw9hsph0xeha" # } + + # Failure response examples: # + # { + # "code": -32602, + # "message": "03c05f973d9c7218e7aec4f52c2c8ab395f51f41d627c398237b5ff056f46faf09: unknown destination node_id (no public channels?)" + # } # - # Failed payment example: # { - # "code": 210, - # "message": "Destination 029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb is not reachable directly and all routehints were unusable.", - # "attempts": [ - # { - # "status": "failed", - # "failreason": "Destination 029b26c73b2c19ec9bdddeeec97c313670c96b6414ceacae0fb1b3502e490a6cbb is not reachable directly and all routehints were unusable.", - # "partid": 0, - # "amount": "528214msat" - # } - # ] + # "code": 206, + # "message": "Route wanted fee of 16101625msat" + # } + # + # { + # "code": 207, + # "message": "Invoice expired" # } # - fi else # code tag not found diff --git a/proxy_docker/app/script/computefees.sh b/proxy_docker/app/script/computefees.sh index 4f57874d0..082605ed1 100644 --- a/proxy_docker/app/script/computefees.sh +++ b/proxy_docker/app/script/computefees.sh @@ -52,14 +52,6 @@ compute_vin_total_amount() local vin_vout_amount=0 local vout local vin_total_amount=0 - local vin_hash - local vin_confirmations - local vin_timereceived - local vin_vsize - local vin_blockhash - local vin_blockheight - local vin_blocktime - local txid_already_inserted=true for vin_txid_vout in ${vin_txids_vout} do @@ -75,21 +67,6 @@ compute_vin_total_amount() trace "[compute_vin_total_amount] vin_vout_amount=${vin_vout_amount}" vin_total_amount=$(awk "BEGIN { printf(\"%.8f\", ${vin_total_amount}+${vin_vout_amount}); exit}") trace "[compute_vin_total_amount] vin_total_amount=${vin_total_amount}" - vin_hash=$(echo "${vin_raw_tx}" | jq -r ".result.hash") - vin_confirmations=$(echo "${vin_raw_tx}" | jq ".result.confirmations") - vin_timereceived=$(echo "${vin_raw_tx}" | jq ".result.time") - vin_size=$(echo "${vin_raw_tx}" | jq ".result.size") - vin_vsize=$(echo "${vin_raw_tx}" | jq ".result.vsize") - vin_blockhash=$(echo "${vin_raw_tx}" | jq -r ".result.blockhash") - vin_blockheight=$(echo "${vin_raw_tx}" | jq ".result.blockheight") - vin_blocktime=$(echo "${vin_raw_tx}" | jq ".result.blocktime") - - # Let's insert the vin tx in the DB just in case it would be useful - sql "INSERT INTO tx (txid, hash, confirmations, timereceived, size, vsize, blockhash, blockheight, blocktime)"\ -" VALUES ('${vin_txid}', '${vin_hash}', ${vin_confirmations}, ${vin_timereceived}, ${vin_size}, ${vin_vsize}, '${vin_blockhash}', ${vin_blockheight}, ${vin_blocktime})"\ -" ON CONFLICT (txid) DO"\ -" UPDATE SET blockhash='${vin_blockhash}', blockheight=${vin_blockheight}, blocktime=${vin_blocktime}, confirmations=${vin_confirmations}" - trace_rc $? done echo "${vin_total_amount}" diff --git a/proxy_docker/app/tests/mine.sh b/proxy_docker/app/tests/mine.sh index 90991dec4..1abfebddf 100755 --- a/proxy_docker/app/tests/mine.sh +++ b/proxy_docker/app/tests/mine.sh @@ -10,9 +10,9 @@ mine() { local minedaddr echo ; echo "About to mine ${nbblocks} block(s)..." - minedaddr=$(docker exec -t $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat getnewaddress | tr -d '\r') + minedaddr=$(docker exec -t $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat getnewaddress | tr -d '\r') echo ; echo "minedaddr=${minedaddr}" - docker exec -t $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat generatetoaddress ${nbblocks} "${minedaddr}" + docker exec -t $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat generatetoaddress ${nbblocks} "${minedaddr}" } case "${0}" in *mine.sh) mine $@;; esac diff --git a/proxy_docker/app/tests/test-manage-missed.sh b/proxy_docker/app/tests/test-manage-missed.sh index a1ed886ad..56292d903 100755 --- a/proxy_docker/app/tests/test-manage-missed.sh +++ b/proxy_docker/app/tests/test-manage-missed.sh @@ -73,10 +73,12 @@ test_manage_missed_0_conf() { trace 3 "[test_manage_missed_0_conf] response=${response}" trace 3 "[test_manage_missed_0_conf] Shutting down the proxy..." - docker stop $(docker ps -q -f "name=proxy\.") + # There are two container names containing "proxy": proxy and proxycron + # Let's exclude proxycron + docker restart $(docker ps -q -f "name=proxy[^c]") trace 3 "[test_manage_missed_0_conf] Sending coins to watched address while proxy is down..." - docker exec -it $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address} 0.0001 + docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address} 0.0001 # txid1=$(exec_in_test_container curl -d '{"address":"'${address}'","amount":0.0001}' proxy:8888/spend | jq -r ".txid") wait_for_proxy @@ -113,14 +115,16 @@ test_manage_missed_1_conf() { trace 3 "[test_manage_missed_1_conf] response=${response}" trace 3 "[test_manage_missed_1_conf] Sending coins to watched address while proxy is up..." - docker exec -it $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address} 0.0001 + docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address} 0.0001 # txid1=$(exec_in_test_container curl -d '{"address":"'${address}'","amount":0.0001}' proxy:8888/spend | jq -r ".txid") trace 3 "[test_manage_missed_1_conf] Sleeping for 20 seconds to let the 0-conf callbacks to happen..." sleep 20 trace 3 "[test_manage_missed_1_conf] Shutting down the proxy..." - docker stop $(docker ps -q -f "name=proxy\.") + # There are two container names containing "proxy": proxy and proxycron + # Let's exclude proxycron + docker restart $(docker ps -q -f "name=proxy[^c]") trace 3 "[test_manage_missed_1_conf] Mine a new block..." mine diff --git a/proxy_docker/app/tests/test-watches.sh b/proxy_docker/app/tests/test-watches.sh index db32da9fb..5e6993e29 100755 --- a/proxy_docker/app/tests/test-watches.sh +++ b/proxy_docker/app/tests/test-watches.sh @@ -176,7 +176,7 @@ test_watches() { trace 2 "\n\n[test_watches] ${BCyan}10. Send coins to address1...${Color_Off}\n" start_callback_server 1111 # Let's use the bitcoin node directly to better simulate an external spend - txid=$(docker exec -it $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address1} 0.0001 | tr -d "\r\n") + txid=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address1} 0.0001 | tr -d "\r\n") # txid=$(exec_in_test_container curl -d '{"address":"'${address1}'","amount":0.001}' proxy:8888/spend | jq -r ".txid") trace 3 "[test_watches] txid=${txid}" trace 3 "[test_watches] Waiting for 0-conf callback on address1..." diff --git a/proxy_docker/app/tests/test-watchpub32.sh b/proxy_docker/app/tests/test-watchpub32.sh index b9a7e17be..f98bcfec2 100755 --- a/proxy_docker/app/tests/test-watchpub32.sh +++ b/proxy_docker/app/tests/test-watchpub32.sh @@ -272,7 +272,7 @@ test_watch_pub32() { trace 2 "\n\n[test_watch_pub32] ${BCyan}12. Send coins to address1...${Color_Off}\n" start_callback_server 1111 # Let's use the bitcoin node directly to better simulate an external spend - txid1=$(docker exec -it $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address1} 0.0001 | tr -d "\r\n") + txid1=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address1} 0.0001 | tr -d "\r\n") # txid1=$(exec_in_test_container curl -d '{"address":"'${address1}'","amount":0.001}' proxy:8888/spend | jq -r ".txid") trace 3 "[test_watch_pub32] txid1=${txid1}" trace 3 "[test_watch_pub32] Waiting for 0-conf callback on address1..." @@ -282,7 +282,7 @@ test_watch_pub32() { trace 2 "\n\n[test_watch_pub32] ${BCyan}13. Send coins to address2...${Color_Off}\n" start_callback_server 1113 # Let's use the bitcoin node directly to better simulate an external spend - txid2=$(docker exec -it $(docker ps -q -f "name=cyphernode_bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address2} 0.0001 | tr -d "\r\n") + txid2=$(docker exec -it $(docker ps -q -f "name=cyphernode.bitcoin") bitcoin-cli -rpcwallet=spending01.dat sendtoaddress ${address2} 0.0001 | tr -d "\r\n") # txid2=$(exec_in_test_container curl -d '{"address":"'${address2}'","amount":0.001}' proxy:8888/spend | jq -r ".txid") trace 3 "[test_watch_pub32] txid2=${txid2}" trace 3 "[test_watch_pub32] Waiting for 0-conf callback on address2..."