diff --git a/scripts/rpc-tester.sh b/scripts/rpc-tester.sh new file mode 100755 index 0000000..8fbc936 --- /dev/null +++ b/scripts/rpc-tester.sh @@ -0,0 +1,136 @@ +#!/bin/bash + +SEPOLIA_RPC=( + "https://sepolia.drpc.org" + "https://sepolia.gateway.tenderly.co" + "https://api.zan.top/eth-sepolia" + "https://rpc.sepolia.ethpandaops.io" + "https://ethereum-sepolia-rpc.publicnode.com" + "https://1rpc.io/sepolia" + "https://0xrpc.io/sep" + "https://eth-sepolia.api.onfinality.io/public" +) + +MORDOR_RPC=( + "https://0xrpc.io/mordor" + "https://geth-mordor.etc-network.info" + "https://rpc.mordor.etccooperative.org" +) + +show_help() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Options: + --chain Specify network: 'sepolia' or 'mordor'. If omitted, checks both. + --output Base directory to save results. Creates a subfolder with Unix Timestamp. + --rpcs Comma-separated list of custom RPC endpoints. + Disables default Sepolia/Mordor lists. + --help Show this help message. + +Example: + $0 --chain sepolia --output ./logs +EOF + exit 0 +} + +spinner() { + local pid=$1 + local net_name=$2 + local delay=0.1 + local spinstr='|/-\' + + tput civis + + while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do + local temp=${spinstr#?} + printf "\r [%c] Checking %s... " "$spinstr" "$net_name" + local spinstr=$temp${spinstr%"$temp"} + sleep $delay + done + printf " \r" + tput cnorm +} + +check_network() { + local name=$1 + shift + local rpcs=("$@") + local target_dir="${OUT_DIR:-/tmp}" + local tmp_file="${target_dir}/$(date +%s)_${name,,}" + + local max_len=0 + for e in "${rpcs[@]}"; do (( ${#e} > max_len )) && max_len=${#e}; done + [[ $max_len -lt 20 ]] && max_len=20 + + local total_width=$(( max_len + 32 )) + local line=$(printf "%.0s-" $(seq 1 $total_width)) + local header_fmt="| %-${max_len}s | %-12s | %-10s |\n" + + ( + for endpoint in "${rpcs[@]}"; do + res_b=$(curl -s -X POST -H "Content-Type: application/json" --max-time 10 \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' "$endpoint") + hex=$(echo "$res_b" | grep -o '"result":"[^"]*' | cut -d'"' -f4) + [[ -n "$hex" && "$hex" != "null" ]] && blk=$(printf "%d" "$hex") || blk="ERROR" + + res_l=$(curl -s -X POST -H "Content-Type: application/json" --max-time 10 \ + --data '{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1","toBlock":"0x2"}],"id":1}' "$endpoint") + echo "$res_l" | grep -q '"result"' && ev="YES" || ev="NO" + + echo "$endpoint|$blk|$ev" + done + ) > "$tmp_file" & + + local worker_pid=$! + + if [[ -z "$OUT_DIR" ]]; then + spinner $worker_pid "$name" + + local table_output="$line\n" + table_output+=$(printf "$header_fmt" "Endpoint" "Block" "Events")"\n" + table_output+="$line\n" + while IFS="|" read -r url blk ev; do + table_output+=$(printf "$header_fmt" "$url" "$blk" "$ev")"\n" + done < "$tmp_file" + table_output+="$line" + + echo -e "$table_output" + rm "$tmp_file" + else + wait $worker_pid + fi +} + +CHOSEN_CHAIN="" +BASE_OUT_DIR="" +CUSTOM_RPCS="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --help) show_help ;; + --chain) CHOSEN_CHAIN="$2"; shift 2 ;; + --output) BASE_OUT_DIR="$2"; shift 2 ;; + --rpcs) CUSTOM_RPCS="$2"; shift 2 ;; + *) echo "Unknown option: $1. Use --help for usage."; exit 1 ;; + esac +done + +if [[ -n "$BASE_OUT_DIR" ]]; then + OUT_DIR="${BASE_OUT_DIR}" + mkdir -p "$OUT_DIR" +fi + +if [[ -n "$CUSTOM_RPCS" ]]; then + IFS=',' read -r -a USER_RPC_ARRAY <<< "$CUSTOM_RPCS" + check_network "Custom" "${USER_RPC_ARRAY[@]}" +else + if [ "$CHOSEN_CHAIN" == "sepolia" ]; then + check_network "Sepolia" "${SEPOLIA_RPC[@]}" + elif [ "$CHOSEN_CHAIN" == "mordor" ]; then + check_network "Mordor" "${MORDOR_RPC[@]}" + else + check_network "Sepolia" "${SEPOLIA_RPC[@]}" + check_network "Mordor" "${MORDOR_RPC[@]}" + fi +fi