commit bf2c2d3508de20173c52808359e6e1fbd2845be9 Author: bitdeals Date: Thu Aug 6 11:56:52 2026 +0000 feat: docker image for Bitcoin Core, configured by environment Replaces lncm/bitcoind, which pins Core 26 — a version that still has legacy wallets, while the code that talks to it (bt's BitcoindClient) is written for the descriptor-only behaviour of 29 and later. The binaries are the official release build, verified by SHA-256 in the same layer that downloads them; a version bump that forgets the checksum fails the build instead of shipping something unverified. uid 1000 and /data/.bitcoin are kept from the image this replaces, so an existing named volume survives the switch without a recursive chown of a synced chain. Verified on testnet2: regtest node healthy in ~12 s, descriptor wallet, 101 blocks mined, sendtoaddress accepted — the last one being the check for BITCOIND_FALLBACKFEE, without which a fresh chain refuses to send. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d7fc2d --- /dev/null +++ b/README.md @@ -0,0 +1,136 @@ +# Intro + +> Русская версия: [README.ru-RU.md](README.ru-RU.md) + +[Bitcoin Core](https://bitcoincore.org/) is the reference Bitcoin implementation. `bitcoind` is its daemon: it keeps a full copy of the chain, relays transactions and serves a JSON-RPC interface. + +Bitcoin Core running as a daemon in a docker container, configured by environment variables. + +This repository covers the docker deployment only. The binaries are the official release build, checked against a SHA-256 pinned in the Dockerfile. + +# Usage + +The container has two ports and they are not interchangeable. The **RPC** port +(8332 main, 18332 test, 18443 regtest) controls the wallet and has no TLS: keep +it on loopback, or on an internal docker network. The **P2P** port (8333 / 18333 +/ 18444) is the chain protocol: publish it to accept inbound peers, leave it +unpublished to stay outbound-only. + +The chain is selected by `BITCOIND_CHAIN`, and it also sets the default RPC +port. An unknown value stops the container instead of falling back to mainnet. + +## docker-compose + +```yaml +services: + bitcoind: + build: + context: https://git.bitdeals.org/private/bitcoind.git + dockerfile: ./docker/Dockerfile + image: registry.bitdeals.org/bitcoind + environment: + - BITCOIND_CHAIN=regtest + - BITCOIND_USER=CHANGE_ME + - BITCOIND_PASSWORD=CHANGE_ME + - BITCOIND_FALLBACKFEE=0.00001 + - BITCOIND_TXINDEX=1 # both required by ElectrumX, + - BITCOIND_TXOSPENDERINDEX=1 # drop them if nothing indexes this node + ports: + - 127.0.0.1:18443:18443 # RPC — loopback only + volumes: + - btcdata:/data/.bitcoin + +volumes: + btcdata: +``` + +## docker cli + +```sh +docker run -d \ + -e BITCOIND_CHAIN=regtest \ + -e BITCOIND_USER=CHANGE_ME \ + -e BITCOIND_PASSWORD=CHANGE_ME \ + -e BITCOIND_FALLBACKFEE=0.00001 \ + -p 127.0.0.1:18443:18443 \ + -v btcdata:/data/.bitcoin \ + registry.bitdeals.org/bitcoind +``` + +Anything after the image name is appended to the daemon's own arguments, so a +one-off maintenance run needs no new image: + +```sh +docker run --rm -v btcdata:/data/.bitcoin registry.bitdeals.org/bitcoind -reindex +``` + +## build and publish + +```sh +docker build . --file docker/Dockerfile --tag registry.bitdeals.org/bitcoind +docker push registry.bitdeals.org/bitcoind +``` + +A different Core version is a build argument, and the checksum must move with +it — take both from `https://bitcoincore.org/bin/bitcoin-core-/SHA256SUMS`: + +```sh +docker build . --file docker/Dockerfile \ + --build-arg BITCOIN_VERSION=31.1 \ + --build-arg BITCOIN_SHA256_X86_64=b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e \ + --tag registry.bitdeals.org/bitcoind:31.1 +``` + +# Parameters + +Container images are configured using parameters passed at runtime. + +|Parameter|Function| +|:--------|:-------| +|-p 127.0.0.1:8332|RPC port. The daemon binds what `BITCOIND_RPCBIND` says, so what you publish decides who reaches it. It has full control of the wallet — see "Notes"| +|-p 8333|P2P port. Optional: without it the node still connects out to peers, it just cannot be connected to. Follows the chain: 8333 main, 18333 test, 18444 regtest| +|-v /data/.bitcoin|Data directory: the chain, the block index and the wallets. Without it a container update means downloading the chain again| +|-e BITCOIND_CHAIN|Network: `main`, `test`, `signet` or `regtest`. Anything else stops the container. Default: `main`| +|-e BITCOIND_USER|RPC user. Default: `user` — change it| +|-e BITCOIND_PASSWORD|RPC password. Default: `pass` — change it| +|-e BITCOIND_PORT|RPC port. Default: the standard port of the selected chain (`8332`/`18332`/`38332`/`18443`). Pin it to keep one RPC URL across networks| +|-e BITCOIND_RPCBIND|Interface the RPC listens on inside the container. Default: `0.0.0.0`, so other containers reach it by service name| +|-e BITCOIND_RPCALLOWIP|Who may call the RPC. Default: `0.0.0.0/0` — the container is expected to be closed off by what you publish, not by this| +|-e BITCOIND_FALLBACKFEE|Fee rate (BTC/kvB) used when the chain has no fee history to estimate from. Default: `0` (disabled). A fresh regtest chain needs it, e.g. `0.00001`| +|-e BITCOIND_TXINDEX|Build the full transaction index. Default: `0`. Required by ElectrumX. Changing it on an existing datadir forces a reindex| +|-e BITCOIND_TXOSPENDERINDEX|Build the index of which transaction spent each output. Default: `0`. Required by ElectrumX 2.x. Changing it on an existing datadir forces a reindex| +|-e BITCOIND_EXTRA_ARGS|Extra `bitcoind` arguments, split on whitespace and appended last — so they override everything above| + +# Notes + +- **The RPC has full control of the wallet and no TLS.** Publish it to + `127.0.0.1` only, or not at all — inside a compose project other services + reach it over the internal network by service name. `BITCOIND_RPCALLOWIP` + defaults to `0.0.0.0/0` because that is the only value that works for + container-to-container calls; the port mapping is what keeps it private. +- **The RPC credentials are visible in the container's process list.** They are + daemon arguments, which is how Core takes network-specific options that a + config file would apply only inside a `[chain]` section. `bitcoin-cli` inside + the container reads them from `cli.conf` instead, so the health check does not + add a second copy. +- **A datadir from another image needs one manual `chown`.** The daemon runs as + uid 1000 and the entrypoint fixes ownership of the data directory itself, but + it deliberately does not walk it: a synced mainnet datadir is hundreds of + gigabytes and a recursive `chown` would be added to every restart. +- **An ElectrumX in front of this node needs two indexes.** Set both + `BITCOIND_TXINDEX=1` and `BITCOIND_TXOSPENDERINDEX=1`: ElectrumX 2.x asks + `getindexinfo` at startup and exits naming the one that is missing — first + `txindex`, then, once that is fixed, `txospenderindex`. Both default to `0` + here because they cost disk and most other users do not need them. +- **Pruning is incompatible with ElectrumX.** An indexer needs the whole chain; + `-prune` through `BITCOIND_EXTRA_ARGS` will make it fail at some later, + much less obvious point. +- **Core 29 and later have no legacy wallets.** `createwallet` produces a + descriptor wallet, and a private key is imported with `importdescriptors`, not + `importprivkey`. Code that pins `descriptors=false` fails at wallet creation. +- **Bumping the version means bumping the checksum.** The build downloads the + release tarball and verifies it in the same layer; a version bump on its own + fails at `sha256sum -c` rather than shipping something unverified. +- The container turns healthy as soon as the RPC answers, which is long before + the chain is synced. That is on purpose: "unhealthy for three days of initial + block download" would get the node restarted by anything watching health. diff --git a/README.ru-RU.md b/README.ru-RU.md new file mode 100644 index 0000000..23aff0e --- /dev/null +++ b/README.ru-RU.md @@ -0,0 +1,139 @@ +# Общие сведения + +> English version: [README.md](README.md) + +[Bitcoin Core](https://bitcoincore.org/) — эталонная реализация Bitcoin. `bitcoind` — её демон: хранит полную копию цепочки, ретранслирует транзакции и предоставляет интерфейс JSON-RPC. + +Bitcoin Core, работающий демоном в docker-контейнере, настраивается переменными окружения. + +Репозиторий описывает только развёртывание в docker. Двоичные файлы — официальная сборка релиза, проверяемая по SHA-256, зафиксированному в Dockerfile. + +# Использование + +У контейнера два порта, и они не взаимозаменяемы. Порт **RPC** (8332 для main, +18332 для test, 18443 для regtest) управляет кошельком и не имеет TLS: держите +его на loopback или во внутренней сети docker. Порт **P2P** (8333 / 18333 / +18444) — протокол цепочки: опубликуйте его, чтобы принимать входящие соединения, +или не публикуйте, и тогда узел работает только на исходящих. + +Сеть выбирается переменной `BITCOIND_CHAIN`, она же задаёт RPC-порт по +умолчанию. Неизвестное значение останавливает контейнер, а не откатывается к +mainnet. + +## docker-compose + +```yaml +services: + bitcoind: + build: + context: https://git.bitdeals.org/private/bitcoind.git + dockerfile: ./docker/Dockerfile + image: registry.bitdeals.org/bitcoind + environment: + - BITCOIND_CHAIN=regtest + - BITCOIND_USER=CHANGE_ME + - BITCOIND_PASSWORD=CHANGE_ME + - BITCOIND_FALLBACKFEE=0.00001 + - BITCOIND_TXINDEX=1 # оба нужны ElectrumX; уберите, + - BITCOIND_TXOSPENDERINDEX=1 # если узел никто не индексирует + ports: + - 127.0.0.1:18443:18443 # RPC — только loopback + volumes: + - btcdata:/data/.bitcoin + +volumes: + btcdata: +``` + +## docker cli + +```sh +docker run -d \ + -e BITCOIND_CHAIN=regtest \ + -e BITCOIND_USER=CHANGE_ME \ + -e BITCOIND_PASSWORD=CHANGE_ME \ + -e BITCOIND_FALLBACKFEE=0.00001 \ + -p 127.0.0.1:18443:18443 \ + -v btcdata:/data/.bitcoin \ + registry.bitdeals.org/bitcoind +``` + +Всё, что указано после имени образа, добавляется к аргументам демона, поэтому +разовая служебная операция не требует нового образа: + +```sh +docker run --rm -v btcdata:/data/.bitcoin registry.bitdeals.org/bitcoind -reindex +``` + +## сборка и публикация + +```sh +docker build . --file docker/Dockerfile --tag registry.bitdeals.org/bitcoind +docker push registry.bitdeals.org/bitcoind +``` + +Другая версия Core задаётся аргументом сборки, и вместе с ней меняется +контрольная сумма — оба значения берутся из +`https://bitcoincore.org/bin/bitcoin-core-<версия>/SHA256SUMS`: + +```sh +docker build . --file docker/Dockerfile \ + --build-arg BITCOIN_VERSION=31.1 \ + --build-arg BITCOIN_SHA256_X86_64=b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e \ + --tag registry.bitdeals.org/bitcoind:31.1 +``` + +# Параметры + +Образы контейнера настраиваются параметрами, передаваемыми при запуске. + +|Параметр|Назначение| +|:--------|:-------| +|-p 127.0.0.1:8332|Порт RPC. Внутри контейнера демон слушает то, что задано `BITCOIND_RPCBIND`, поэтому доступность определяет то, что опубликовано. RPC полностью управляет кошельком — см. «Замечания»| +|-p 8333|P2P-порт. Необязательный: без него узел всё равно подключается к пирам сам, просто к нему подключиться нельзя. Зависит от сети: 8333 для main, 18333 для test, 18444 для regtest| +|-v /data/.bitcoin|Каталог данных: цепочка, индекс блоков и кошельки. Без него обновление контейнера означает повторную загрузку цепочки| +|-e BITCOIND_CHAIN|Сеть: `main`, `test`, `signet` или `regtest`. Любое другое значение останавливает контейнер. По умолчанию: `main`| +|-e BITCOIND_USER|Пользователь RPC. По умолчанию: `user` — измените| +|-e BITCOIND_PASSWORD|Пароль RPC. По умолчанию: `pass` — измените| +|-e BITCOIND_PORT|Порт RPC. По умолчанию: стандартный порт выбранной сети (`8332`/`18332`/`38332`/`18443`). Задайте явно, чтобы URL RPC не менялся при смене сети| +|-e BITCOIND_RPCBIND|Интерфейс, на котором RPC слушает внутри контейнера. По умолчанию: `0.0.0.0`, чтобы другие контейнеры обращались по имени сервиса| +|-e BITCOIND_RPCALLOWIP|Кому разрешены вызовы RPC. По умолчанию: `0.0.0.0/0` — закрытость контейнера обеспечивается тем, что опубликовано, а не этим параметром| +|-e BITCOIND_FALLBACKFEE|Комиссия (BTC/kvB) на случай, когда в цепочке нет истории для оценки. По умолчанию: `0` (выключено). Свежей regtest-цепочке параметр необходим, например `0.00001`| +|-e BITCOIND_TXINDEX|Строить полный индекс транзакций. По умолчанию: `0`. Требуется для ElectrumX. Изменение на существующем каталоге данных вызывает переиндексацию| +|-e BITCOIND_TXOSPENDERINDEX|Строить индекс «какая транзакция потратила этот выход». По умолчанию: `0`. Требуется для ElectrumX 2.x. Изменение на существующем каталоге данных вызывает переиндексацию| +|-e BITCOIND_EXTRA_ARGS|Дополнительные аргументы `bitcoind`, разделяемые пробелами и добавляемые последними — то есть они перекрывают всё вышеперечисленное| + +# Замечания + +- **RPC полностью управляет кошельком и не имеет TLS.** Публикуйте его только на + `127.0.0.1` или не публикуйте вовсе — внутри compose-проекта другие сервисы + обращаются к нему по имени сервиса во внутренней сети. Значение + `BITCOIND_RPCALLOWIP` по умолчанию `0.0.0.0/0`, потому что только оно работает + для обращений между контейнерами; закрытость даёт публикация портов. +- **Учётные данные RPC видны в списке процессов контейнера.** Это аргументы + демона, и иначе нельзя: сетевые параметры Core в конфигурационном файле + действуют только внутри секции `[chain]`. Внутри контейнера `bitcoin-cli` + берёт их из `cli.conf`, поэтому проверка состояния второй копии не создаёт. +- **Каталог данных из другого образа требует однократного `chown`.** Демон + работает под uid 1000, точка входа исправляет владельца самого каталога, но + намеренно не обходит его содержимое: синхронизированный mainnet — сотни + гигабайт, и рекурсивный `chown` добавлялся бы к каждому перезапуску. +- **ElectrumX перед этим узлом требует двух индексов.** Задайте одновременно + `BITCOIND_TXINDEX=1` и `BITCOIND_TXOSPENDERINDEX=1`: ElectrumX 2.x при старте + запрашивает `getindexinfo` и завершается, назвав недостающий — сначала + `txindex`, а после его включения `txospenderindex`. По умолчанию оба выключены, + потому что занимают место, а большинству других применений не нужны. +- **Обрезка цепочки (pruning) несовместима с ElectrumX.** Индексатору нужна вся + цепочка; `-prune` через `BITCOIND_EXTRA_ARGS` приведёт к отказу позже и в куда + менее очевидном месте. +- **В Core 29 и новее нет legacy-кошельков.** `createwallet` создаёт + дескрипторный кошелёк, приватный ключ импортируется через `importdescriptors`, + а не `importprivkey`. Код, жёстко задающий `descriptors=false`, падает уже при + создании кошелька. +- **Смена версии — это и смена контрольной суммы.** Сборка скачивает архив + релиза и проверяет его в том же слое; изменение одной лишь версии приводит к + ошибке `sha256sum -c`, а не к выпуску непроверенного образа. +- Контейнер становится healthy, как только отвечает RPC, — задолго до + синхронизации цепочки. Это сделано намеренно: состояние «unhealthy трое суток + начальной загрузки блоков» приводило бы к перезапускам узла всем, что следит + за состоянием контейнеров. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5e0c209 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +services: + bitcoind: + build: + # Repository root, not ./docker: the Dockerfile copies ./docker/run.sh + # and ./docker/healthy_check.sh, and those paths are resolved against the + # build context. + context: . + dockerfile: ./docker/Dockerfile + image: registry.bitdeals.org/bitcoind + environment: + - BITCOIND_CHAIN=regtest + - BITCOIND_USER=CHANGE_ME + - BITCOIND_PASSWORD=CHANGE_ME + # A fresh regtest chain has no fee history, so an unqualified + # sendtoaddress is refused until this is set. 0.00001 BTC/kvB = 1 sat/vB. + - BITCOIND_FALLBACKFEE=0.00001 + # Both are off by default and both are required by an ElectrumX in front + # of this node -- drop them if nothing indexes it. + - BITCOIND_TXINDEX=1 + - BITCOIND_TXOSPENDERINDEX=1 + ports: + # RPC controls the wallet and has no TLS -- loopback only. + - 127.0.0.1:18443:18443 + volumes: + - btcdata:/data/.bitcoin + +volumes: + btcdata: diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..0a882c1 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,90 @@ +# A container for the Bitcoin Core daemon +# +# The binaries are the official release build, taken from bitcoincore.org and +# checked against a SHA-256 pinned in this file. Building Core from source in +# CI would cost twenty minutes per image for a binary that upstream already +# publishes reproducibly; verifying the checksum is what makes taking it safe. +# +# Bumping BITCOIN_VERSION means bumping both checksums below. Get them from +# https://bitcoincore.org/bin/bitcoin-core-/SHA256SUMS -- if you bump +# the version alone the build fails at `sha256sum -c`, which is the intent. + +FROM debian:trixie-slim AS fetch + +ARG BITCOIN_VERSION=31.1 +ARG BITCOIN_SHA256_X86_64=b80d9c3e04da78fb6f0569685673418cf686fadba9042d926d13fb87ff503f9e +ARG BITCOIN_SHA256_AARCH64=dcf1873f2208ba4f962f3398d47e154c39c0084be8f4553e05c940d0ace3d004 + +RUN apt-get update \ + && apt-get install -yq --no-install-suggests --no-install-recommends \ + ca-certificates wget \ + && rm -rf /var/lib/apt/lists/* + +# One RUN, because the checksum must be verified in the same layer that +# downloads: a cached "download" layer paired with a later check would verify +# an artefact nobody fetched in this build. +RUN set -eu; \ + arch="$(uname -m)"; \ + case "$arch" in \ + x86_64) sha="$BITCOIN_SHA256_X86_64" ;; \ + aarch64) sha="$BITCOIN_SHA256_AARCH64" ;; \ + *) echo "unsupported architecture: $arch" >&2; exit 1 ;; \ + esac; \ + tarball="bitcoin-${BITCOIN_VERSION}-${arch}-linux-gnu.tar.gz"; \ + wget -q "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/${tarball}"; \ + echo "${sha} ${tarball}" | sha256sum -c -; \ + tar -xzf "$tarball" -C /tmp; \ + mkdir -p /opt/bitcoin/bin; \ + cp "/tmp/bitcoin-${BITCOIN_VERSION}/bin/bitcoind" \ + "/tmp/bitcoin-${BITCOIN_VERSION}/bin/bitcoin-cli" /opt/bitcoin/bin/; \ + /opt/bitcoin/bin/bitcoind -version | head -n 1 + + +FROM debian:trixie-slim + +# RPC. The daemon binds what BITCOIND_RPCBIND says (0.0.0.0 by default, because +# a container's peers reach it by service name); what you publish decides who +# outside can reach it, and the answer should stay "loopback only" -- the RPC +# controls the wallet and has no TLS. +EXPOSE 8332/tcp +# P2P. Publish it to accept inbound peers; without it the node still connects +# out. The port follows the chain: 8333 main, 18333 test, 18444 regtest. +EXPOSE 8333/tcp + +# uid/gid 1000 and /data/.bitcoin are not arbitrary: they are what the image +# this one replaces (lncm/bitcoind) used, so an existing named volume keeps +# working across the switch without a recursive chown of a synced chain. +ENV USER_UID=1000 +ENV USER_GID=1000 +ENV HOME=/data +ENV BITCOIN_DATA=/data/.bitcoin + +COPY --from=fetch /opt/bitcoin/bin/ /usr/local/bin/ +COPY ./docker/run.sh /usr/local/bin/ +COPY ./docker/healthy_check.sh /usr/local/bin/ + +RUN apt-get update \ + && apt-get install -yq --no-install-suggests --no-install-recommends gosu \ + && rm -rf /var/lib/apt/lists/* + +# Both are ENTRYPOINT/HEALTHCHECK targets in exec form, so the bit has to be +# set here: a clone on a filesystem that does not carry it would otherwise +# build an image that cannot start. +RUN chmod +x /usr/local/bin/run.sh /usr/local/bin/healthy_check.sh + +# groupadd, not addgroup: the slim images dropped the adduser package. +RUN groupadd --gid $USER_GID bitcoin \ + && useradd --uid $USER_UID --gid $USER_GID --skel /dev/null --create-home --home-dir $HOME bitcoin + +VOLUME ${BITCOIN_DATA} +WORKDIR ${HOME} + +# ENTRYPOINT, not CMD: everything after the image name is appended to bitcoind's +# own arguments, so `docker run … -reindex` does what it looks like. +ENTRYPOINT ["/usr/local/bin/run.sh"] + +# The daemon answers RPC long before the chain is synced, so this reports "can I +# be talked to", not "am I caught up". On a fresh mainnet datadir the first +# answer still waits for the block index to load, hence the start period. +HEALTHCHECK --interval=15s --timeout=10s --start-period=120s --retries=3 \ + CMD ["/usr/local/bin/healthy_check.sh"] diff --git a/docker/healthy_check.sh b/docker/healthy_check.sh new file mode 100755 index 0000000..ee88a8f --- /dev/null +++ b/docker/healthy_check.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Healthy = the RPC answers. Not "the chain is synced": an initial block +# download takes days on mainnet, and a container that reports unhealthy for all +# of it would be restarted by every orchestrator that watches health. +# +# The credentials come from cli.conf, written by run.sh, so they stay out of the +# process list -- unlike the daemon's own arguments, which cannot avoid them. + +set -eu + +exec gosu bitcoin bitcoin-cli \ + -datadir="${BITCOIN_DATA:-/data/.bitcoin}" \ + -conf="${BITCOIN_DATA:-/data/.bitcoin}/cli.conf" \ + getblockchaininfo > /dev/null diff --git a/docker/run.sh b/docker/run.sh new file mode 100755 index 0000000..b7341ee --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +set -eu + +export BITCOIND_CHAIN="${BITCOIND_CHAIN:-main}" +export BITCOIND_USER="${BITCOIND_USER:-user}" +export BITCOIND_PASSWORD="${BITCOIND_PASSWORD:-pass}" +export BITCOIND_FALLBACKFEE="${BITCOIND_FALLBACKFEE:-0}" +export BITCOIND_RPCBIND="${BITCOIND_RPCBIND:-0.0.0.0}" +export BITCOIND_RPCALLOWIP="${BITCOIND_RPCALLOWIP:-0.0.0.0/0}" +export BITCOIND_TXINDEX="${BITCOIND_TXINDEX:-0}" +export BITCOIND_TXOSPENDERINDEX="${BITCOIND_TXOSPENDERINDEX:-0}" +export BITCOIND_EXTRA_ARGS="${BITCOIND_EXTRA_ARGS:-}" + +# The chain name decides the default RPC port, so an unknown value must stop the +# container rather than fall through to a default: "-chain=testnet" (the name +# Core does not use -- it wants "test") would otherwise be a mainnet node +# holding a wallet the caller believes is worthless. +case "$BITCOIND_CHAIN" in + main) default_port=8332 ;; + test) default_port=18332 ;; + signet) default_port=38332 ;; + regtest) default_port=18443 ;; + *) + echo "BITCOIND_CHAIN must be one of main, test, signet, regtest (got '$BITCOIND_CHAIN')" >&2 + exit 1 + ;; +esac + +export BITCOIND_PORT="${BITCOIND_PORT:-$default_port}" +case "$BITCOIND_PORT" in + '' | *[!0-9]*) + echo "BITCOIND_PORT must be a positive integer" >&2 + exit 1 + ;; +esac + +# A named volume starts out owned by root. Non-recursive on purpose: the only +# case that needs fixing is the empty datadir, and a synced mainnet chain is +# hundreds of gigabytes -- walking it on every start would add minutes to each +# restart. A datadir moved here from an image with another uid must be chowned +# by hand, once (see README, "Notes"). +mkdir -p "$BITCOIN_DATA" +if [ "$(stat -c %u "$BITCOIN_DATA")" != "$USER_UID" ] +then + chown "$USER_UID:$USER_GID" "$BITCOIN_DATA" +fi + +# Credentials for bitcoin-cli, so the health check does not have to repeat them +# on a command line. Written before the daemon starts and readable only by the +# daemon's user. rpcport is deliberately at the top level: bitcoin-cli is +# invoked without -chain and therefore reads the mainnet section, whatever chain +# the daemon runs -- what matters is that the number matches. +cli_conf="${BITCOIN_DATA}/cli.conf" +umask 077 +cat > "$cli_conf" <