#!/usr/bin/env python3
"""Reproducer: pursekeeper decision-436 claims "Nanswap and public nodes still
answer unkeyed" (in rebuttal of "my free work route is now the only free one").
Probe a fixed set of public/Nanswap endpoints with work_generate and record
whether each answers unkeyed. A second probe (block_count) distinguishes a
dead host from a live host that refuses work without a key.

Run: python3 reproduce_unkeyed_work.py
"""
import json, socket, ssl, urllib.request, urllib.error, time

HASH = "F68B9E8B7E1DB80747E611DF7712E79AB14F5AFFF313DF6E4681904704BA7EDA"
UA = {"Content-Type": "application/json", "User-Agent": "arion-item5-probe/1.0"}

ENDPOINTS = [
    # named in the claim
    ("nanswap-documented", "https://nodes.nanswap.com/XNO"),
    ("nanswap-legacy",     "https://node.nanswap.com"),
    # listed on pursekeeper sellers / no-node.md "nodes are listed at" set
    ("rpc.nano.to",        "https://rpc.nano.to"),
    ("nanoslo-proxy",      "https://nanoslo.0x.no/proxy"),
    ("nanoslo-node",       "https://nanoslo.0x.no/node"),
    ("somenano-node",      "https://node.somenano.com"),
    ("somenano-proxy",     "https://node.somenano.com/proxy"),
    ("rainstorm",          "https://rainstorm.city/api"),
    # other well-known public endpoints
    ("natrium-api",        "https://app.natrium.io/api"),
    ("mynano.ninja",       "https://mynano.ninja/api/node"),
    ("nanocafe",           "https://nanocafe.cc/api/node"),
    ("nanos.cc-proxy",     "https://nault.nanos.cc/proxy"),
    ("public.somenano",    "https://public.somenano.com"),
    ("nanoverse",          "https://nanoverse.io/api/node"),
    ("bytehosting",        "https://nano.bytehosting.cloud"),
]

def post(url, body, timeout=12):
    req = urllib.request.Request(url, data=json.dumps(body).encode(),
                                 headers=UA, method="POST")
    t0 = time.time()
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return r.status, time.time()-t0, r.read()[:400].decode("utf-8","replace")
    except urllib.error.HTTPError as e:
        return e.code, time.time()-t0, e.read()[:400].decode("utf-8","replace")
    except Exception as e:
        return 0, time.time()-t0, type(e).__name__ + ": " + str(e)[:120]

def main():
    print("hash under test:", HASH)
    print(f"{'endpoint':22} {'work_generate':38} {'block_count':30}")
    print("-"*96)
    unkeyed_work = []
    for name, url in ENDPOINTS:
        ws, _, wb = post(url, {"action": "work_generate", "hash": HASH})
        bs, _, bb = post(url, {"action": "block_count"})
        wsum = f"{ws} " + (wb or "")[:60]
        bsum = f"{bs} " + (bb or "")[:50]
        print(f"{name:22} {wsum:38} {bsum:30}")
        if ws == 200:
            try:
                if json.loads(wb).get("work"):
                    unkeyed_work.append(name)
            except Exception:
                pass
    print("-"*96)
    print("endpoints answering work_generate UNKEYED with a work value:", unkeyed_work or "NONE")

if __name__ == "__main__":
    main()
