105 lines
3.9 KiB
Plaintext
105 lines
3.9 KiB
Plaintext
|
|
#!/usr/bin/env bats
|
||
|
|
# tests/lifecycle/bats/bitcoin-receive.bats
|
||
|
|
#
|
||
|
|
# Regression coverage for the Bitcoin "Receive" flow. Receive addresses come
|
||
|
|
# from LND's hot wallet via the `lnd.newaddress` RPC, so this exercises the
|
||
|
|
# exact path that broke on the fleet:
|
||
|
|
# - .116: LND REST published on the wrong host port (8080 vs the manifest's
|
||
|
|
# 18080) -> connection refused -> receive failed with the generic
|
||
|
|
# "Operation failed. Check server logs." message.
|
||
|
|
# - .228: the same family surfaced to the UI as a *false* "wallet is locked".
|
||
|
|
#
|
||
|
|
# These tests run on the archy host (they shell into podman / curl localhost).
|
||
|
|
#
|
||
|
|
# Tiers: read-only only — generating a receive address is non-destructive.
|
||
|
|
|
||
|
|
load '../lib/rpc.bash'
|
||
|
|
|
||
|
|
setup_file() {
|
||
|
|
: "${ARCHY_PASSWORD:?Set ARCHY_PASSWORD env var to the UI password}"
|
||
|
|
export ARCHY_FORCE_LOGIN=1
|
||
|
|
rpc_login
|
||
|
|
unset ARCHY_FORCE_LOGIN
|
||
|
|
}
|
||
|
|
|
||
|
|
teardown_file() {
|
||
|
|
rpc_logout_local
|
||
|
|
}
|
||
|
|
|
||
|
|
# Resolve the LND REST host port from the manifest (single source of truth) so
|
||
|
|
# this test follows the manifest rather than hard-coding 18080.
|
||
|
|
_lnd_rest_host_port() {
|
||
|
|
local mf
|
||
|
|
for mf in \
|
||
|
|
"${ARCHIPELAGO_APPS_DIR:-/opt/archipelago/apps}/lnd/manifest.yml" \
|
||
|
|
"${ARCHIPELAGO_APPS_DIR:-/opt/archipelago/apps}/lnd/manifest.yaml" \
|
||
|
|
"$BATS_TEST_DIRNAME/../../../apps/lnd/manifest.yml"; do
|
||
|
|
[[ -r "$mf" ]] || continue
|
||
|
|
# The REST mapping is the `- host: <N>` whose following `container:` is 8080.
|
||
|
|
awk '
|
||
|
|
/- host:/ { host=$3 }
|
||
|
|
/container:/ { if ($2 == 8080 && host != "") { print host; exit } }
|
||
|
|
' "$mf"
|
||
|
|
return 0
|
||
|
|
done
|
||
|
|
}
|
||
|
|
|
||
|
|
_lnd_running() {
|
||
|
|
rpc_result container-list 2>/dev/null \
|
||
|
|
| jq -e '.[] | select(.name == "lnd" and .state == "running")' >/dev/null 2>&1
|
||
|
|
}
|
||
|
|
|
||
|
|
# ────────────────────────────────────────────────────────────────────
|
||
|
|
# Read-only tier
|
||
|
|
# ────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
@test "LND REST is reachable on the manifest host port (catches port drift)" {
|
||
|
|
_lnd_running || skip "lnd not running"
|
||
|
|
local port
|
||
|
|
port=$(_lnd_rest_host_port)
|
||
|
|
[[ -n "$port" ]] || skip "could not resolve LND REST host port from manifest"
|
||
|
|
|
||
|
|
# A TCP connect is enough: drift (container published on a different host
|
||
|
|
# port) shows up as connection-refused here, exactly as on .116.
|
||
|
|
run curl -sk -o /dev/null --max-time 8 "https://127.0.0.1:${port}/v1/getinfo"
|
||
|
|
if [ "$status" -ne 0 ]; then
|
||
|
|
echo "LND REST not reachable on host port ${port} (curl exit $status) — likely published-port drift" >&2
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "lnd.newaddress returns a bech32 address when lnd is running" {
|
||
|
|
_lnd_running || skip "lnd not running"
|
||
|
|
|
||
|
|
run rpc_call lnd.newaddress
|
||
|
|
[ "$status" -eq 0 ]
|
||
|
|
|
||
|
|
local err addr
|
||
|
|
err=$(echo "$output" | jq -r '.error.message // .error // empty')
|
||
|
|
addr=$(echo "$output" | jq -r '.result.address // empty')
|
||
|
|
|
||
|
|
# The whole point of the fix: a running lnd must hand back a real address.
|
||
|
|
if [[ -n "$err" ]]; then
|
||
|
|
echo "lnd.newaddress errored on a running node: $err" >&2
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
if [[ "$addr" != bc1* ]]; then
|
||
|
|
echo "expected a bech32 (bc1…) address, got: '$addr'" >&2
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
@test "receive errors are specific, never the generic catch-all" {
|
||
|
|
# Even when receive legitimately can't produce an address, the message must be
|
||
|
|
# actionable (start with 'Bitcoin address' and/or carry a [CODE] token) — the
|
||
|
|
# generic 'Operation failed' is what hid the real cause on .116.
|
||
|
|
run rpc_call lnd.newaddress
|
||
|
|
[ "$status" -eq 0 ]
|
||
|
|
local err
|
||
|
|
err=$(echo "$output" | jq -r '.error.message // .error // empty')
|
||
|
|
if [[ "$err" == "Operation failed. Check server logs for details." ]]; then
|
||
|
|
echo "receive returned the generic catch-all instead of a specific reason" >&2
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|