104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
|
|
#!/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())
|