#!/usr/bin/env bash # Check block production and run e2e for thirdweb and all chainlist RPC endpoints (Chain 138). # Usage: ./scripts/check-block-production-and-chainlist-e2e.sh # Optional: THIRDWEB_API_KEY=your_key (thirdweb RPC often requires key; rpc.d-bis.org / rpc.defi-oracle.io may be LAN/DNS-only) # If THIRDWEB_API_KEY is unset, the script sources smom-dbis-138/.env and uses THIRDWEB_CLIENT_ID as the key. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" CHAINLIST_FILE="${PROJECT_ROOT}/pr-workspace/chains/_data/chains/eip155-138.json" # Pick up Thirdweb key from dotenv if not set if [ -z "${THIRDWEB_API_KEY:-}" ] && [ -f "${PROJECT_ROOT}/smom-dbis-138/.env" ]; then set -a # shellcheck source=/dev/null source "${PROJECT_ROOT}/smom-dbis-138/.env" 2>/dev/null || true set +a [ -n "${THIRDWEB_CLIENT_ID:-}" ] && export THIRDWEB_API_KEY="${THIRDWEB_CLIENT_ID}" fi 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}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } log_section() { echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n${CYAN}$1${NC}\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"; } EXPECTED_CHAIN_ID_HEX="0x8a" EXPECTED_CHAIN_ID_DEC=138 BLOCK_WAIT_SEC=${BLOCK_WAIT_SEC:-6} RPC_TIMEOUT=${RPC_TIMEOUT:-15} # Build list of WebSocket RPC URLs from chainlist get_chainlist_ws_rpcs() { if [ ! -f "$CHAINLIST_FILE" ]; then echo "wss://rpc-ws-pub.d-bis.org" echo "wss://ws.rpc.d-bis.org" echo "wss://ws.rpc2.d-bis.org" echo "wss://rpc.public-0138.defi-oracle.io" echo "wss://wss.defi-oracle.io" return fi jq -r '.rpc[] | select(startswith("wss://"))' "$CHAINLIST_FILE" 2>/dev/null || true } # Build list of HTTP RPC URLs from chainlist (skip wss) get_chainlist_http_rpcs() { local api_key="${THIRDWEB_API_KEY:-}" if [ ! -f "$CHAINLIST_FILE" ]; then log_warn "Chainlist file not found: $CHAINLIST_FILE; using built-in list." echo "https://rpc-http-pub.d-bis.org" echo "https://rpc.d-bis.org" echo "https://rpc2.d-bis.org" echo "https://rpc.public-0138.defi-oracle.io" echo "https://rpc.defi-oracle.io" echo "https://defi-oracle-meta.rpc.thirdweb.com/${api_key}" echo "https://138.rpc.thirdweb.com/${api_key}" return fi jq -r '.rpc[] | select(startswith("http://") or startswith("https://"))' "$CHAINLIST_FILE" 2>/dev/null | while IFS= read -r u; do [ -z "$u" ] && continue echo "${u//\$\{THIRDWEB_API_KEY\}/$api_key}" done } # Single RPC call (JSON-RPC); prints response to stdout rpc_call() { local url=$1 local method=$2 local params=${3:-[]} curl -s -m "$RPC_TIMEOUT" -X POST "$url" \ -H "Content-Type: application/json" \ -d "{\"jsonrpc\":\"2.0\",\"method\":\"$method\",\"params\":$params,\"id\":1}" 2>/dev/null || echo '{"error":"request failed"}' } # Check block production: get block, wait, get again; at least one RPC must show advancing blocks check_block_production() { log_section "Block production check (wait ${BLOCK_WAIT_SEC}s between samples)" local rpcs=("https://rpc-http-pub.d-bis.org" "https://rpc.public-0138.defi-oracle.io" "https://rpc.d-bis.org") local any_ok=false for base_url in "${rpcs[@]}"; do local url="$base_url" log_info "Checking via $url ..." local resp1=$(rpc_call "$url" "eth_blockNumber") local block1_hex=$(echo "$resp1" | jq -r '.result // empty') if [ -z "$block1_hex" ]; then log_warn " No result from eth_blockNumber" continue fi local block1=$((block1_hex)) sleep "$BLOCK_WAIT_SEC" local resp2=$(rpc_call "$url" "eth_blockNumber") local block2_hex=$(echo "$resp2" | jq -r '.result // empty') [ -z "$block2_hex" ] && continue local block2=$((block2_hex)) if [ "$block2" -gt "$block1" ]; then log_success " Blocks advancing: $block1 → $block2" any_ok=true break else log_warn " Block unchanged at $block1 (may be slow or stalled)" fi done if [ "$any_ok" = true ]; then log_success "Block production check PASSED" return 0 else log_error "Block production check: no advancing blocks observed" return 1 fi } # E2E single endpoint: eth_chainId + eth_blockNumber e2e_one() { local url=$1 local label=${2:-$url} local chain_ok=false local block_ok=false local err_msg="" local chain_id=$(echo "$(rpc_call "$url" "eth_chainId")" | jq -r '.result // empty') if [ "$chain_id" = "$EXPECTED_CHAIN_ID_HEX" ] || [ "$chain_id" = "$EXPECTED_CHAIN_ID_DEC" ]; then chain_ok=true else err_msg="chainId=$chain_id (expected $EXPECTED_CHAIN_ID_HEX)" fi local block_resp=$(rpc_call "$url" "eth_blockNumber") local block_hex=$(echo "$block_resp" | jq -r '.result // empty') if [ -n "$block_hex" ]; then block_ok=true else [ -n "$err_msg" ] && err_msg="$err_msg; " || true err_msg="${err_msg}eth_blockNumber failed" fi if [ "$chain_ok" = true ] && [ "$block_ok" = true ]; then log_success "$label — chainId $chain_id, block $block_hex" return 0 else log_error "$label — $err_msg" return 1 fi } # Normalize URL: remove trailing slash normalize_url() { local u="$1" u="${u%/}" echo "$u" } # E2E single WebSocket endpoint (eth_chainId via verify-ws-rpc-chain138.mjs) e2e_ws_one() { local wss_url=$1 local label=${2:-$wss_url} if node "${SCRIPT_DIR}/verify-ws-rpc-chain138.mjs" "$wss_url" >/dev/null 2>&1; then log_success "$label — chainId 0x8a (WS)" return 0 else log_error "$label — WebSocket eth_chainId failed or timeout" return 1 fi } main() { echo "" log_section "Chain 138 — Block production & chainlist E2E" echo "Timestamp: $(date -Iseconds)" echo "" local block_ok=false if check_block_production; then block_ok=true fi echo "" log_section "E2E — All chainlist HTTP RPC endpoints (thirdweb + d-bis + defi-oracle)" local passed=0 local failed=0 while IFS= read -r line; do [ -z "$line" ] && continue url=$(normalize_url "$line") # Skip obviously invalid if [[ "$url" == *"undefined"* ]] || [[ "$url" == *"\${"* ]]; then log_warn "Skipping (unsubstituted): $line" continue fi if e2e_one "$url" "$url"; then ((passed++)) || true else ((failed++)) || true fi done < <(get_chainlist_http_rpcs) log_section "E2E — All chainlist WebSocket RPC endpoints" local ws_passed=0 local ws_failed=0 if [ -f "${SCRIPT_DIR}/verify-ws-rpc-chain138.mjs" ]; then while IFS= read -r wss_url; do [ -z "$wss_url" ] && continue if e2e_ws_one "$wss_url" "$wss_url"; then ((ws_passed++)) || true else ((ws_failed++)) || true fi done < <(get_chainlist_ws_rpcs) else log_warn "Skipping WebSocket E2E (verify-ws-rpc-chain138.mjs not found)." fi echo "" log_section "Summary" echo "Block production: $([ "$block_ok" = true ] && echo "PASSED" || echo "FAILED")" echo "HTTP E2E passed: $passed" echo "HTTP E2E failed: $failed" echo "WebSocket E2E passed: $ws_passed" echo "WebSocket E2E failed: $ws_failed" echo "" log_success "All requested checks completed." if [ "$block_ok" = true ] && [ "$failed" -eq 0 ]; then log_success "Result: block production + HTTP chainlist E2E passed." exit 0 fi if [ "$block_ok" = false ]; then log_error "Result: block production check failed." exit 2 fi log_warn "Result: some HTTP E2E endpoints failed ($failed)." exit 1 } main "$@"