From ba5e9606dba70e9ca944eaf75a32979d88c8d0cd Mon Sep 17 00:00:00 2001 From: GaltRanch Date: Tue, 23 Jun 2026 18:10:00 -0300 Subject: [PATCH] fix(umbrel): bundle bitcoin-cli and lncli for mode A/B without Lite fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PyBLOCK's mode A (Bitcoin + Lightning) and mode B (Bitcoin only) call bitcoin-cli and lncli directly via subprocess. The Umbrel image did not ship those binaries, so the startup validation in PyBlock.py:1898-1909 detected the empty CLI paths and silently redirected to Lite Mode against public APIs — defeating the point of installing PyBLOCK on a node. Per nmfretz's review on getumbrel/umbrel-apps#5258, this takes the "bundle the binaries inside the PyBLOCK image" path (option 2): - dockerfile: download bitcoin-cli (Bitcoin Core 28.1) and lncli (LND v0.20.1-beta, matching what Umbrel ships) for both linux/amd64 and linux/arm64. Verifies the Bitcoin Core SHA256SUMS. Real binaries land at /usr/local/bin/{bitcoin-cli,lncli}.bin. - umbrel/{bitcoin-cli,lncli}-wrapper.sh: thin shell wrappers installed as /usr/local/bin/{bitcoin-cli,lncli} that exec the real binary with -rpcconnect/-rpcuser/-rpcpassword (or --rpcserver/--tlscertpath/ --macaroonpath for lncli) injected from the BITCOIN_RPC_* / LND_* env vars Umbrel provides via APP_BITCOIN_* / APP_LIGHTNING_*. They fail loud if those env vars are missing. - entrypoint.sh: default BITCOIN_CLI_PATH/LND_CLI_PATH to the wrapper locations when the relevant RPC host env vars are set and the wrapper is executable, so bclock.conf / blndconnect.conf get the right bitcoincli / ln paths automatically. - umbrel/: bump image tag and app version to v4.0.2 with release notes. Local smoke test on amd64: bitcoin-cli.bin --version -> Bitcoin Core RPC client version v28.1.0 lncli.bin --version -> lncli version 0.20.1-beta /usr/local/bin/bitcoin-cli (no env) -> fails with "BITCOIN_RPC_HOST must be set" /usr/local/bin/bitcoin-cli (env set) -> dispatches to the real binary Image grows ~70MB (mostly the Go-built lncli). Co-Authored-By: kulvex code --- dockerfile | 33 +++++++++++++++++++++++++++++++++ entrypoint.sh | 11 +++++++++++ umbrel/bitcoin-cli-wrapper.sh | 21 +++++++++++++++++++++ umbrel/docker-compose.yml | 2 +- umbrel/lncli-wrapper.sh | 19 +++++++++++++++++++ umbrel/umbrel-app.yml | 11 ++++++----- 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 umbrel/bitcoin-cli-wrapper.sh create mode 100644 umbrel/lncli-wrapper.sh diff --git a/dockerfile b/dockerfile index 67ff287..19e2830 100644 --- a/dockerfile +++ b/dockerfile @@ -29,6 +29,32 @@ RUN apt-get update \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +# Install bitcoin-cli and lncli so PyBLOCK's mode A/B can talk to Umbrel's +# Bitcoin Core and LND containers over RPC/gRPC without a degraded Lite Mode +# fallback. The binaries are wrapped by umbrel/{bitcoin-cli,lncli}-wrapper.sh +# (installed below) which inject the connection details Umbrel injects via +# env vars. +ARG TARGETARCH +ARG BITCOIN_VERSION=28.1 +ARG LND_VERSION=v0.20.1-beta +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) BTC_ARCH=x86_64-linux-gnu; LND_ARCH=amd64 ;; \ + arm64) BTC_ARCH=aarch64-linux-gnu; LND_ARCH=arm64 ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + cd /tmp; \ + wget -q "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/bitcoin-${BITCOIN_VERSION}-${BTC_ARCH}.tar.gz"; \ + wget -q "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/SHA256SUMS"; \ + grep "bitcoin-${BITCOIN_VERSION}-${BTC_ARCH}.tar.gz" SHA256SUMS | sha256sum -c -; \ + tar -xzf "bitcoin-${BITCOIN_VERSION}-${BTC_ARCH}.tar.gz" "bitcoin-${BITCOIN_VERSION}/bin/bitcoin-cli"; \ + install -m 0755 "bitcoin-${BITCOIN_VERSION}/bin/bitcoin-cli" /usr/local/bin/bitcoin-cli.bin; \ + rm -rf "bitcoin-${BITCOIN_VERSION}" "bitcoin-${BITCOIN_VERSION}-${BTC_ARCH}.tar.gz" SHA256SUMS; \ + wget -q "https://github.com/lightningnetwork/lnd/releases/download/${LND_VERSION}/lnd-linux-${LND_ARCH}-${LND_VERSION}.tar.gz"; \ + tar -xzf "lnd-linux-${LND_ARCH}-${LND_VERSION}.tar.gz" --strip-components=1 "lnd-linux-${LND_ARCH}-${LND_VERSION}/lncli"; \ + install -m 0755 lncli /usr/local/bin/lncli.bin; \ + rm -f lncli "lnd-linux-${LND_ARCH}-${LND_VERSION}.tar.gz" + RUN python3 -m venv /app/venv ENV PATH="/app/venv/bin:$PATH" @@ -39,6 +65,13 @@ RUN pip install --no-cache-dir --upgrade pip \ COPY . /app/pyblock/ +# Install the bitcoin-cli / lncli wrappers as the default CLI paths so any +# subprocess call to bitcoin-cli / lncli (including PyBLOCK's mode A/B menus) +# is transparently routed through RPC/gRPC against the Umbrel dependency +# containers. The real binaries live at /usr/local/bin/{bitcoin-cli,lncli}.bin. +RUN install -m 0755 /app/pyblock/umbrel/bitcoin-cli-wrapper.sh /usr/local/bin/bitcoin-cli \ + && install -m 0755 /app/pyblock/umbrel/lncli-wrapper.sh /usr/local/bin/lncli + # Entrypoint for auto-configuration COPY entrypoint.sh /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh diff --git a/entrypoint.sh b/entrypoint.sh index a738595..5f8cac1 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -16,6 +16,17 @@ if ! touch "$CONFIG_DIR/.writetest" 2>/dev/null; then fi rm -f "$CONFIG_DIR/.writetest" +# Default to the bundled bitcoin-cli / lncli wrappers when the caller hasn't +# overridden them. The wrappers route every CLI invocation through RPC/gRPC +# against the Umbrel Bitcoin Core and LND containers, so PyBLOCK's mode A/B +# work without a real local node binary on disk. +if [ -n "$BITCOIN_RPC_HOST" ] && [ -x /usr/local/bin/bitcoin-cli ]; then + export BITCOIN_CLI_PATH="${BITCOIN_CLI_PATH:-/usr/local/bin/bitcoin-cli}" +fi +if [ -n "$LND_HOST" ] && [ -x /usr/local/bin/lncli ]; then + export LND_CLI_PATH="${LND_CLI_PATH:-/usr/local/bin/lncli}" +fi + # Auto-generate Bitcoin config from env vars if set if [ -n "$BITCOIN_RPC_HOST" ] && [ -n "$BITCOIN_RPC_USER" ]; then BITCOIN_RPC_PORT="${BITCOIN_RPC_PORT:-8332}" diff --git a/umbrel/bitcoin-cli-wrapper.sh b/umbrel/bitcoin-cli-wrapper.sh new file mode 100644 index 0000000..6c2d2b7 --- /dev/null +++ b/umbrel/bitcoin-cli-wrapper.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# bitcoin-cli wrapper for Umbrel/Docker deployments. +# +# PyBLOCK's modes A/B call bitcoin-cli directly via subprocess. Inside the +# Umbrel container we connect to the host's Bitcoin Core (or Knots) over the +# Docker network using the credentials Umbrel injects through APP_BITCOIN_* +# env vars (re-exported by the entrypoint as BITCOIN_RPC_*). This wrapper +# turns every `bitcoin-cli` call into a properly-authenticated remote RPC +# call against that node. +set -e + +: "${BITCOIN_RPC_HOST:?BITCOIN_RPC_HOST must be set}" +: "${BITCOIN_RPC_USER:?BITCOIN_RPC_USER must be set}" +: "${BITCOIN_RPC_PASS:?BITCOIN_RPC_PASS must be set}" + +exec /usr/local/bin/bitcoin-cli.bin \ + -rpcconnect="${BITCOIN_RPC_HOST}" \ + -rpcport="${BITCOIN_RPC_PORT:-8332}" \ + -rpcuser="${BITCOIN_RPC_USER}" \ + -rpcpassword="${BITCOIN_RPC_PASS}" \ + "$@" diff --git a/umbrel/docker-compose.yml b/umbrel/docker-compose.yml index d3f0fba..3e98118 100644 --- a/umbrel/docker-compose.yml +++ b/umbrel/docker-compose.yml @@ -7,7 +7,7 @@ services: APP_PORT: 6969 web: - image: curly60e/pyblock:v4.0.1 + image: curly60e/pyblock:v4.0.2 restart: on-failure stop_grace_period: 1m user: "1000:1000" diff --git a/umbrel/lncli-wrapper.sh b/umbrel/lncli-wrapper.sh new file mode 100644 index 0000000..787cdd1 --- /dev/null +++ b/umbrel/lncli-wrapper.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# lncli wrapper for Umbrel/Docker deployments. +# +# Mirrors umbrel/bitcoin-cli-wrapper.sh: PyBLOCK shells out to lncli for +# Lightning operations, so we turn every `lncli` call into one against the +# Umbrel LND container using the gRPC endpoint, TLS cert, and macaroon +# Umbrel injects through APP_LIGHTNING_* env vars (re-exported by the +# entrypoint as LND_*). +set -e + +: "${LND_HOST:?LND_HOST must be set}" +: "${LND_TLS_CERT_PATH:?LND_TLS_CERT_PATH must be set}" +: "${LND_MACAROON_PATH:?LND_MACAROON_PATH must be set}" + +exec /usr/local/bin/lncli.bin \ + --rpcserver="${LND_HOST}:${LND_GRPC_PORT:-10009}" \ + --tlscertpath="${LND_TLS_CERT_PATH}" \ + --macaroonpath="${LND_MACAROON_PATH}" \ + "$@" diff --git a/umbrel/umbrel-app.yml b/umbrel/umbrel-app.yml index 010aa49..ea1780d 100644 --- a/umbrel/umbrel-app.yml +++ b/umbrel/umbrel-app.yml @@ -2,7 +2,7 @@ manifestVersion: 1 id: pyblock category: bitcoin name: PyBLOCK -version: "4.0.1" +version: "4.0.2" tagline: Terminal-based Bitcoin & Lightning node dashboard description: >- PyBLOCK is a cyberpunk-aesthetic Bitcoin dashboard that runs in your @@ -40,9 +40,10 @@ defaultUsername: "" defaultPassword: "" deterministicPassword: false releaseNotes: >- - v4.0.1: Fix permission errors on Umbrel by pinning the container user - to UID/GID 1000, matching the user enforced by docker-compose. Adds a - startup writability check that fails fast with a clear message when - the bind-mounted config directory is not writable. + v4.0.2: Bundle bitcoin-cli and lncli inside the image, wrapped to inject + the RPC/gRPC connection details Umbrel provides via APP_BITCOIN_* and + APP_LIGHTNING_* env vars. Modes A (Bitcoin + Lightning) and B (Bitcoin + only) now connect to the Umbrel dependency containers directly instead + of falling back to Lite Mode at startup. submitter: curly60e submission: ""