From 2d8606872ee8325e36a0c65d0872c77b940264ca Mon Sep 17 00:00:00 2001 From: Dorian Date: Fri, 10 Jul 2026 18:16:21 +0100 Subject: [PATCH] fix(doctor): enforce BTCPay Lightning route hints so private-channel invoices stay payable A store on a node whose LND has only unannounced channels mints BOLT11 invoices with no route hints when lightningPrivateRouteHints is off, and external wallets fail with "no way to pay this invoice" (hit on shorty-s 2026-07-10 with a Blink payer). Hints cost nothing on public channels, so the doctor now flips the flag on for every store on each run. Co-Authored-By: Claude Fable 5 --- scripts/container-doctor.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/scripts/container-doctor.sh b/scripts/container-doctor.sh index e16795af..dc5dd35a 100755 --- a/scripts/container-doctor.sh +++ b/scripts/container-doctor.sh @@ -16,6 +16,8 @@ # 7. Containers stuck with exit code 127 (binary not found) # 8. Stopped core containers (rootless restart policy workaround) # 9. Missing rootless port listeners while Podman still shows published ports +# 10. Nginx Proxy Manager public hosts not mirrored into host nginx +# 11. BTCPay stores producing unpayable Lightning invoices (route hints off) # # Safe to run multiple times (idempotent). Never blocks deploy (exit 0 always). # @@ -566,6 +568,32 @@ fix_npm_public_hosts() { return 1 } +# ── Fix 12: BTCPay Lightning route hints ───────────────────── +# A BTCPay store whose LND node has only private (unannounced) channels +# produces BOLT11 invoices that external wallets cannot route to unless the +# store's lightningPrivateRouteHints flag is on — payers see "no way to pay +# this invoice" (observed on shorty-s 2026-07-10 with a Blink payer). Route +# hints are a no-op with public channels and essential with private ones, so +# the doctor enforces the flag on every store. BTCPay reads store blobs from +# Postgres per request; no restart needed. +fix_btcpay_route_hints() { + local state + state=$(podman_rootless inspect archy-btcpay-db --format '{{.State.Status}}' 2>/dev/null || echo "missing") + [ "$state" = "running" ] || return 1 + + local count + count=$(podman_rootless exec archy-btcpay-db psql -U btcpay -d btcpay -t -A -c \ + "SELECT count(*) FROM \"Stores\" WHERE (\"StoreBlob\"->>'lightningPrivateRouteHints') = 'false';" 2>/dev/null) + [ -n "$count" ] && [ "$count" -gt 0 ] 2>/dev/null || return 1 + + if podman_rootless exec archy-btcpay-db psql -U btcpay -d btcpay -q -c \ + "UPDATE \"Stores\" SET \"StoreBlob\" = jsonb_set(\"StoreBlob\", '{lightningPrivateRouteHints}', 'true'::jsonb) WHERE (\"StoreBlob\"->>'lightningPrivateRouteHints') = 'false';" >/dev/null 2>&1; then + log "Enabled Lightning route hints on $count BTCPay store(s) (private-channel invoices were unpayable)" + return 0 + fi + return 1 +} + # ── Main ───────────────────────────────────────────────────── # If remote host provided, run via SSH @@ -596,6 +624,7 @@ run_fix "netns-egress" fix_rootless_netns_egress run_fix "stopped-core" fix_stopped_core_containers run_fix "rootless-ports" fix_missing_rootless_ports run_fix "npm-public-hosts" fix_npm_public_hosts +run_fix "btcpay-route-hints" fix_btcpay_route_hints echo "" if [ $FIXES_APPLIED -gt 0 ]; then