pyblock/entrypoint.sh
GaltRanch ba5e9606db fix(umbrel): bundle bitcoin-cli and lncli for mode A/B without Lite fallback
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 <noreply@github.com>
2026-06-23 18:10:00 -03:00

112 lines
3.7 KiB
Bash
Executable file

#!/bin/bash
set -e
CONFIG_DIR="/app/pyblock/pybitblock/config"
mkdir -p "$CONFIG_DIR"
# Fail fast with a clear message if the config dir is not writable. This is
# almost always a UID mismatch between the host bind-mount owner and the
# container user (Umbrel forces `user: "1000:1000"`).
if ! touch "$CONFIG_DIR/.writetest" 2>/dev/null; then
echo "[PyBLOCK] FATAL: cannot write to $CONFIG_DIR" >&2
echo "[PyBLOCK] The bind-mounted host directory must be writable by UID $(id -u):$(id -g)." >&2
echo "[PyBLOCK] On Umbrel, ensure \${APP_DATA_DIR}/data/config is owned by 1000:1000." >&2
ls -ld "$CONFIG_DIR" >&2 || true
exit 1
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}"
cat > "$CONFIG_DIR/bclock.conf" <<BTCEOF
{
"ip_port": "http://${BITCOIN_RPC_HOST}:${BITCOIN_RPC_PORT}",
"rpcuser": "${BITCOIN_RPC_USER}",
"rpcpass": "${BITCOIN_RPC_PASS}",
"bitcoincli": "${BITCOIN_CLI_PATH:-}"
}
BTCEOF
echo "[PyBLOCK] Bitcoin RPC configured: ${BITCOIN_RPC_HOST}:${BITCOIN_RPC_PORT}"
fi
# Auto-generate LND config from env vars if set
if [ -n "$LND_HOST" ] || [ -n "$LND_TLS_CERT_PATH" ]; then
LND_GRPC_PORT="${LND_GRPC_PORT:-10009}"
# Only build ip_port if LND_HOST is set (matches Python _env_lnd_config)
if [ -n "$LND_HOST" ]; then
LND_IP_PORT="${LND_HOST}:${LND_GRPC_PORT}"
else
LND_IP_PORT=""
fi
cat > "$CONFIG_DIR/blndconnect.conf" <<LNDEOF
{
"ip_port": "${LND_IP_PORT}",
"tls": "${LND_TLS_CERT_PATH:-}",
"macaroon": "${LND_MACAROON_PATH:-}",
"ln": "${LND_CLI_PATH:-}"
}
LNDEOF
echo "[PyBLOCK] LND configured: ${LND_IP_PORT:-local paths only}"
fi
# Auto-set mode if specified (PYBLOCK_MODE always overwrites)
PYBLOCK_MODE="${PYBLOCK_MODE:-}"
if [ -n "$PYBLOCK_MODE" ]; then
echo "\"${PYBLOCK_MODE}\"" > "$CONFIG_DIR/intro.conf"
echo "[PyBLOCK] Mode set to: ${PYBLOCK_MODE}"
elif [ -n "$BITCOIN_RPC_HOST" ] && [ ! -f "$CONFIG_DIR/intro.conf" ]; then
# Auto-detect mode from available env vars
if [ -n "$LND_HOST" ] || [ -n "$LND_TLS_CERT_PATH" ]; then
echo '"A"' > "$CONFIG_DIR/intro.conf"
echo "[PyBLOCK] Auto-detected mode: A (Bitcoin + Lightning)"
else
echo '"B"' > "$CONFIG_DIR/intro.conf"
echo "[PyBLOCK] Auto-detected mode: B (Bitcoin Only)"
fi
fi
# Generate default settings if missing
if [ ! -f "$CONFIG_DIR/pyblocksettings.conf" ]; then
cat > "$CONFIG_DIR/pyblocksettings.conf" <<SEOF
{
"gradient": "",
"design": "block",
"colorA": "green",
"colorB": "yellow"
}
SEOF
fi
if [ ! -f "$CONFIG_DIR/pyblocksettingsClock.conf" ]; then
cat > "$CONFIG_DIR/pyblocksettingsClock.conf" <<SCEOF
{
"gradient": "",
"colorA": "green",
"colorB": "yellow"
}
SCEOF
fi
echo "[PyBLOCK] Starting..."
# Ensure UTF-8 for all terminal output (ttyd, AI responses, etc.)
export LANG="${LANG:-C.UTF-8}"
export LC_ALL="${LC_ALL:-C.UTF-8}"
export PYTHONIOENCODING=utf-8
# Launch PyBLOCK via ttyd
exec ttyd -W -p "${PYBLOCK_PORT:-6969}" \
${PYBLOCK_TTYD_AUTH:+-c "$PYBLOCK_TTYD_AUTH"} \
python3 /app/pyblock/pybitblock/PyBlock.py "$@"