2026-04-03 13:20:40 +01:00
|
|
|
# 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
|
2026-04-03 13:53:07 +01:00
|
|
|
--rpc-ignore-offline
|
2026-04-03 13:20:40 +01:00
|
|
|
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"]
|