Fred808 commited on
Commit
abce7f8
·
verified ·
1 Parent(s): dd95810

Upload 4 files

Browse files
Files changed (4) hide show
  1. node_list.py +8 -0
  2. requirements.txt +3 -0
  3. solo_miner.py +204 -0
  4. xmrig-config.json.template +25 -0
node_list.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # List of reliable public Monero nodes
2
+ PUBLIC_NODES = [
3
+ "https://node.moneroworld.com:18089",
4
+ "https://node.supportxmr.com:18089",
5
+ "https://node.xmr.ru:18081",
6
+ "https://node.c3pool.com:18089",
7
+ "https://node.xmr.to:18081"
8
+ ]
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ py-cryptonight>=0.2.0
2
+ requests>=2.25.1
3
+ rich>=10.0.0
solo_miner.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ import time
4
+ import json
5
+ import random
6
+ import requests
7
+ import platform
8
+ import threading
9
+ import subprocess
10
+ import multiprocessing
11
+ from pathlib import Path
12
+ from datetime import datetime
13
+ from typing import Dict, Optional, Tuple
14
+ from concurrent.futures import ThreadPoolExecutor
15
+ from urllib.parse import urlparse
16
+ try:
17
+ from cryptonight import cryptonight
18
+ except ImportError:
19
+ print("Error: py-cryptonight not installed. Please install Python and run:")
20
+ print("pip install py-cryptonight requests rich")
21
+ sys.exit(1)
22
+
23
+ class MoneroNodeManager:
24
+ def __init__(self):
25
+ self.daemon_url = None
26
+
27
+ def find_fastest_node(self) -> str:
28
+ """Find the fastest responding public node"""
29
+ from node_list import PUBLIC_NODES
30
+ best_latency = float('inf')
31
+ best_node = None
32
+
33
+ print("Finding fastest public node...")
34
+ for node in PUBLIC_NODES:
35
+ try:
36
+ start_time = time.time()
37
+ response = requests.get(f"{node}/get_info", timeout=5)
38
+ if response.status_code == 200:
39
+ latency = time.time() - start_time
40
+ if latency < best_latency:
41
+ best_latency = latency
42
+ best_node = node
43
+ print(f"Node {node} responded in {latency:.2f}s")
44
+ except:
45
+ print(f"Node {node} not responding")
46
+ continue
47
+
48
+ if best_node:
49
+ print(f"\nSelected fastest node: {best_node} (latency: {best_latency:.2f}s)")
50
+ return best_node
51
+ raise Exception("No responsive public nodes found")
52
+
53
+ class MoneroSoloMiner:
54
+ def __init__(self, daemon_url: str = None, threads: int = None):
55
+ self.node_manager = MoneroNodeManager()
56
+ self.daemon_url = daemon_url or self.node_manager.find_fastest_node()
57
+ self.threads = threads or (multiprocessing.cpu_count() - 1)
58
+ self.running = False
59
+ self.wallet_address = None
60
+ self.stats = {
61
+ "start_time": None,
62
+ "hashes": 0,
63
+ "blocks_found": 0,
64
+ "best_diff": 0,
65
+ "node_height": 0,
66
+ "network_height": 0
67
+ }
68
+ self._lock = threading.Lock()
69
+
70
+ def get_block_template(self) -> Optional[Dict]:
71
+ try:
72
+ payload = {
73
+ "jsonrpc": "2.0",
74
+ "id": "0",
75
+ "method": "get_block_template",
76
+ "params": {
77
+ "wallet_address": self.wallet_address,
78
+ "reserve_size": 1
79
+ }
80
+ }
81
+ response = requests.post(self.daemon_url + "/json_rpc", json=payload)
82
+ result = response.json().get("result", {})
83
+ return result
84
+ except Exception as e:
85
+ print(f"Error getting block template: {e}")
86
+ return None
87
+
88
+ def submit_block(self, block_blob: str) -> bool:
89
+ try:
90
+ payload = {
91
+ "jsonrpc": "2.0",
92
+ "id": "0",
93
+ "method": "submit_block",
94
+ "params": [block_blob]
95
+ }
96
+ response = requests.post(self.daemon_url + "/json_rpc", json=payload)
97
+ result = response.json()
98
+ if "error" not in result:
99
+ return True
100
+ print(f"Block submission error: {result['error']}")
101
+ return False
102
+ except Exception as e:
103
+ print(f"Error submitting block: {e}")
104
+ return False
105
+
106
+ def mine_block(self, block_template: Dict):
107
+ blob = block_template["blockhashing_blob"]
108
+ difficulty = int(block_template["difficulty"])
109
+ height = block_template["height"]
110
+
111
+ while self.running:
112
+ nonce = random.getrandbits(32)
113
+ blob = blob[:78] + hex(nonce)[2:].zfill(8) + blob[86:]
114
+
115
+ hash_result = cryptonight(bytes.fromhex(blob))
116
+ result_num = int.from_bytes(hash_result, byteorder='little')
117
+
118
+ with self._lock:
119
+ self.stats["hashes"] += 1
120
+ if result_num < difficulty:
121
+ print(f"\nBlock found at height {height}!")
122
+ self.stats["blocks_found"] += 1
123
+ if self.submit_block(blob):
124
+ print("Block successfully submitted!")
125
+ return True
126
+
127
+ current_diff = (2**256 - 1) // result_num
128
+ if current_diff > self.stats["best_diff"]:
129
+ self.stats["best_diff"] = current_diff
130
+
131
+ def display_stats(self):
132
+ while self.running:
133
+ elapsed = time.time() - self.stats["start_time"]
134
+ hashrate = self.stats["hashes"] / elapsed if elapsed > 0 else 0
135
+
136
+ print("\033[H\033[J") # Clear screen
137
+ print(f"=== Monero Solo Mining Stats ===")
138
+ print(f"Runtime: {elapsed:.1f} seconds")
139
+ print(f"Hashrate: {hashrate:.2f} H/s")
140
+ print(f"Total hashes: {self.stats['hashes']}")
141
+ print(f"Blocks found: {self.stats['blocks_found']}")
142
+ print(f"Best diff: {self.stats['best_diff']}")
143
+ print(f"Mining with {self.threads} threads")
144
+ print("Press Ctrl+C to stop mining")
145
+
146
+ time.sleep(1)
147
+
148
+ def start_mining(self):
149
+ print("Starting Monero solo mining...")
150
+ self.running = True
151
+ self.stats["start_time"] = time.time()
152
+
153
+ # Start stats display in a separate thread
154
+ stats_thread = threading.Thread(target=self.display_stats)
155
+ stats_thread.daemon = True
156
+ stats_thread.start()
157
+
158
+ while self.running:
159
+ template = self.get_block_template()
160
+ if not template:
161
+ print("Failed to get block template. Retrying in 10 seconds...")
162
+ time.sleep(10)
163
+ continue
164
+
165
+ with ThreadPoolExecutor(max_workers=self.threads) as executor:
166
+ futures = [executor.submit(self.mine_block, template) for _ in range(self.threads)]
167
+ for future in futures:
168
+ if future.result():
169
+ break
170
+
171
+ def stop_mining(self):
172
+ self.running = False
173
+
174
+ if __name__ == "__main__":
175
+ import argparse
176
+
177
+ parser = argparse.ArgumentParser(description='Monero Solo Miner')
178
+ parser.add_argument('--wallet', help='Your Monero wallet address (optional for testing)')
179
+ parser.add_argument('--threads', type=int, help='Number of mining threads')
180
+ parser.add_argument('--node', help='Custom node URL (optional)')
181
+
182
+ args = parser.parse_args()
183
+
184
+ try:
185
+ miner = MoneroSoloMiner(
186
+ daemon_url=args.node,
187
+ threads=args.threads
188
+ )
189
+
190
+ # Use test wallet if none provided
191
+ miner.wallet_address = args.wallet or "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A" # Test wallet
192
+
193
+ print(f"Mining with {miner.threads} threads on node: {miner.daemon_url}")
194
+ miner.start_mining()
195
+
196
+ except KeyboardInterrupt:
197
+ print("\nStopping miner...")
198
+ miner.stop_mining()
199
+ print("\nMining stopped. Summary:")
200
+ print(f"Total hashes: {miner.stats['hashes']}")
201
+ print(f"Blocks found: {miner.stats['blocks_found']}")
202
+ except Exception as e:
203
+ print(f"Error: {e}")
204
+ sys.exit(1)
xmrig-config.json.template ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "algo": "rx/0",
3
+ "autosave": true,
4
+ "cpu": true,
5
+ "opencl": false,
6
+ "cuda": false,
7
+ "pools": [
8
+ {
9
+ "url": "127.0.0.1:18081",
10
+ "user": "{{WALLET_ADDRESS}}",
11
+ "pass": "x",
12
+ "keepalive": true,
13
+ "rig-id": "solo",
14
+ "nicehash": false,
15
+ "enabled": true
16
+ }
17
+ ],
18
+ "api": {
19
+ "id": null,
20
+ "worker-id": null,
21
+ "port": {{API_PORT}},
22
+ "access-token": null,
23
+ "restricted": true
24
+ }
25
+ }