mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-utils.git
synced 2026-04-22 05:38:01 +00:00
fix: implement blacklist filtering for broken RPC chains
- Add blocked-chains.json with DNS-failing endpoints (AlephZero, InvArch, Quartz, Passet Hub Testnet) - Update merge-chains.py to filter PAUSED chains, testnets (except Pezkuwi), and broken RPCs - Reduce chain count from 102 to 86 (4 Pezkuwi + 82 working Nova chains) - This fixes staking page not loading due to DNS resolution failures
This commit is contained in:
+152
-27
@@ -3,14 +3,17 @@
|
||||
Pezkuwi Wallet Chain Config Merger
|
||||
|
||||
This script merges Nova's chain configurations with Pezkuwi-specific chains.
|
||||
Nova configs are used as the base, Pezkuwi chains are prepended (priority).
|
||||
Uses a blacklist to exclude broken/paused chains.
|
||||
|
||||
Usage:
|
||||
python3 merge-chains.py [--version v22] [--output chains/v22/chains.json]
|
||||
python3 merge-chains.py [--version v22] [--full] [--update]
|
||||
|
||||
Options:
|
||||
--full Include ALL Nova chains (including broken ones) - NOT recommended
|
||||
--update Update Nova submodule first
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
@@ -21,6 +24,26 @@ NOVA_BASE = ROOT_DIR / "nova-base"
|
||||
PEZKUWI_OVERLAY = ROOT_DIR / "pezkuwi-overlay"
|
||||
OUTPUT_DIR = ROOT_DIR / "chains"
|
||||
|
||||
# Chains with known broken RPC endpoints
|
||||
BROKEN_CHAIN_KEYWORDS = [
|
||||
'aleph zero',
|
||||
'alephzero',
|
||||
'quartz',
|
||||
'invarch',
|
||||
]
|
||||
|
||||
# These chains have broken endpoints or are not useful
|
||||
EXCLUDED_CHAIN_IDS = {
|
||||
# AlephZero - DNS failures
|
||||
'70255b4d28de0fc4e1a193d7e175ad1ccef431598211c55538f1018651a0344e',
|
||||
# Quartz - DNS failures
|
||||
'cd4d732201ebe5d6b014edda071c4203e16867305332f43c2e25ae6c9a1b7e6f',
|
||||
# InvArch - PAUSED
|
||||
'31a7d8914fb31c249b972f18c115f1e22b4b039abbcb03c73b6774c5642f9efe',
|
||||
# Aleph Zero EVM - PAUSED
|
||||
'eip155:41455',
|
||||
}
|
||||
|
||||
|
||||
def load_json(path: Path) -> list | dict:
|
||||
"""Load JSON file."""
|
||||
@@ -36,29 +59,104 @@ def save_json(path: Path, data: list | dict, indent: int = 2):
|
||||
print(f"✓ Saved: {path}")
|
||||
|
||||
|
||||
def merge_chains(nova_chains: list, pezkuwi_chains: list) -> list:
|
||||
def is_chain_excluded(chain: dict) -> tuple[bool, str]:
|
||||
"""
|
||||
Check if a chain should be excluded.
|
||||
|
||||
Returns:
|
||||
(excluded: bool, reason: str)
|
||||
"""
|
||||
chain_id = chain.get('chainId', '')
|
||||
name = chain.get('name', '')
|
||||
options = chain.get('options', [])
|
||||
|
||||
# Check explicit exclusion list
|
||||
if chain_id in EXCLUDED_CHAIN_IDS:
|
||||
return True, "broken RPC"
|
||||
|
||||
# Check for PAUSED chains
|
||||
if 'PAUSED' in name:
|
||||
return True, "PAUSED"
|
||||
|
||||
# Check for testnets (but NOT Pezkuwi testnets)
|
||||
if 'testnet' in options and 'pezkuwi' not in name.lower() and 'zagros' not in name.lower():
|
||||
return True, "testnet"
|
||||
|
||||
# Check for broken chain keywords
|
||||
name_lower = name.lower()
|
||||
for keyword in BROKEN_CHAIN_KEYWORDS:
|
||||
if keyword in name_lower:
|
||||
return True, f"broken ({keyword})"
|
||||
|
||||
return False, ""
|
||||
|
||||
|
||||
def merge_chains(nova_chains: list, pezkuwi_chains: list, filter_broken: bool = True) -> tuple[list, dict]:
|
||||
"""
|
||||
Merge Nova and Pezkuwi chains.
|
||||
Pezkuwi chains are prepended to appear first in the wallet.
|
||||
Duplicate chainIds are handled (Pezkuwi takes priority).
|
||||
|
||||
Args:
|
||||
nova_chains: Nova's chain list
|
||||
pezkuwi_chains: Pezkuwi's chain list
|
||||
filter_broken: Whether to filter out broken chains
|
||||
|
||||
Returns:
|
||||
(merged_list, stats_dict)
|
||||
"""
|
||||
# Create a set of Pezkuwi chain IDs to avoid duplicates
|
||||
pezkuwi_chain_ids = {c['chainId'] for c in pezkuwi_chains}
|
||||
|
||||
# Filter out any Nova chains that might conflict with Pezkuwi
|
||||
nova_filtered = [c for c in nova_chains if c['chainId'] not in pezkuwi_chain_ids]
|
||||
stats = {
|
||||
'pezkuwi': len(pezkuwi_chains),
|
||||
'nova_total': len(nova_chains),
|
||||
'nova_included': 0,
|
||||
'excluded_paused': 0,
|
||||
'excluded_testnet': 0,
|
||||
'excluded_broken': 0,
|
||||
'excluded_duplicate': 0,
|
||||
}
|
||||
|
||||
nova_filtered = []
|
||||
excluded_chains = []
|
||||
|
||||
for chain in nova_chains:
|
||||
chain_id = chain.get('chainId', '')
|
||||
|
||||
# Skip duplicates
|
||||
if chain_id in pezkuwi_chain_ids:
|
||||
stats['excluded_duplicate'] += 1
|
||||
continue
|
||||
|
||||
# Check if should be excluded
|
||||
if filter_broken:
|
||||
excluded, reason = is_chain_excluded(chain)
|
||||
if excluded:
|
||||
excluded_chains.append((chain.get('name', 'Unknown'), reason))
|
||||
if 'PAUSED' in reason:
|
||||
stats['excluded_paused'] += 1
|
||||
elif 'testnet' in reason:
|
||||
stats['excluded_testnet'] += 1
|
||||
else:
|
||||
stats['excluded_broken'] += 1
|
||||
continue
|
||||
|
||||
nova_filtered.append(chain)
|
||||
stats['nova_included'] += 1
|
||||
|
||||
# Pezkuwi first, then Nova
|
||||
merged = pezkuwi_chains + nova_filtered
|
||||
stats['total'] = len(merged)
|
||||
stats['excluded_list'] = excluded_chains
|
||||
|
||||
return merged
|
||||
return merged, stats
|
||||
|
||||
|
||||
def merge_version(version: str = "v22"):
|
||||
def merge_version(version: str = "v22", filter_broken: bool = True):
|
||||
"""Merge chains for a specific version."""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Merging chains for {version}")
|
||||
print(f"{'='*50}")
|
||||
print(f"Mode: {'FILTERED (exclude broken)' if filter_broken else 'FULL (all chains)'}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# Paths
|
||||
nova_chains_path = NOVA_BASE / "chains" / version / "chains.json"
|
||||
@@ -68,16 +166,15 @@ def merge_version(version: str = "v22"):
|
||||
# Check if Nova chains exist
|
||||
if not nova_chains_path.exists():
|
||||
print(f"⚠ Nova chains not found: {nova_chains_path}")
|
||||
# Try root level chains.json
|
||||
nova_chains_path = NOVA_BASE / "chains" / "chains.json"
|
||||
if not nova_chains_path.exists():
|
||||
print(f"✗ Nova chains not found at root level either")
|
||||
return False
|
||||
|
||||
# Load Nova chains
|
||||
print(f"Loading Nova chains from: {nova_chains_path}")
|
||||
print(f"\nLoading Nova chains from: {nova_chains_path}")
|
||||
nova_chains = load_json(nova_chains_path)
|
||||
print(f" → {len(nova_chains)} Nova chains loaded")
|
||||
print(f" → {len(nova_chains)} Nova chains available")
|
||||
|
||||
# Load Pezkuwi chains
|
||||
if not pezkuwi_chains_path.exists():
|
||||
@@ -89,10 +186,26 @@ def merge_version(version: str = "v22"):
|
||||
print(f" → {len(pezkuwi_chains)} Pezkuwi chains loaded")
|
||||
|
||||
# Merge
|
||||
merged = merge_chains(nova_chains, pezkuwi_chains)
|
||||
print(f"\nMerged result: {len(merged)} total chains")
|
||||
print(f" - Pezkuwi chains: {len(pezkuwi_chains)} (priority)")
|
||||
print(f" - Nova chains: {len(merged) - len(pezkuwi_chains)}")
|
||||
merged, stats = merge_chains(nova_chains, pezkuwi_chains, filter_broken)
|
||||
|
||||
# Print stats
|
||||
print(f"\n{'─'*40}")
|
||||
print("📊 Merge Statistics:")
|
||||
print(f"{'─'*40}")
|
||||
print(f" Pezkuwi chains: {stats['pezkuwi']:3} (priority)")
|
||||
print(f" Nova available: {stats['nova_total']:3}")
|
||||
print(f" Nova included: {stats['nova_included']:3}")
|
||||
print(f"{'─'*40}")
|
||||
|
||||
if filter_broken:
|
||||
print(f" Excluded (PAUSED): {stats['excluded_paused']:3}")
|
||||
print(f" Excluded (testnet): {stats['excluded_testnet']:3}")
|
||||
print(f" Excluded (broken): {stats['excluded_broken']:3}")
|
||||
print(f" Excluded (dupes): {stats['excluded_duplicate']:3}")
|
||||
print(f"{'─'*40}")
|
||||
|
||||
print(f" TOTAL OUTPUT: {stats['total']:3} chains")
|
||||
print(f"{'─'*40}")
|
||||
|
||||
# Save
|
||||
save_json(output_path, merged)
|
||||
@@ -127,28 +240,40 @@ def main():
|
||||
parser = argparse.ArgumentParser(description="Merge Nova and Pezkuwi chain configs")
|
||||
parser.add_argument("--version", "-v", default="v22", help="Chain config version (default: v22)")
|
||||
parser.add_argument("--update", "-u", action="store_true", help="Update Nova submodule first")
|
||||
parser.add_argument("--full", "-f", action="store_true", help="Include ALL chains (no filtering)")
|
||||
parser.add_argument("--all", "-a", action="store_true", help="Merge all versions")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("╔══════════════════════════════════════════════════╗")
|
||||
print("║ Pezkuwi Wallet Chain Config Merger ║")
|
||||
print("╚══════════════════════════════════════════════════╝")
|
||||
print("╔════════════════════════════════════════════════════════════╗")
|
||||
print("║ Pezkuwi Wallet Chain Config Merger ║")
|
||||
print("║ Nova Base + Pezkuwi Overlay Architecture ║")
|
||||
print("╚════════════════════════════════════════════════════════════╝")
|
||||
|
||||
# Update Nova if requested
|
||||
if args.update:
|
||||
update_nova_submodule()
|
||||
|
||||
# Filter by default (unless --full specified)
|
||||
filter_broken = not args.full
|
||||
|
||||
# Merge
|
||||
if args.all:
|
||||
versions = ["v21", "v22"]
|
||||
for v in versions:
|
||||
merge_version(v)
|
||||
merge_version(v, filter_broken)
|
||||
else:
|
||||
merge_version(args.version)
|
||||
merge_version(args.version, filter_broken)
|
||||
|
||||
print("\n✓ Merge complete!")
|
||||
print("\nPezkuwi chains will appear FIRST in the wallet.")
|
||||
print("Nova ecosystem chains follow after Pezkuwi.")
|
||||
print("\n" + "="*60)
|
||||
print("✓ Merge complete!")
|
||||
print("="*60)
|
||||
|
||||
if filter_broken:
|
||||
print("\n📋 Filtered mode:")
|
||||
print(" - PAUSED chains excluded")
|
||||
print(" - Testnets excluded (except Pezkuwi)")
|
||||
print(" - Broken RPC chains excluded")
|
||||
print("\n💡 To include all 98 Nova chains, run with --full flag")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user