#!/usr/bin/env bash set -euo pipefail # Load IP configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true # Verify and Update Node Lists (static-nodes.json and permissioned-nodes.json) # Ensures each RPC node has unique enode with matching IP address # All enodes must be in both static-nodes.json and permissioned-nodes.json on all nodes set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_section() { echo -e "\n${CYAN}=== $1 ===${NC}"; } # Configuration paths STATIC_NODES_FILE="${1:-$PROJECT_ROOT/smom-dbis-138/config/static-nodes.json}" PERMISSIONED_NODES_FILE="${2:-$PROJECT_ROOT/smom-dbis-138-proxmox/config/permissioned-nodes.json}" # Expected RPC nodes with IPs (from ALL_VMIDS_ENDPOINTS.md) declare -A RPC_NODES=( # ThirdWeb RPC ["2400"]="${RPC_THIRDWEB_PRIMARY}" ["2401"]="${RPC_THIRDWEB_1:-${RPC_THIRDWEB_1:-${RPC_THIRDWEB_1:-${RPC_THIRDWEB_1:-192.168.11.241}}}}" ["2402"]="${RPC_THIRDWEB_2:-${RPC_THIRDWEB_2:-${RPC_THIRDWEB_2:-${RPC_THIRDWEB_2:-192.168.11.242}}}}" # Public/Permissioned RPC ["2500"]="${RPC_ALLTRA_1:-192.168.11.250}" ["2501"]="${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-${RPC_ALI_1:-192.168.11.251}}}}" ["2502"]="${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-${RPC_ALI_2:-192.168.11.252}}}}" ["2503"]="192.168.11.253" ["2504"]="192.168.11.254" # Named RPC ["2505"]="${IP_VAULT_PHOENIX_2:-192.168.11.201}" ["2506"]="192.168.11.202" ["2507"]="192.168.11.203" ["2508"]="192.168.11.204" # VMID 2101 (if exists) ["2101"]="${RPC_CORE_1}" ) # Validator nodes declare -A VALIDATOR_NODES=( ["1000"]="${IP_VALIDATOR_0:-${IP_VALIDATOR_0:-${IP_VALIDATOR_0:-${IP_VALIDATOR_0:-192.168.11.100}}}}" ["1001"]="${IP_VALIDATOR_1:-${IP_VALIDATOR_1:-${IP_VALIDATOR_1:-${IP_VALIDATOR_1:-192.168.11.101}}}}" ["1002"]="${IP_VALIDATOR_2:-${IP_VALIDATOR_2:-${IP_VALIDATOR_2:-${IP_VALIDATOR_2:-192.168.11.102}}}}" ["1003"]="${IP_VALIDATOR_3:-${IP_VALIDATOR_3:-${IP_VALIDATOR_3:-${IP_VALIDATOR_3:-192.168.11.103}}}}" ["1004"]="${IP_VALIDATOR_4:-${IP_VALIDATOR_4:-${IP_VALIDATOR_4:-${IP_VALIDATOR_4:-192.168.11.104}}}}" ) # Sentry nodes declare -A SENTRY_NODES=( ["1500"]="${IP_BESU_RPC_0:-${IP_BESU_RPC_0:-${IP_BESU_RPC_0:-${IP_BESU_RPC_0:-192.168.11.150}}}}" ["1501"]="${IP_BESU_RPC_1:-${IP_BESU_RPC_1:-${IP_BESU_RPC_1:-${IP_BESU_RPC_1:-192.168.11.151}}}}" ["1502"]="${IP_BESU_RPC_2:-${IP_BESU_RPC_2:-${IP_BESU_RPC_2:-${IP_BESU_RPC_2:-192.168.11.152}}}}" ["1503"]="${IP_BESU_RPC_3:-${IP_BESU_RPC_3:-${IP_BESU_RPC_3:-${IP_BESU_RPC_3:-192.168.11.153}}}}" ["1504"]="${IP_BESU_SENTRY:-192.168.11.154}" ) log_section "Node List Verification and Update" log_info "Static nodes file: $STATIC_NODES_FILE" log_info "Permissioned nodes file: $PERMISSIONED_NODES_FILE" log_info "" # Step 1: Verify files exist if [ ! -f "$STATIC_NODES_FILE" ]; then log_error "Static nodes file not found: $STATIC_NODES_FILE" exit 1 fi if [ ! -f "$PERMISSIONED_NODES_FILE" ]; then log_warn "Permissioned nodes file not found: $PERMISSIONED_NODES_FILE" log_info "Creating new permissioned nodes file..." mkdir -p "$(dirname "$PERMISSIONED_NODES_FILE")" echo "[]" > "$PERMISSIONED_NODES_FILE" fi # Step 2: Parse current enodes from static-nodes.json log_section "Step 1: Parsing Current Enodes" STATIC_ENODES=() while IFS= read -r line; do # Extract enode from JSON (handles quotes and commas) enode=$(echo "$line" | sed 's/^[[:space:]]*"\(.*\)",\?$/\1/' | grep -o 'enode://[^"]*' || true) if [ -n "$enode" ]; then STATIC_ENODES+=("$enode") # Extract IP from enode ip=$(echo "$enode" | sed -n 's/.*@\([0-9.]*\):.*/\1/p') # Extract node ID (first 128 chars after enode://) node_id=$(echo "$enode" | sed -n 's/enode:\/\/\([^@]*\).*/\1/p') log_info " Found: $ip -> $node_id" fi done < <(cat "$STATIC_NODES_FILE" | jq -r '.[]' 2>/dev/null || cat "$STATIC_NODES_FILE" | grep -o 'enode://[^"]*' 2>/dev/null || echo "") # Step 3: Check for duplicates and verify IP matching log_section "Step 2: Checking for Duplicates and IP Mismatches" declare -A ENODE_IPS=() declare -A IP_ENODES=() declare -A NODE_IDS=() DUPLICATES_FOUND=false IP_MISMATCHES=false for enode in "${STATIC_ENODES[@]}"; do if [ -z "$enode" ]; then continue fi # Extract components node_id=$(echo "$enode" | sed -n 's/enode:\/\/\([^@]*\).*/\1/p') ip=$(echo "$enode" | sed -n 's/.*@\([0-9.]*\):.*/\1/p') port=$(echo "$enode" | sed -n 's/.*:\([0-9]*\)$/\1/p') # Check for duplicate node IDs if [ -n "${NODE_IDS[$node_id]}" ]; then log_error "Duplicate node ID found: $node_id" log_error " First: ${NODE_IDS[$node_id]}" log_error " Duplicate: $enode" DUPLICATES_FOUND=true else NODE_IDS[$node_id]="$enode" fi # Check for duplicate IPs with different enodes if [ -n "${IP_ENODES[$ip]}" ] && [ "${IP_ENODES[$ip]}" != "$enode" ]; then log_error "IP $ip has multiple enodes:" log_error " ${IP_ENODES[$ip]}" log_error " $enode" IP_MISMATCHES=true else IP_ENODES[$ip]="$enode" ENODE_IPS[$enode]="$ip" fi done if [ "$DUPLICATES_FOUND" = false ] && [ "$IP_MISMATCHES" = false ]; then log_success "No duplicates or IP mismatches found in static-nodes.json" else log_error "Issues found - please review and fix" exit 1 fi # Step 4: Verify permissioned-nodes.json matches log_section "Step 3: Verifying Permissioned Nodes Match" PERMISSIONED_ENODES=() if command -v jq &> /dev/null; then while IFS= read -r enode; do if [ -n "$enode" ]; then PERMISSIONED_ENODES+=("$enode") fi done < <(jq -r '.[]' "$PERMISSIONED_NODES_FILE" 2>/dev/null || echo "") else # Fallback to grep if jq not available while IFS= read -r line; do enode=$(echo "$line" | grep -o 'enode://[^"]*' || true) if [ -n "$enode" ]; then PERMISSIONED_ENODES+=("$enode") fi done < <(cat "$PERMISSIONED_NODES_FILE" 2>/dev/null || echo "") fi # Compare static and permissioned lists STATIC_SORTED=$(printf '%s\n' "${STATIC_ENODES[@]}" | sort) PERMISSIONED_SORTED=$(printf '%s\n' "${PERMISSIONED_ENODES[@]}" | sort) if [ "$STATIC_SORTED" = "$PERMISSIONED_SORTED" ]; then log_success "static-nodes.json and permissioned-nodes.json match" else log_warn "static-nodes.json and permissioned-nodes.json differ" log_info "Updating permissioned-nodes.json to match static-nodes.json..." # Update permissioned-nodes.json to match static-nodes.json if command -v jq &> /dev/null; then cp "$STATIC_NODES_FILE" "$PERMISSIONED_NODES_FILE" log_success "Updated permissioned-nodes.json" else log_error "jq not available - cannot update permissioned-nodes.json" log_info "Please manually update permissioned-nodes.json to match static-nodes.json" fi fi # Step 5: Summary log_section "Summary" TOTAL_NODES=${#STATIC_ENODES[@]} log_info "Total enodes in static-nodes.json: $TOTAL_NODES" log_info "Total enodes in permissioned-nodes.json: ${#PERMISSIONED_ENODES[@]}" log_info "" log_info "Expected RPC nodes: ${#RPC_NODES[@]}" log_info "Expected Validator nodes: ${#VALIDATOR_NODES[@]}" log_info "Expected Sentry nodes: ${#SENTRY_NODES[@]}" log_info "" log_success "Verification complete!" log_info "" log_info "Next steps:" log_info "1. Ensure static-nodes.json is deployed to ALL nodes" log_info "2. Ensure permissioned-nodes.json is deployed to ALL nodes" log_info "3. Restart Besu services on all nodes to apply changes" log_info "4. Verify peer connections after restart"