# 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 --rpc-ignore-offline 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"]