Files
zeekayandHanzo Dev af132289b2 fix(lux-test-k8s): quorum 2-of-3 is below the 2/3 BFT bound — raise to 3
floor(2n/3)+1 for n=3 is 3. Sample 3 / quorum 2 lets one equivocating node
finalize conflicting blocks across two 2-node partitions. Same safety law as
the 5-node fleets (sample 5 / quorum 4, which is correct and must never be
lowered).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 09:23:04 -07:00

113 lines
4.8 KiB
YAML

apiVersion: v1
kind: ConfigMap
metadata:
name: luxd-startup
namespace: testnet
data:
startup.sh: |
#!/bin/sh
set -e
POD_INDEX=${HOSTNAME##*-}
echo "=== luxd startup for $HOSTNAME (network-id=2, testnet) ==="
# Copy staking keys from secret
IDX=${HOSTNAME##*-}
mkdir -p /data/staking
if [ -f "/staking-keys/staker-${IDX}.crt" ]; then
cp /staking-keys/staker-${IDX}.crt /data/staking/staker.crt
cp /staking-keys/staker-${IDX}.key /data/staking/staker.key
if [ -f "/staking-keys/signer-${IDX}.key" ]; then
cp /staking-keys/signer-${IDX}.key /data/staking/signer.key
else
rm -f /data/staking/signer.key
fi
echo "[STAKING] Keys copied from secret for index ${IDX}"
elif [ -f "/data/staking/staker.crt" ]; then
rm -f /data/staking/signer.key
echo "[STAKING] Using existing keys on PVC for index ${IDX}"
else
echo "[STAKING] No keys found, generating new keypair for index ${IDX}"
openssl ecparam -genkey -name prime256v1 -out /data/staking/staker.key 2>/dev/null
printf "[req]\ndistinguished_name=dn\n[dn]\n" > /tmp/openssl.cnf
openssl req -new -x509 -key /data/staking/staker.key -out /data/staking/staker.crt \
-sha256 -days 36500 -nodes -set_serial 0 -subj "/" \
-config /tmp/openssl.cnf 2>/dev/null
rm -f /data/staking/signer.key
echo "[STAKING] Generated new keypair for index ${IDX}"
fi
echo "[STAKING] Keys ready for index ${IDX}"
# Copy plugins from image
mkdir -p /data/plugins
if [ -d /luxd/build/plugins ] && ls /luxd/build/plugins/* >/dev/null 2>&1; then
for f in /luxd/build/plugins/*; do
dest="/data/plugins/$(basename $f)"
if [ ! -f "$dest" ]; then
cp "$f" "$dest"
echo "[PLUGINS] Copied $(basename $f) from image"
else
echo "[PLUGINS] Keeping existing $(basename $f)"
fi
done
fi
ls -la /data/plugins/ 2>/dev/null || echo "[PLUGINS] No plugins directory"
# Bootstrap nodes (discover from headless service)
BOOTSTRAP_NODES="luxd-0.luxd-headless.testnet.svc.cluster.local:9651,luxd-1.luxd-headless.testnet.svc.cluster.local:9651,luxd-2.luxd-headless.testnet.svc.cluster.local:9651"
# --- Public IP: the pod IP, and only the pod IP ---
# The staking mesh is cluster-internal, so a pod IP is the only address a
# peer can dial. The k8s-API LoadBalancer-ingress lookup that used to live
# here POISONED lux-mainnet: svc/luxd-N were flipped LoadBalancer ->
# ClusterIP, but the pods that had booted while the LB ingress IPs were
# still published signed and gossiped those IPs. luxd's ipTracker replaces
# a configured bootstrap endpoint with the peer's signed IP, so every node
# then dialled a blackholed address and the mesh could not heal -- measured
# 2/3/4/1/2 of 4 peers, C-Chain accepting on ONE of five validators.
# lux-devnet and lux-testnet advertise the pod IP and hold 4/4 each.
# One way, every net.
PUBLIC_IP=$(hostname -i | awk '{print $1}')
echo "[IP] Pod: $PUBLIC_IP"
# luxd arguments
ARGS="--network-id=2"
ARGS="$ARGS --http-host=0.0.0.0 --http-port=9650 --http-allowed-hosts=*"
ARGS="$ARGS --staking-port=9651"
ARGS="$ARGS --data-dir=/data --db-type=zapdb"
ARGS="$ARGS --index-enabled=true"
ARGS="$ARGS --api-admin-enabled=true --api-metrics-enabled=true --api-keystore-enabled=true"
ARGS="$ARGS --log-level=info"
ARGS="$ARGS --plugin-dir=/data/plugins"
ARGS="$ARGS --staking-tls-cert-file=/data/staking/staker.crt"
ARGS="$ARGS --staking-tls-key-file=/data/staking/staker.key"
[ -f "/data/staking/signer.key" ] && ARGS="$ARGS --staking-signer-key-file=/data/staking/signer.key"
ARGS="$ARGS --network-compression-type=zstd"
# BFT: alpha must be a STRICT 2/3 majority — floor(2n/3)+1. For n=3 that
# is 3, not 2: quorum 2-of-3 lets two partitions finalize conflicting
# blocks with one equivocating node. Same safety law as the 5-node fleets
# (sample 5 / quorum 4). Never lower this to buy liveness.
ARGS="$ARGS --consensus-sample-size=3 --consensus-quorum-size=3"
ARGS="$ARGS --sybil-protection-enabled=true"
ARGS="$ARGS --network-require-validator-to-connect=false --network-allow-private-ips=true"
ARGS="$ARGS --genesis-file=/etc/lux/genesis/genesis.json"
ARGS="$ARGS --track-all-chains=true"
[ -n "$PUBLIC_IP" ] && ARGS="$ARGS --public-ip=$PUBLIC_IP"
[ -n "$BOOTSTRAP_NODES" ] && ARGS="$ARGS --bootstrap-nodes=$BOOTSTRAP_NODES"
echo "[START] luxd ${ARGS}" | head -c 200
echo ""
/luxd/build/luxd $ARGS &
LUXD_PID=$!
set +e
i=0
while [ "$i" -lt 180 ]; do
curl -sf -m 2 http://127.0.0.1:9650/v1/health >/dev/null 2>&1 && echo "[HEALTHY] after ${i}s" && break
i=$((i + 1))
sleep 1
done
wait "$LUXD_PID"