feat(docker): single-container staking node for GUI integration
Some checks are pending
Build & Release / Linux x86_64 (push) Waiting to run
Build & Release / macOS ARM64 (push) Waiting to run
Build & Release / Create Release (push) Blocked by required conditions

Dockerfile.staking-node — runs daemon + wallet with PoS staking in one
container using supervisord. No docker-compose needed.

For the CoreGUI desktop app to run on Windows/Mac/Linux:
  docker run -d -p 46941:36941 -p 46942:36942 -p 46944:36944 \
    -v lthn-chain:/data -v lthn-wallet:/wallet \
    -e WALLET_PASSWORD=pass \
    lthn/staking-node

Built-in helpers:
  docker exec <name> /status.sh         — chain + wallet status
  docker exec <name> /wallet-address.sh — get wallet address

Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
Claude 2026-04-03 13:20:40 +01:00
parent e1292a6445
commit 3fd1af9824
No known key found for this signature in database
GPG key ID: AF404715446AEB41

View file

@ -0,0 +1,182 @@
# Lethean Staking Node — single container, no compose needed
# Runs daemon + wallet with PoS staking in one container.
#
# Build:
# docker build -f Dockerfile.staking-node -t lthn/staking-node .
#
# Run:
# docker run -d --name lthn-staker \
# -p 46941:36941 -p 46942:36942 -p 46944:36944 \
# -v lthn-chain:/data -v lthn-wallet:/wallet \
# lthn/staking-node
#
# Run with password:
# docker run -d --name lthn-staker \
# -e WALLET_PASSWORD=my-pass \
# -p 46941:36941 -p 46942:36942 -p 46944:36944 \
# -v lthn-chain:/data -v lthn-wallet:/wallet \
# lthn/staking-node
#
# Check status:
# docker exec lthn-staker /status.sh
#
# Get wallet address:
# docker exec lthn-staker /wallet-address.sh
#
# Ports:
# 36941 — Daemon RPC (chain queries)
# 36942 — P2P (open on router for full node)
# 36944 — Wallet RPC (balance, transfers)
FROM lthn/chain:testnet
RUN apt-get update && apt-get install -y --no-install-recommends \
curl supervisor bc \
&& rm -rf /var/lib/apt/lists/*
# Supervisor manages both daemon and wallet in one container
COPY <<'SUPERVISOR' /etc/supervisor/conf.d/lethean.conf
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0
loglevel=info
[program:daemon]
command=lethean-chain-node
--data-dir /data
--rpc-bind-ip 0.0.0.0
--rpc-bind-port 36941
--p2p-bind-port 36942
--rpc-enable-admin-api
--allow-local-ip
--log-level %(ENV_DAEMON_LOG_LEVEL)s
--disable-upnp
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:wallet]
command=/start-wallet.sh
autorestart=true
startsecs=30
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
SUPERVISOR
# Wallet startup script — waits for daemon, creates wallet if needed
COPY <<'WALLETSH' /start-wallet.sh
#!/bin/bash
set -e
WALLET_FILE="/wallet/staker.wallet"
WALLET_PASS="${WALLET_PASSWORD:-}"
DAEMON="127.0.0.1:36941"
# Wait for daemon RPC
echo "[wallet] Waiting for daemon..."
until curl -sf "http://$DAEMON/json_rpc" \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "[wallet] Daemon ready"
# Create wallet if it doesn't exist
if [ ! -f "$WALLET_FILE" ]; then
echo "[wallet] Creating new wallet..."
echo "$WALLET_PASS" | lethean-wallet-cli \
--generate-new-wallet "$WALLET_FILE" \
--password "$WALLET_PASS" \
--daemon-address "$DAEMON" \
--command exit
echo "[wallet] Wallet created"
fi
# Start wallet with PoS staking
exec lethean-wallet-cli \
--wallet-file "$WALLET_FILE" \
--password "$WALLET_PASS" \
--daemon-address "$DAEMON" \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
WALLETSH
# Status helper — shows chain + wallet in one command
COPY <<'STATUSSH' /status.sh
#!/bin/bash
echo "=== Lethean Staking Node ==="
echo ""
# Chain
INFO=$(curl -sf http://127.0.0.1:36941/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' \
-H 'Content-Type: application/json' 2>/dev/null)
if [ -n "$INFO" ]; then
echo "$INFO" | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
hf=d.get('is_hardfok_active',[])
active=sum(1 for h in hf if h)
print(f'Chain:')
print(f' Height: {d[\"height\"]:,}')
print(f' Hardforks: HF0-{active-1}')
print(f' PoW diff: {d.get(\"pow_difficulty\",0):,}')
print(f' Aliases: {d.get(\"alias_count\",0)}')
print(f' Peers in: {d.get(\"incoming_connections_count\",0)}')
print(f' Peers out: {d.get(\"outgoing_connections_count\",0)}')
print(f' Status: {d[\"status\"]}')
" 2>/dev/null
else
echo "Chain: starting..."
fi
echo ""
# Wallet
BAL=$(curl -sf http://127.0.0.1:36944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' \
-H 'Content-Type: application/json' 2>/dev/null)
if [ -n "$BAL" ]; then
echo "$BAL" | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(f'Wallet:')
print(f' Balance: {d[\"balance\"]/1e12:.4f} LTHN')
print(f' Unlocked: {d[\"unlocked_balance\"]/1e12:.4f} LTHN')
print(f' Staking: yes (PoS mining active)')
" 2>/dev/null
else
echo "Wallet: syncing..."
fi
STATUSSH
# Wallet address helper
COPY <<'ADDRSH' /wallet-address.sh
#!/bin/bash
curl -sf http://127.0.0.1:36944/json_rpc \
-d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' \
-H 'Content-Type: application/json' | python3 -c "
import sys,json
d=json.load(sys.stdin)['result']
print(d['address'])
" 2>/dev/null || echo "Wallet not ready yet — daemon still syncing"
ADDRSH
RUN chmod +x /start-wallet.sh /status.sh /wallet-address.sh
ENV DAEMON_LOG_LEVEL=1
ENV WALLET_PASSWORD=
EXPOSE 36941 36942 36944
VOLUME ["/data", "/wallet"]
ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/conf.d/lethean.conf"]