docker-compose.regtest.yml
Rama master · réplica de lectura del repositorio original.
# Local regtest e2e stack: bitcoind + postgres + 3 Spark Operators + our SSP.
#
# Usage:
# git submodule update --init --recursive
# SPARK_ADMIN_TOKEN=regtest-spark-admin-token docker compose -f docker-compose.regtest.yml up --build -d
# ./e2e/e2e.sh # resets a separate test project and tears it down afterward
# docker compose -f docker-compose.regtest.yml down
#
# Sources default to the pinned Git submodules in vendor/. Override SPARK_REF
# or LDK_SERVER_REF to build from other local checkouts.
#
# Host ports: bitcoind RPC uses BITCOIN_RPC_PORT (8332 by default), SOs use
# 8535-8537, and SSP uses 5000. PostgreSQL and bitcoind ZMQ stay private.
x-operator-common: &operator-common
image: ${SPARK_OPERATOR_IMAGE:-open-ssp-spark-operator:regtest}
build:
context: ${SPARK_REF:-./vendor/spark}
dockerfile: Dockerfile
depends_on:
postgres:
condition: service_healthy
bitcoin-init:
condition: service_completed_successfully
cert-init:
condition: service_completed_successfully
restart: unless-stopped
entrypoint: ["/bin/sh", "-c"]
volumes:
- ./e2e/upstream/entrypoint.sh:/opt/spark/entrypoint.sh:ro
- ./e2e/upstream/config.json:/opt/spark/config.json:ro
- ./e2e/upstream/operator.config.yaml:/opt/spark/operator.config.yaml:ro
- ./e2e/upstream/operator_0.key:/opt/spark/keys/operator_0.key:ro
- ./e2e/upstream/operator_1.key:/opt/spark/keys/operator_1.key:ro
- ./e2e/upstream/operator_2.key:/opt/spark/keys/operator_2.key:ro
- tls-certs:/opt/spark/tls:ro
services:
cert-init:
image: alpine:3.20
restart: "no"
entrypoint: ["/bin/sh", "-c"]
command:
- |
set -e
apk add --no-cache openssl > /dev/null
for i in 0 1 2; do
KEY="/tls/server_$${i}.key"
CERT="/tls/server_$${i}.crt"
if [ -f "$$KEY" ] && [ -f "$$CERT" ] \
&& openssl x509 -in "$$CERT" -noout -ext basicConstraints 2>/dev/null \
| grep -q "CA:FALSE"; then
echo "TLS key/cert for operator $$i already exist, skipping"
continue
fi
echo "Generating TLS server key/cert for operator $$i..."
TMP_KEY="$${KEY}.tmp"
TMP_CERT="$${CERT}.tmp"
openssl genrsa -out "$$TMP_KEY" 2048 2>/dev/null
openssl req -new -x509 \
-key "$$TMP_KEY" -out "$$TMP_CERT" \
-days 3650 \
-subj "/CN=spark-operator-$${i}" \
-addext "subjectAltName = DNS:spark-operator-$${i},DNS:localhost,DNS:spark-operator-$${i}.minikube.local" \
-addext "basicConstraints = critical,CA:FALSE" \
-addext "keyUsage = critical,digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage = serverAuth"
mv "$$TMP_KEY" "$$KEY"
mv "$$TMP_CERT" "$$CERT"
done
echo "TLS certificates ready"
volumes:
- tls-certs:/tls
postgres:
image: postgres:16-bookworm
environment:
POSTGRES_HOST_AUTH_METHOD: trust
volumes:
- postgres-data:/var/lib/postgresql/data
- ./e2e/upstream/init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 5s
retries: 30
start_period: 30s
bitcoind:
image: lncm/bitcoind:v28.0
command:
- -conf=/bitcoin.conf
ports:
- "127.0.0.1:${BITCOIN_RPC_PORT:-8332}:8332"
volumes:
- bitcoind-data:/data/.bitcoin
- ./e2e/upstream/bitcoin.conf:/bitcoin.conf:ro
healthcheck:
test: ["CMD", "bitcoin-cli", "-regtest", "-rpcuser=testutil", "-rpcpassword=testutilpassword", "-rpcport=8332", "getblockchaininfo"]
interval: 2s
timeout: 5s
retries: 15
bitcoin-init:
image: lncm/bitcoind:v28.0
depends_on:
bitcoind:
condition: service_healthy
restart: "no"
entrypoint: ["/bin/sh", "-c"]
command:
- |
set -e
CLI="bitcoin-cli -regtest -rpcuser=testutil -rpcpassword=testutilpassword -rpcconnect=bitcoind -rpcport=8332"
if ! $$CLI listwallets | grep -q '"default"'; then
if $$CLI listwalletdir | grep -q '"name": "default"'; then
$$CLI loadwallet default > /dev/null
else
$$CLI createwallet default false false '' false true > /dev/null
fi
fi
BALANCE=$$($$CLI -rpcwallet=default getbalance)
case "$$BALANCE" in
0|0.00000000) NEEDS_FUND=1 ;;
*) NEEDS_FUND=0 ;;
esac
if [ "$$NEEDS_FUND" = "1" ]; then
ADDRESS=$$($$CLI -rpcwallet=default getnewaddress)
$$CLI generatetoaddress 101 "$$ADDRESS" > /dev/null
echo "Funded wallet with 101 blocks"
fi
echo "Bitcoin wallet ready"
if ! $$CLI listwallets | grep -q '"ssp-withdrawals"'; then
if $$CLI listwalletdir | grep -q '"name": "ssp-withdrawals"'; then
$$CLI loadwallet ssp-withdrawals > /dev/null
else
$$CLI createwallet ssp-withdrawals false false '' false true > /dev/null
fi
fi
if [ "$$($$CLI -rpcwallet=ssp-withdrawals getbalance)" = "0.00000000" ]; then
ADDRESS=$$($$CLI -rpcwallet=ssp-withdrawals getnewaddress '' bech32m)
$$CLI -rpcwallet=default sendtoaddress "$$ADDRESS" 1 > /dev/null
MINE_ADDRESS=$$($$CLI -rpcwallet=default getnewaddress)
$$CLI generatetoaddress 3 "$$MINE_ADDRESS" > /dev/null
fi
bitcoin-miner:
image: lncm/bitcoind:v28.0
depends_on:
bitcoin-init:
condition: service_completed_successfully
restart: unless-stopped
entrypoint: ["/bin/sh", "-c"]
command:
- |
CLI="bitcoin-cli -regtest -rpcuser=testutil -rpcpassword=testutilpassword -rpcconnect=bitcoind -rpcport=8332"
while true; do
ADDRESS=$$($$CLI -rpcwallet=default getnewaddress 2>&1) || { sleep 10; continue; }
$$CLI generatetoaddress 1 "$$ADDRESS" > /dev/null 2>&1 && \
echo "$$(date): Mined 1 block" || \
echo "$$(date): ERROR: Failed to mine block"
sleep 10
done
electrs:
image: coffernetwork/regtest-electrs:28.1@sha256:7cd973541afc28e75ff18b93050df4e91749b38af031930ed2b77f4088a3d246
depends_on:
bitcoind:
condition: service_healthy
command:
- --network=regtest
- --jsonrpc-import
- --cookie=testutil:testutilpassword
- --daemon-rpc-addr=bitcoind:8332
- --db-dir=/electrs
- --electrum-rpc-addr=0.0.0.0:60401
- --http-addr=0.0.0.0:3002
- --monitoring-addr=0.0.0.0:24224
- --cors=*
- --address-search
ports:
- "127.0.0.1:30000:3002"
volumes:
- electrs-data:/electrs
restart: unless-stopped
spark-operator-0:
<<: *operator-common
command:
- /opt/spark/entrypoint.sh 0
ports:
- "127.0.0.1:8535:8535"
expose:
- "8536"
networks:
default:
aliases:
- spark-operator-0.minikube.local
spark-operator-1:
<<: *operator-common
command:
- /opt/spark/entrypoint.sh 1
ports:
- "127.0.0.1:8536:8535"
expose:
- "8536"
networks:
default:
aliases:
- spark-operator-1.minikube.local
spark-operator-2:
<<: *operator-common
command:
- /opt/spark/entrypoint.sh 2
ports:
- "127.0.0.1:8537:8535"
expose:
- "8536"
networks:
default:
aliases:
- spark-operator-2.minikube.local
# ---- Lightning backend ---------------------------------------------------
# Built from a local ldk-server checkout (set LDK_SERVER_REF). The SSP talks
# to it over gRPC whenever LDK_GRPC_ADDR and credentials are set.
ldk-server:
image: ${LDK_SERVER_IMAGE:-open-ssp-ldk-server:regtest}
build:
context: ${LDK_SERVER_REF:-./vendor/ldk-server}
dockerfile: Dockerfile
depends_on:
bitcoind:
condition: service_healthy
ports:
- "127.0.0.1:3536:3536"
- "127.0.0.1:19735:9735"
healthcheck:
test: ["CMD-SHELL", "test -r /data/regtest/macaroons/admin.macaroon && ldk-server-cli --base-url localhost:3536 --macaroon $$(tr -d '[:space:]' < /data/regtest/macaroons/admin.macaroon) --tls-cert /data/tls.crt get-node-info >/dev/null"]
interval: 10s
timeout: 5s
retries: 12
volumes:
- ldk-data:/data
- ./e2e/ldk-server-config.toml:/config.toml:ro
entrypoint: ["/bin/sh", "-c"]
command:
- |
ldk-server /config.toml &
PID=$$!
trap 'kill -TERM "$$PID"' TERM INT
while kill -0 "$$PID" 2>/dev/null; do
if [ -f /data/regtest/macaroons/admin.macaroon ] && [ -f /data/tls.crt ]; then
chmod 0755 /data/regtest /data/regtest/macaroons
chmod 0444 /data/regtest/macaroons/admin.macaroon /data/tls.crt
break
fi
sleep 1
done
wait "$$PID"
restart: unless-stopped
# Second node: LN counterparty for e2e send/receive (channel peer for ldk-server).
ldk-server-2:
image: ${LDK_SERVER_IMAGE:-open-ssp-ldk-server:regtest}
build:
context: ${LDK_SERVER_REF:-./vendor/ldk-server}
dockerfile: Dockerfile
depends_on:
bitcoind:
condition: service_healthy
ports:
- "127.0.0.1:3537:3536"
- "127.0.0.1:19736:9735"
volumes:
- ldk-data-2:/data
- ./e2e/ldk-server-2-config.toml:/config.toml:ro
entrypoint: ["/bin/sh", "-c"]
command:
- |
ldk-server /config.toml &
PID=$$!
trap 'kill -TERM "$$PID"' TERM INT
while kill -0 "$$PID" 2>/dev/null; do
if [ -f /data/regtest/macaroons/admin.macaroon ] && [ -f /data/tls.crt ]; then
chmod 0755 /data/regtest /data/regtest/macaroons
chmod 0444 /data/regtest/macaroons/admin.macaroon /data/tls.crt
break
fi
sleep 1
done
wait "$$PID"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "test -r /data/regtest/macaroons/admin.macaroon && ldk-server-cli --base-url localhost:3536 --macaroon $$(tr -d '[:space:]' < /data/regtest/macaroons/admin.macaroon) --tls-cert /data/tls.crt get-node-info >/dev/null"]
interval: 10s
timeout: 5s
retries: 12
ssp:
# Prebuilt: docker compose pull (needs GHCR access); or --build locally.
image: ${SSP_IMAGE:-ghcr.io/benthecarman/open-ssp:latest}
build:
context: .
dockerfile: ssp.Dockerfile
depends_on:
spark-operator-0:
condition: service_started
spark-operator-1:
condition: service_started
spark-operator-2:
condition: service_started
ldk-server:
condition: service_healthy
ports:
- "127.0.0.1:5000:5000"
extra_hosts:
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD", "open-ssp", "healthcheck"]
interval: 10s
timeout: 5s
retries: 12
volumes:
- ssp-data:/data
- ldk-data:/ldk-data:ro
- tls-certs:/tls:ro
environment:
SSP_LISTEN_ADDR: 0.0.0.0:5000
SSP_CORS_ORIGINS: ${SSP_CORS_ORIGINS:-}
SSP_NETWORK: ${SSP_NETWORK:-REGTEST}
SSP_DATA_DIR: /data
SSP_PUBLIC_URL: http://ssp:5000
SSP_WEBHOOK_ALLOW_LOCAL: ${SSP_WEBHOOK_ALLOW_LOCAL:-0}
SSP_INSTANT_MAX_OUTSTANDING_SATS: ${SSP_INSTANT_MAX_OUTSTANDING_SATS:-0}
SSP_INSTANT_MAX_DEPOSIT_SATS: ${SSP_INSTANT_MAX_DEPOSIT_SATS:-0}
COOP_BITCOIN_RPC_URL: http://bitcoind:8332/wallet/ssp-withdrawals
COOP_BITCOIN_RPC_USER: testutil
COOP_BITCOIN_RPC_PASSWORD: testutilpassword
SPARK_MNEMONIC_FILE: /data/spark.mnemonic
SO_HOSTS: ${SO_HOSTS:-spark-operator-0.minikube.local:8535,spark-operator-1.minikube.local:8535,spark-operator-2.minikube.local:8535}
SO_IDENTITY_PUBKEYS: ${SO_IDENTITY_PUBKEYS:-0322ca18fc489ae25418a0e768273c2c61cabb823edfb14feb891e9bec62016510,0341727a6c41b168f07eb50865ab8c397a53c7eef628ac1020956b705e43b6cb27,0305ab8d485cc752394de4981f8a5ae004f2becfea6f432c9a59d5022d8764f0a6}
SO_CERT_FILES: /tls/server_0.crt,/tls/server_1.crt,/tls/server_2.crt
SSP_OPERATOR_HOSTS: spark-operator-0.minikube.local:8536,spark-operator-1.minikube.local:8536,spark-operator-2.minikube.local:8536
SSP_OPERATOR_CERT_FILES: /tls/server_0.crt,/tls/server_1.crt,/tls/server_2.crt
# Regtest withdrawal fees can require leaves smaller than 330 sats.
SSP_MIN_SPLIT_CHILD_SATS: 1
SPARK_ADMIN_TOKEN: ${SPARK_ADMIN_TOKEN:?set SPARK_ADMIN_TOKEN}
# Live LDK backend: bitcoind-backed ldk-server above.
LDK_GRPC_ADDR: ${LDK_GRPC_ADDR:-ldk-server:3536}
LDK_MACAROON: ${LDK_MACAROON:-}
LDK_MACAROON_FILE: ${LDK_MACAROON_FILE:-/ldk-data/regtest/macaroons/admin.macaroon}
LDK_TLS_CERT_FILE: ${LDK_TLS_CERT_FILE:-/ldk-data/tls.crt}
SSP_SWAP_FEE_SATS: 0
SSP_FROST_THRESHOLD: 2
RUST_LOG: info
# The second SSP gives each Breez wallet a distinct Lightning node. This
# prevents the test from paying an invoice back to the same node.
ssp-2:
image: ${SSP_IMAGE:-ghcr.io/benthecarman/open-ssp:latest}
build:
context: .
dockerfile: ssp.Dockerfile
depends_on:
spark-operator-0:
condition: service_started
spark-operator-1:
condition: service_started
spark-operator-2:
condition: service_started
ldk-server-2:
condition: service_healthy
ports:
- "127.0.0.1:5001:5000"
extra_hosts:
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD", "open-ssp", "healthcheck"]
interval: 10s
timeout: 5s
retries: 12
volumes:
- ssp-data-2:/data
- ldk-data-2:/ldk-data:ro
- tls-certs:/tls:ro
environment:
SSP_LISTEN_ADDR: 0.0.0.0:5000
SSP_NETWORK: REGTEST
SSP_DATA_DIR: /data
SSP_PUBLIC_URL: http://ssp-2:5000
SSP_WEBHOOK_ALLOW_LOCAL: ${SSP_WEBHOOK_ALLOW_LOCAL:-0}
SSP_INSTANT_MAX_OUTSTANDING_SATS: ${SSP_INSTANT_MAX_OUTSTANDING_SATS:-0}
SSP_INSTANT_MAX_DEPOSIT_SATS: ${SSP_INSTANT_MAX_DEPOSIT_SATS:-0}
SPARK_MNEMONIC_FILE: /data/spark.mnemonic
SO_HOSTS: spark-operator-0.minikube.local:8535,spark-operator-1.minikube.local:8535,spark-operator-2.minikube.local:8535
SO_IDENTITY_PUBKEYS: 0322ca18fc489ae25418a0e768273c2c61cabb823edfb14feb891e9bec62016510,0341727a6c41b168f07eb50865ab8c397a53c7eef628ac1020956b705e43b6cb27,0305ab8d485cc752394de4981f8a5ae004f2becfea6f432c9a59d5022d8764f0a6
SO_CERT_FILES: /tls/server_0.crt,/tls/server_1.crt,/tls/server_2.crt
SSP_OPERATOR_HOSTS: spark-operator-0.minikube.local:8536,spark-operator-1.minikube.local:8536,spark-operator-2.minikube.local:8536
SSP_OPERATOR_CERT_FILES: /tls/server_0.crt,/tls/server_1.crt,/tls/server_2.crt
SSP_MIN_SPLIT_CHILD_SATS: 330
SPARK_ADMIN_TOKEN: ${SPARK_ADMIN_TOKEN:?set SPARK_ADMIN_TOKEN}
LDK_GRPC_ADDR: ldk-server-2:3536
LDK_MACAROON_FILE: /ldk-data/regtest/macaroons/admin.macaroon
LDK_TLS_CERT_FILE: /ldk-data/tls.crt
SSP_SWAP_FEE_SATS: 0
SSP_FROST_THRESHOLD: 2
RUST_LOG: info
volumes:
postgres-data:
bitcoind-data:
electrs-data:
tls-certs:
ldk-data:
ldk-data-2:
ssp-data:
ssp-data-2: