Fred808 commited on
Commit
733c03d
·
verified ·
1 Parent(s): 7c648df

Update solo_miner.py

Browse files
Files changed (1) hide show
  1. solo_miner.py +204 -204
solo_miner.py CHANGED
@@ -1,204 +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)
 
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 pycryptonight import cn_slow_hash as 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)