#!/usr/bin/env python3 """ Validate config/pmm-soak-wallet-grid.json: dimensions, linearIndex formula, addresses, cellId, label vs networkCode/asn. Exit 0 if OK; non-zero with message on stderr. """ from __future__ import annotations import json import re import sys from pathlib import Path _REPO_LIB = Path(__file__).resolve().parent if str(_REPO_LIB) not in sys.path: sys.path.insert(0, str(_REPO_LIB)) from elemental_imperium_wallet_common import build_label, cell_id, linear_index # noqa: E402 ADDR = re.compile(r"^0x[0-9a-fA-F]{40}$") MAX_ERRORS = 80 def main() -> int: repo_root = Path(__file__).resolve().parents[2] grid_path = repo_root / "config" / "pmm-soak-wallet-grid.json" if not grid_path.is_file(): print("Missing config/pmm-soak-wallet-grid.json", file=sys.stderr) return 1 data = json.loads(grid_path.read_text(encoding="utf-8")) dim = data.get("dimensions") or {} lp_n = int(dim.get("lpbcaCount", 33)) br_n = int(dim.get("branchCount", 33)) cl_n = int(dim.get("classCount", 6)) expected_count = lp_n * br_n * cl_n wallets = data.get("wallets") if not isinstance(wallets, list): print("Invalid: wallets must be an array", file=sys.stderr) return 1 errs: list[str] = [] if len(wallets) != expected_count: errs.append(f"wallet count {len(wallets)} != dimensions product {expected_count}") for i, w in enumerate(wallets): if len(errs) >= MAX_ERRORS: errs.append("… (further errors suppressed)") break try: lpbca = int(w["lpbca"]) branch = int(w["branch"]) class_ = int(w["class"]) li = int(w["linearIndex"]) except (KeyError, TypeError, ValueError) as e: errs.append(f"wallet {i}: bad coordinates or linearIndex ({e})") continue if not (0 <= lpbca < lp_n and 0 <= branch < br_n and 0 <= class_ < cl_n): errs.append(f"wallet {i}: coordinate out of range") exp_li = linear_index(lpbca, branch, class_) if li != exp_li: errs.append(f"wallet {i}: linearIndex {li} != expected {exp_li} (L{lpbca} B{branch} C{class_})") exp_cid = cell_id(lpbca, branch, class_) if w.get("cellId") != exp_cid: errs.append(f"wallet {i}: cellId {w.get('cellId')!r} != {exp_cid!r}") addr = w.get("address", "") if not isinstance(addr, str) or not ADDR.match(addr): errs.append(f"wallet {i}: invalid address {addr!r}") nc = w.get("networkCode") if nc is not None and (not isinstance(nc, str) or not nc.strip()): errs.append(f"wallet {i}: invalid networkCode") asn = w.get("asn") if asn is not None and type(asn) is not int: errs.append(f"wallet {i}: asn must be int or null") if nc is not None: exp_label = build_label(str(nc), exp_cid, asn if isinstance(asn, int) else None) if w.get("label") != exp_label: errs.append( f"wallet {i}: label {w.get('label')!r} != expected {exp_label!r}" ) if errs: print("Elemental Imperium wallet grid validation failed:", file=sys.stderr) for e in errs: print(f" {e}", file=sys.stderr) return 1 print(f"OK: {len(wallets)} wallets, linearIndex/cellId/labels consistent") return 0 if __name__ == "__main__": raise SystemExit(main())