#!/usr/bin/env bash # End-to-End (E2E) Test for Public RPC Nodes # Tests DNS → Network → Service → RPC API functionality set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # Configuration PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}" SSH_KEY="${SSH_KEY:-~/.ssh/id_ed25519_proxmox}" 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_test() { echo -e "${CYAN}[TEST]${NC} $1"; } # Test counters TESTS_PASSED=0 TESTS_FAILED=0 TESTS_WARN=0 # Public RPC Endpoints to Test declare -A PUBLIC_RPC_ENDPOINTS=( # d-bis.org domain ["rpc-http-pub.d-bis.org"]="VMID 2502 (Public RPC - HTTP)" ["rpc-ws-pub.d-bis.org"]="VMID 2502 (Public RPC - WebSocket)" # defi-oracle.io domain ["rpc.public-0138.defi-oracle.io"]="VMID 2400 (ThirdWeb RPC)" ) # Direct node tests (internal) declare -A DIRECT_NODES=( ["192.168.11.252:8545"]="VMID 2502 (Direct HTTP)" ["192.168.11.240:8545"]="VMID 2400 (ThirdWeb Direct HTTP)" ) echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ PUBLIC RPC NODES - END-TO-END TEST ║${NC}" echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}" echo "" # Function to test DNS resolution test_dns() { local domain=$1 local description=$2 log_test "DNS Resolution: $domain" local ip=$(dig +short "$domain" | head -1 || echo "") if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then log_success " DNS resolves to: $ip" ((TESTS_PASSED++)) return 0 else log_error " DNS resolution failed or invalid IP: $ip" ((TESTS_FAILED++)) return 1 fi } # Function to test port connectivity test_port() { local host=$1 local port=$2 local description=$3 log_test "Port Connectivity: $host:$port ($description)" if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$host/$port" 2>/dev/null; then log_success " Port $port is open and accessible" ((TESTS_PASSED++)) return 0 else log_error " Port $port is not accessible" ((TESTS_FAILED++)) return 1 fi } # Function to test HTTP RPC endpoint test_http_rpc() { local url=$1 local description=$2 log_test "HTTP RPC: $url ($description)" local response=$(curl -s -m 10 -X POST "$url" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' 2>&1 || echo "ERROR") if echo "$response" | grep -q "\"result\""; then local block_num=$(echo "$response" | grep -oP '"result":"\K[^"]+' || echo "") log_success " RPC responding - Block Number: $block_num" ((TESTS_PASSED++)) return 0 else log_error " RPC request failed" log_error " Response: $(echo "$response" | head -3 | tr '\n' ' ')" ((TESTS_FAILED++)) return 1 fi } # Function to test RPC chainId test_chain_id() { local url=$1 local expected_chain_id=$2 local description=$3 log_test "Chain ID Check: $url (expected: $expected_chain_id)" local response=$(curl -s -m 10 -X POST "$url" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' 2>&1 || echo "ERROR") local chain_id=$(echo "$response" | grep -oP '"result":"\K[^"]+' || echo "") if [ "$chain_id" = "$expected_chain_id" ]; then log_success " Chain ID correct: $chain_id" ((TESTS_PASSED++)) return 0 else log_warn " Chain ID mismatch: got $chain_id, expected $expected_chain_id" ((TESTS_WARN++)) return 1 fi } # Function to test WebSocket (if enabled) test_websocket() { local url=$1 local description=$2 log_test "WebSocket RPC: $url ($description)" # Check if WebSocket port is accessible (wss:// or ws://) local ws_url=$(echo "$url" | sed 's|https://|wss://|' | sed 's|http://|ws://|' | sed 's|rpc-http|rpc-ws|' || echo "") if [ -z "$ws_url" ]; then log_warn " WebSocket URL could not be determined" ((TESTS_WARN++)) return 1 fi log_info " Testing WebSocket: $ws_url" log_warn " WebSocket testing requires specialized tools (beyond curl)" log_warn " Manual testing recommended: Use WebSocket client or wscat" ((TESTS_WARN++)) return 0 } # Function to check service status on container check_container_service() { local vmid=$1 local service=$2 local description=$3 log_test "Container Service: VMID $vmid ($description)" if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i "${SSH_KEY/#\~/$HOME}" "root@${PROXMOX_HOST}" "pct status $vmid 2>&1 | grep -q running" 2>/dev/null; then log_error " Container $vmid is not running" ((TESTS_FAILED++)) return 1 fi local status=$(ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no -i "${SSH_KEY/#\~/$HOME}" "root@${PROXMOX_HOST}" "pct exec $vmid -- systemctl is-active $service 2>&1" || echo "unknown") if [ "$status" = "active" ]; then log_success " Service is active" ((TESTS_PASSED++)) return 0 else log_error " Service status: $status" ((TESTS_FAILED++)) return 1 fi } # Phase 1: DNS Resolution Tests echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Phase 1: DNS Resolution Tests${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" for domain in "${!PUBLIC_RPC_ENDPOINTS[@]}"; do description="${PUBLIC_RPC_ENDPOINTS[$domain]}" test_dns "$domain" "$description" echo "" done # Phase 2: Port Connectivity Tests echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Phase 2: Port Connectivity Tests${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" for domain in "${!PUBLIC_RPC_ENDPOINTS[@]}"; do description="${PUBLIC_RPC_ENDPOINTS[$domain]}" ip=$(dig +short "$domain" | head -1 || echo "") if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then # HTTPS port 443 test_port "$ip" "443" "$description (HTTPS)" echo "" fi done # Test direct node ports for node in "${!DIRECT_NODES[@]}"; do description="${DIRECT_NODES[$node]}" IFS=':' read -r ip port <<< "$node" test_port "$ip" "$port" "$description" echo "" done # Phase 3: HTTP RPC Endpoint Tests echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Phase 3: HTTP RPC Endpoint Tests${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" for domain in "${!PUBLIC_RPC_ENDPOINTS[@]}"; do description="${PUBLIC_RPC_ENDPOINTS[$domain]}" # Skip WebSocket-only domains for HTTP tests if [[ "$domain" == *"ws"* ]]; then continue fi url="https://$domain" test_http_rpc "$url" "$description" echo "" # Test chain ID (ChainID 138 = 0x8a in hex) test_chain_id "$url" "0x8a" "$description" echo "" done # Test direct HTTP endpoints for node in "${!DIRECT_NODES[@]}"; do description="${DIRECT_NODES[$node]}" IFS=':' read -r ip port <<< "$node" url="http://$ip:$port" test_http_rpc "$url" "$description" echo "" test_chain_id "$url" "0x8a" "$description" echo "" done # Phase 4: Container Service Status echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Phase 4: Container Service Status${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" check_container_service "2502" "besu-rpc.service" "Public RPC (d-bis.org)" echo "" check_container_service "2400" "besu-rpc.service" "ThirdWeb RPC (defi-oracle.io)" echo "" # Phase 5: Advanced RPC Method Tests echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Phase 5: Advanced RPC Method Tests${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" # Test public HTTP endpoint with multiple methods PUBLIC_HTTP="https://rpc-http-pub.d-bis.org" log_test "Testing multiple RPC methods on $PUBLIC_HTTP" echo "" # Test eth_syncing log_info " Testing eth_syncing..." response=$(curl -s -m 10 -X POST "$PUBLIC_HTTP" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' 2>&1 || echo "ERROR") if echo "$response" | grep -q "\"result\""; then log_success " eth_syncing: OK" ((TESTS_PASSED++)) else log_warn " eth_syncing: Failed or error" ((TESTS_WARN++)) fi # Test net_version log_info " Testing net_version..." response=$(curl -s -m 10 -X POST "$PUBLIC_HTTP" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}' 2>&1 || echo "ERROR") if echo "$response" | grep -q "\"result\""; then version=$(echo "$response" | grep -oP '"result":"\K[^"]+' || echo "") log_success " net_version: $version" ((TESTS_PASSED++)) else log_warn " net_version: Failed" ((TESTS_WARN++)) fi # Test web3_clientVersion (if available) log_info " Testing web3_clientVersion..." response=$(curl -s -m 10 -X POST "$PUBLIC_HTTP" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"web3_clientVersion","params":[],"id":1}' 2>&1 || echo "ERROR") if echo "$response" | grep -q "\"result\""; then client=$(echo "$response" | grep -oP '"result":"\K[^"]+' | head -c 50 || echo "") log_success " web3_clientVersion: ${client}..." ((TESTS_PASSED++)) else log_warn " web3_clientVersion: Not available or failed" ((TESTS_WARN++)) fi echo "" # Summary echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}E2E Test Summary${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" TOTAL_TESTS=$((TESTS_PASSED + TESTS_FAILED + TESTS_WARN)) echo "Tests passed: $TESTS_PASSED" echo "Tests failed: $TESTS_FAILED" echo "Warnings: $TESTS_WARN" echo "Total tests: $TOTAL_TESTS" echo "" if [ "$TESTS_FAILED" -eq 0 ]; then if [ "$TESTS_WARN" -eq 0 ]; then log_success "✅ All E2E tests passed!" echo "" echo "Public RPC endpoints are fully functional:" echo " ✅ DNS resolution working" echo " ✅ Port connectivity confirmed" echo " ✅ RPC endpoints responding" echo " ✅ Services running correctly" exit 0 else log_warn "⚠️ E2E tests completed with warnings" echo "" echo "Public RPC endpoints are functional but some checks had warnings." echo "Review warnings above for details." exit 0 fi else log_error "❌ E2E tests found failures" echo "" echo "Some public RPC endpoints are not fully functional." echo "Review failed tests above and take corrective action." exit 1 fi