Dogfood public bootstrap peers as secondary reinject seed.

Add bootstrap-peers.sh and fall back to stakesquid.eu/bootstrap when local peerset capture is empty; optional --seed-bootstrap on connect-peers.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
rob
2026-07-19 08:56:52 +00:00
parent 6a19dc91e1
commit 9c6a4ab148
3 changed files with 176 additions and 7 deletions

View File

@@ -3,7 +3,14 @@
# Uses admin_addStaticPeer for geth, admin_addPeer otherwise (connect-peers.sh).
# In-network vantage (rpc_chains). Idempotent; best-effort (never fails the restart).
#
# Seed order (one path for us and customers):
# 1. Own persisted peerset (peer-state/<compose>.json from peer-capture)
# 2. Public bootstrap list https://stakesquid.eu/bootstrap/<network>.json
# (third-party enodes only — same JSON customers curl)
#
# Usage: peer-reinject.sh <compose-path>
# Env: PEER_BOOTSTRAP=0 to disable bootstrap fallback
# BOOTSTRAP_BASE_URL to override (default https://stakesquid.eu/bootstrap)
set -euo pipefail
COMPOSE_PATH="${1:-}"
@@ -18,6 +25,7 @@ SAFE="$(echo "$COMPOSE_PATH" | sed 's|[^a-zA-Z0-9._-]|_|g')"
STATE="$STATE_DIR/${SAFE}.json"
CURL_IMAGE="${PEER_CURL_IMAGE:-curlimages/curl:8.5.0}"
LOG="${PEER_HOOK_LOG:-/var/log/peer-hooks.log}"
USE_BOOTSTRAP="${PEER_BOOTSTRAP:-1}"
log() { echo "$(date '+%F %T') peer-reinject[$COMPOSE_PATH]: $*" | tee -a "$LOG" >&2; }
@@ -28,15 +36,35 @@ case "$COMPOSE_PATH" in
;;
esac
if [ ! -f "$STATE" ]; then
log "no capture state at $STATE — nothing to reinject"
exit 0
CLIENT_TYPE="unknown"
ENODES=()
SOURCE="none"
if [ -f "$STATE" ]; then
CLIENT_TYPE="$(jq -r '.client_type // "unknown"' "$STATE" 2>/dev/null || echo unknown)"
mapfile -t ENODES < <(jq -r '.peers[].id // empty' "$STATE" 2>/dev/null | grep -E '^enode://' | head -n 50 || true)
if [ "${#ENODES[@]}" -gt 0 ]; then
SOURCE="peerset"
fi
fi
# Secondary seed: public bootstrap API (same files customers use).
if [ "${#ENODES[@]}" -eq 0 ] && [ "$USE_BOOTSTRAP" != "0" ]; then
if [ -x "$BASEPATH/bootstrap-peers.sh" ]; then
mapfile -t ENODES < <("$BASEPATH/bootstrap-peers.sh" --from-compose "$COMPOSE_PATH" 2>/dev/null | grep -E '^enode://' | head -n 25 || true)
if [ "${#ENODES[@]}" -gt 0 ]; then
SOURCE="bootstrap"
log "no local peerset — using bootstrap fallback (${#ENODES[@]} enodes)"
fi
fi
fi
CLIENT_TYPE="$(jq -r '.client_type // "unknown"' "$STATE" 2>/dev/null || echo unknown)"
mapfile -t ENODES < <(jq -r '.peers[].id // empty' "$STATE" 2>/dev/null | grep -E '^enode://' | head -n 50 || true)
if [ "${#ENODES[@]}" -eq 0 ]; then
log "no enodes in $STATE"
if [ ! -f "$STATE" ]; then
log "no capture state at $STATE and bootstrap empty — nothing to reinject"
else
log "no enodes in $STATE and bootstrap empty"
fi
exit 0
fi
@@ -64,6 +92,11 @@ if [ -z "$EL" ]; then
fi
IP="$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$EL" 2>/dev/null || true)"
# Prefer rpc_chains IP when present
RPC_IP="$(docker inspect -f '{{(index .NetworkSettings.Networks "rpc_chains").IPAddress}}' "$EL" 2>/dev/null || true)"
if [ -n "$RPC_IP" ] && [ "$RPC_IP" != "<no value>" ]; then
IP="$RPC_IP"
fi
if [ -z "$IP" ]; then
log "no IP for $EL"
exit 0
@@ -134,5 +167,5 @@ COUNT="$(docker exec peer-hook-probe curl -s --max-time 8 -X POST \
"http://${IP}:8545" 2>/dev/null | jq -r '.result | length' 2>/dev/null || echo '?')"
docker rm -f peer-hook-probe >/dev/null 2>&1 || true
log "reinjected added=$ADDED fail=$FAIL now_peers=$COUNT (from ${#ENODES[@]} enodes)"
log "reinjected source=$SOURCE added=$ADDED fail=$FAIL now_peers=$COUNT (from ${#ENODES[@]} enodes)"
exit 0