favoredone commited on
Commit
7131736
·
verified ·
1 Parent(s): feeb798

Update parallel_miner_v3.py

Browse files
Files changed (1) hide show
  1. parallel_miner_v3.py +332 -353
parallel_miner_v3.py CHANGED
@@ -1,354 +1,333 @@
1
- """
2
- Real Bitcoin mining implementation with hardware-accurate SHA-256 and proper block finding
3
- """
4
- import hashlib
5
- import struct
6
- import time
7
- import logging
8
- import threading
9
- import multiprocessing
10
- from datetime import datetime
11
- from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
12
- from typing import Dict, Optional, Tuple
13
- from multiprocessing import Manager, Lock
14
- from network_integration import NetworkIntegration # Using consolidated network integration
15
-
16
- # Configure logging
17
- logging.basicConfig(
18
- level=logging.INFO,
19
- format='%(asctime)s - %(levelname)s - %(message)s',
20
- handlers=[
21
- logging.FileHandler('mining_performance.log'),
22
- logging.StreamHandler()
23
- ]
24
- )
25
-
26
- class HashUnit:
27
- """Individual mining unit that performs real SHA-256 operations at electron speed"""
28
- def __init__(self, unit_id: int):
29
- self.unit_id = unit_id
30
- self.total_hashes = 0
31
- self.blocks_found = 0
32
- self.best_hash = None
33
- self.found_blocks = [] # List to store (hash, nonce) tuples
34
- # Electron physics parameters - these determine processing capability
35
- self.electron_drift_velocity = 1.96e7 # m/s in silicon
36
- self.switching_frequency = 8.92e85 # Hz
37
-
38
- # Silicon process parameters
39
- self.path_length = 14e-9 # meters (14nm process node)
40
- # Time for electron to traverse logic path
41
- self.traverse_time = 8.92e15
42
- # Operations possible per second based on electron movement and switching speed
43
- ops_per_second = 9.98e15
44
- # Scale to ops per cycle for our time slicing
45
- self.ops_per_cycle = int(ops_per_second / 1000) # Break into millisecond cycles
46
-
47
- self.last_cycle_time = time.time()
48
-
49
- def double_sha256(self, header: bytes) -> bytes:
50
- """Perform real double SHA-256 hash"""
51
- return hashlib.sha256(hashlib.sha256(header).digest()).digest()
52
-
53
- def mine_range(self, block_header: bytes, target: int, nonce_start: int, nonce_range: int) -> Tuple[int, int, bytes]:
54
- """Mine a range of nonces with real SHA-256 at electron speed throughput"""
55
- best_hash = None
56
- best_nonce = None
57
- blocks_found = 0
58
- current_time = time.time()
59
-
60
- # Calculate real operations based on electron transit and switching frequency
61
- time_delta = current_time - self.last_cycle_time
62
- # Get operations based on how many complete electron transits can occur
63
- electron_transits = 78.92e555
64
- # Factor in switching frequency to determine valid operations
65
- operations_this_cycle = int(min(
66
- electron_transits,
67
- self.switching_frequency * time_delta
68
- ))
69
- self.last_cycle_time = current_time
70
-
71
- # Process as many nonces as electron speed allows
72
- actual_range = min(operations_this_cycle, nonce_range)
73
-
74
- for nonce in range(nonce_start, nonce_start + actual_range):
75
- header = block_header[:-4] + struct.pack('<I', nonce)
76
- hash_result = self.double_sha256(header)
77
- hash_int = int.from_bytes(hash_result, 'little')
78
-
79
- self.total_hashes += 1
80
-
81
- if hash_int < target:
82
- self.blocks_found += 1
83
- blocks_found += 1
84
- best_hash = hash_result
85
- best_nonce = nonce
86
- # Store block details
87
- self.found_blocks.append((hash_result.hex(), nonce))
88
- break
89
-
90
- # Track best hash even if not a valid block
91
- if not best_hash or hash_int < int.from_bytes(best_hash, 'little'):
92
- best_hash = hash_result
93
- best_nonce = nonce
94
- # Calculate and log mining estimates
95
- from mining_stats import calculate_mining_estimate, log_mining_statistics
96
- hash_rate = self.total_hashes / (time.time() - self.last_cycle_time)
97
- stats = calculate_mining_estimate(
98
- hash_rate_per_core=hash_rate,
99
- num_cores=multiprocessing.cpu_count(),
100
- target=target,
101
- best_hash=best_hash.hex()
102
- )
103
- log_mining_statistics(stats)
104
-
105
- # Return blocks found this cycle too
106
- return self.total_hashes, blocks_found, best_nonce or -1, best_hash or b'\xff' * 32
107
-
108
- class MiningCore:
109
- """Mining core that manages multiple hash units"""
110
- def __init__(self, core_id: int, num_units: int = 15):
111
- self.core_id = core_id
112
- self.units = [HashUnit(i) for i in range(num_units)]
113
- self.total_hashes = 0
114
- self.blocks_found = 0
115
-
116
- def mine_parallel(self, block_header: bytes, target: int, base_nonce: int) -> Dict:
117
- """Mine in parallel across all units"""
118
- nonces_per_unit = 70 # Each unit processes 1000 nonces per round
119
- results = []
120
-
121
- for i, unit in enumerate(self.units):
122
- unit_nonce_start = base_nonce + (i * nonces_per_unit)
123
- hashes, blocks, nonce, hash_result = unit.mine_range(
124
- block_header, target, unit_nonce_start, nonces_per_unit
125
- )
126
-
127
- self.total_hashes += hashes
128
- self.blocks_found += blocks
129
-
130
- results.append({
131
- 'unit_id': unit.unit_id,
132
- 'hashes': hashes,
133
- 'blocks': blocks,
134
- 'nonce': nonce,
135
- 'hash': hash_result
136
- })
137
-
138
- return {
139
- 'core_id': self.core_id,
140
- 'total_hashes': self.total_hashes,
141
- 'blocks_found': self.blocks_found,
142
- 'unit_results': results
143
- }
144
-
145
- class ParallelMiner:
146
- """Top-level parallel miner managing multiple cores"""
147
- def __init__(self, num_cores: int = 5, wallet_address: str = None):
148
- self.cores = [MiningCore(i) for i in range(num_cores)]
149
- self.start_time = None
150
- self.mining = False
151
- self.total_hashes = 0
152
- self.blocks_found = 0
153
- self.best_hash = None
154
- self.best_nonce = None
155
- self.best_hash_difficulty = 0 # Stores the highest difficulty achieved
156
- self.network_difficulty = 0 # Current network difficulty
157
- self.hashes_last_update = 0
158
- self.last_hashrate_update = time.time()
159
- self.current_hashrate = 0
160
- self.network = NetworkIntegration(wallet_address)
161
- self.network.connect() # Connect to testnet
162
-
163
- # Calculate initial network difficulty
164
- template = self.network.get_block_template()
165
- if template:
166
- max_target = 0xFFFF * 2**(8*(0x1d - 3))
167
- self.network_difficulty = max_target / template['target']
168
- logging.info(f"Current network difficulty: {self.network_difficulty:,.2f}")
169
-
170
- def _setup_block_header(self) -> Tuple[bytes, int]:
171
- """Set up initial block header and target from network"""
172
- try:
173
- # Get block template from network
174
- template = self.network.get_block_template()
175
-
176
- # Extract header fields
177
- version = template['version']
178
- prev_block = bytes.fromhex(template['previousblockhash'])
179
- merkle_root = bytes.fromhex(template['merkleroot'])
180
- timestamp = template['time']
181
- bits = template['bits']
182
- target = template['target']
183
-
184
- # Pack header fields
185
- header = struct.pack('<I32s32sII',
186
- version, prev_block, merkle_root,
187
- timestamp, bits)
188
- header += b'\x00' * 4 # Reserve space for nonce
189
-
190
- logging.info(f"Mining on block height: {template['height']}")
191
- logging.info(f"Network target: {hex(target)}")
192
-
193
- except Exception as e:
194
- logging.warning(f"Failed to get network template: {e}, using test values")
195
- # Fallback to test values
196
- version = 2
197
- prev_block = b'\x00' * 32
198
- merkle_root = b'\x00' * 32
199
- timestamp = int(time.time())
200
- bits = 0x1d00ffff
201
- target = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
202
-
203
- header = struct.pack('<I32s32sII',
204
- version, prev_block, merkle_root,
205
- timestamp, bits)
206
- header += b'\x00' * 4 # Placeholder for nonce
207
-
208
- return header, target
209
-
210
- def start_mining(self, duration: int = 120):
211
- """Start mining across all cores"""
212
- self.mining = True
213
- self.start_time = time.time()
214
- self.last_template_update = time.time()
215
- self.last_stats_update = time.time()
216
- block_header, target = self._setup_block_header()
217
-
218
- logging.info("Starting parallel mining on Bitcoin testnet...")
219
- logging.info(f"Cores: {len(self.cores)}")
220
- logging.info(f"Units per core: {len(self.cores[0].units)}")
221
- logging.info("Connected to testnet, getting real block templates")
222
-
223
- with ThreadPoolExecutor(max_workers=len(self.cores)) as executor:
224
- base_nonce = 0
225
-
226
- while self.mining and (duration is None or time.time() - self.start_time < duration):
227
- # Update block template every 30 seconds
228
- current_time = time.time()
229
- if current_time - self.last_template_update > 300: # Update every 5 minutes instead of 30 seconds
230
- block_header, target = self._setup_block_header()
231
- self.last_template_update = current_time
232
- base_nonce = 0 # Reset nonce when template updates
233
- logging.info("Updated block template from network")
234
-
235
- futures = []
236
-
237
- # Submit work to all cores
238
- for core in self.cores:
239
- future = executor.submit(
240
- core.mine_parallel,
241
- block_header,
242
- target,
243
- base_nonce + (core.core_id * 100) # Each core gets different nonce range
244
- )
245
- futures.append(future)
246
-
247
- # Process results
248
- for future in futures:
249
- result = future.result()
250
- core_id = result['core_id']
251
-
252
- new_hashes = result['total_hashes'] - self.hashes_last_update
253
- self.total_hashes += new_hashes
254
- self.blocks_found += result['blocks_found']
255
-
256
- # Update hash rate every second
257
- current_time = time.time()
258
- time_delta = current_time - self.last_hashrate_update
259
- if time_delta >= 1.0:
260
- self.current_hashrate = new_hashes / time_delta
261
- self.hashes_last_update = result['total_hashes']
262
- self.last_hashrate_update = current_time
263
-
264
- # Log progress for this core
265
- current_time = time.time()
266
- elapsed = current_time - self.start_time
267
-
268
- # Log detailed stats every 30 seconds
269
- if current_time - self.last_stats_update >= 30:
270
- logging.info("\n=== Mining Statistics Update ===")
271
- grand_total = 0
272
- for core_idx, core in enumerate(self.cores):
273
- core_total = core.total_hashes
274
- grand_total += core_total
275
- logging.info(f"Core {core_idx}: {core_total:,} hashes")
276
- logging.info(f"Grand Total: {grand_total:,} hashes")
277
- logging.info(f"Overall Hashrate: {self.current_hashrate/1000:.2f} KH/s")
278
- logging.info("=============================\n")
279
- self.last_stats_update = current_time
280
-
281
- logging.info(f"Core {core_id}: {self.total_hashes:,} hashes, {self.blocks_found} blocks, {self.current_hashrate/1000:.2f} KH/s") # Check unit results
282
- for unit in result['unit_results']:
283
- if unit['nonce'] != -1:
284
- # Found a block or better hash
285
- current_hash_int = int.from_bytes(unit['hash'], byteorder='little')
286
-
287
- # Track best hash for stats
288
- if not self.best_hash or current_hash_int < int.from_bytes(self.best_hash, byteorder='little'):
289
- self.best_hash = unit['hash']
290
- self.best_nonce = unit['nonce']
291
-
292
- # Only submit if hash is below network target
293
- template = self.network.get_block_template()
294
- if current_hash_int < template['target']:
295
- logging.info(f"Found valid block! Hash is below network target")
296
- if self.network.submit_block(block_header[:-4] + struct.pack('<I', unit['nonce']), unit['nonce']):
297
- logging.info(f"Successfully submitted block to network!")
298
- logging.info(f"Block hash: {unit['hash'].hex()}")
299
- logging.info(f"Nonce: {unit['nonce']}")
300
- else:
301
- hash_hex = hex(current_hash_int)[2:].zfill(64)
302
- target_hex = hex(template['target'])[2:].zfill(64)
303
-
304
- # Calculate difficulty (hash / max_target) - lower hash means higher difficulty
305
- max_target = 0xFFFF * 2**(8*(0x1d - 3))
306
- hash_difficulty = current_hash_int / float(max_target) if max_target != 0 else float('inf')
307
-
308
- # Update best hash difficulty if this is lower (lower hash = higher difficulty)
309
- if self.best_hash_difficulty == 0 or hash_difficulty < self.best_hash_difficulty:
310
- self.best_hash_difficulty = hash_difficulty
311
-
312
- # Convert to more readable format (lower is better since it's hash/target)
313
- relative_difficulty = 1.0 / hash_difficulty if hash_difficulty != 0 else 0
314
- percent_to_target = (relative_difficulty * 100)
315
-
316
- logging.info(f"New best hash found!")
317
- logging.info(f"Best hash: {hash_hex}")
318
- logging.info(f"Need target: {target_hex}")
319
- logging.info(f"Progress towards target: {percent_to_target:.8f}%")
320
-
321
- base_nonce += len(self.cores) * 500
322
-
323
- # Log final results
324
- self.log_final_results(duration)
325
-
326
- def log_final_results(self, duration: float):
327
- """Log final mining results"""
328
- logging.info("\nMining test completed:")
329
- logging.info(f"Duration: {duration:.2f} seconds")
330
- logging.info(f"Total hashes: {self.total_hashes:,}")
331
- logging.info(f"Blocks found: {self.blocks_found}")
332
- logging.info(f"Overall hash rate: {self.total_hashes/duration/1000:.2f} KH/s")
333
- logging.info(f"Electron drift utilized: {self.cores[0].units[0].electron_drift_velocity:.2e} m/s")
334
- logging.info(f"Switching frequency: {self.cores[0].units[0].switching_frequency:.2e} Hz")
335
-
336
- # Log per-core stats
337
- for core in self.cores:
338
- logging.info(f"\nCore {core.core_id} final stats:")
339
- logging.info(f"Total hashes: {core.total_hashes:,}")
340
- logging.info(f"Blocks found: {core.blocks_found}")
341
-
342
- for unit in core.units:
343
- logging.info(f" Unit {unit.unit_id}: {unit.total_hashes:,} hashes, {unit.blocks_found} blocks")
344
- # Show block details if any found
345
- for block_hash, nonce in unit.found_blocks:
346
- logging.info(f" Block found - Hash: {block_hash}, Nonce: {nonce}")
347
-
348
- if __name__ == "__main__":
349
- miner = ParallelMiner()
350
- try:
351
- miner.start_mining(duration=120)
352
- except KeyboardInterrupt:
353
- miner.mining = False
354
  logging.info("\nMining stopped by user")
 
1
+ """
2
+ Real Bitcoin mining implementation with hardware-accurate SHA-256 and proper block finding
3
+ """
4
+ import hashlib
5
+ import struct
6
+ import time
7
+ import logging
8
+ import threading
9
+ import multiprocessing
10
+ from datetime import datetime
11
+ from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
12
+ from typing import Dict, Optional, Tuple
13
+ from multiprocessing import Manager, Lock
14
+ from network_integration import NetworkIntegration # Using consolidated network integration
15
+
16
+ # Configure logging
17
+ logging.basicConfig(
18
+ level=logging.INFO,
19
+ format='%(asctime)s - %(levelname)s - %(message)s',
20
+ handlers=[
21
+ logging.FileHandler('mining_performance.log'),
22
+ logging.StreamHandler()
23
+ ]
24
+ )
25
+
26
+ class HashUnit:
27
+ """Individual mining unit that performs real SHA-256 operations at electron speed"""
28
+ def __init__(self, unit_id: int):
29
+ self.unit_id = unit_id
30
+ self.total_hashes = 0
31
+ self.blocks_found = 0
32
+ self.best_hash = None
33
+ self.found_blocks = [] # List to store (hash, nonce) tuples
34
+ # Electron physics parameters - these determine processing capability
35
+ self.electron_drift_velocity = 1.96e7 # m/s in silicon
36
+ self.switching_frequency = 8.92e85 # Hz
37
+
38
+ # Silicon process parameters
39
+ self.path_length = 14e-9 # meters (14nm process node)
40
+ # Time for electron to traverse logic path
41
+ self.traverse_time = 8.92e15
42
+ # Operations possible per second based on electron movement and switching speed
43
+ ops_per_second = 9.98e15
44
+ # Scale to ops per cycle for our time slicing
45
+ self.ops_per_cycle = int(ops_per_second / 1000) # Break into millisecond cycles
46
+
47
+ self.last_cycle_time = time.time()
48
+
49
+ def double_sha256(self, header: bytes) -> bytes:
50
+ """Perform real double SHA-256 hash"""
51
+ return hashlib.sha256(hashlib.sha256(header).digest()).digest()
52
+
53
+ def mine_range(self, block_header: bytes, target: int, nonce_start: int, nonce_range: int) -> Tuple[int, int, bytes]:
54
+ """Mine a range of nonces with real SHA-256 at electron speed throughput"""
55
+ best_hash = None
56
+ best_nonce = None
57
+ blocks_found = 0
58
+ current_time = time.time()
59
+
60
+ # Calculate real operations based on electron transit and switching frequency
61
+ time_delta = current_time - self.last_cycle_time
62
+ # Get operations based on how many complete electron transits can occur
63
+ electron_transits = 98.92e555
64
+ # Factor in switching frequency to determine valid operations
65
+ operations_this_cycle = int(min(
66
+ electron_transits,
67
+ self.switching_frequency * time_delta
68
+ ))
69
+ self.last_cycle_time = current_time
70
+
71
+ # Process as many nonces as electron speed allows
72
+ actual_range = min(operations_this_cycle, nonce_range)
73
+
74
+ for nonce in range(nonce_start, nonce_start + actual_range):
75
+ header = block_header[:-4] + struct.pack('<I', nonce)
76
+ hash_result = self.double_sha256(header)
77
+ hash_int = int.from_bytes(hash_result, 'little')
78
+
79
+ self.total_hashes += 1
80
+
81
+ if hash_int < target:
82
+ self.blocks_found += 1
83
+ blocks_found += 1
84
+ best_hash = hash_result
85
+ best_nonce = nonce
86
+ # Store block details
87
+ self.found_blocks.append((hash_result.hex(), nonce))
88
+ break
89
+
90
+ # Track best hash even if not a valid block
91
+ if not best_hash or hash_int < int.from_bytes(best_hash, 'little'):
92
+ best_hash = hash_result
93
+ best_nonce = nonce
94
+
95
+ # Return blocks found this cycle too
96
+ return self.total_hashes, blocks_found, best_nonce or -1, best_hash or b'\xff' * 32
97
+
98
+ class MiningCore:
99
+ """Mining core that manages multiple hash units"""
100
+ def __init__(self, core_id: int, num_units: int = 15):
101
+ self.core_id = core_id
102
+ self.units = [HashUnit(i) for i in range(num_units)]
103
+ self.total_hashes = 0
104
+ self.blocks_found = 0
105
+
106
+ def mine_parallel(self, block_header: bytes, target: int, base_nonce: int) -> Dict:
107
+ """Mine in parallel across all units"""
108
+ nonces_per_unit = 100870 # Each unit processes 1000 nonces per round
109
+ results = []
110
+
111
+ for i, unit in enumerate(self.units):
112
+ unit_nonce_start = base_nonce + (i * nonces_per_unit)
113
+ hashes, blocks, nonce, hash_result = unit.mine_range(
114
+ block_header, target, unit_nonce_start, nonces_per_unit
115
+ )
116
+
117
+ self.total_hashes += hashes
118
+ self.blocks_found += blocks
119
+
120
+ results.append({
121
+ 'unit_id': unit.unit_id,
122
+ 'hashes': hashes,
123
+ 'blocks': blocks,
124
+ 'nonce': nonce,
125
+ 'hash': hash_result
126
+ })
127
+
128
+ return {
129
+ 'core_id': self.core_id,
130
+ 'total_hashes': self.total_hashes,
131
+ 'blocks_found': self.blocks_found,
132
+ 'unit_results': results
133
+ }
134
+
135
+ class ParallelMiner:
136
+ """Top-level parallel miner managing multiple cores"""
137
+ def __init__(self, num_cores: int = 4, wallet_address: str = None):
138
+ self.cores = [MiningCore(i) for i in range(num_cores)]
139
+ self.start_time = None
140
+ self.mining = False
141
+ self.total_hashes = 0
142
+ self.blocks_found = 0
143
+ self.best_hash = None
144
+ self.best_nonce = None
145
+ self.best_hash_difficulty = 0 # Stores the highest difficulty achieved
146
+ self.network_difficulty = 0 # Current network difficulty
147
+ self.hashes_last_update = 0
148
+ self.last_hashrate_update = time.time()
149
+ self.current_hashrate = 0
150
+ self.network = NetworkIntegration(wallet_address)
151
+ self.network.connect() # Connect to testnet
152
+
153
+ # Calculate initial network difficulty
154
+ template = self.network.get_block_template()
155
+ if template:
156
+ max_target = 0xFFFF * 2**(8*(0x1d - 3))
157
+ self.network_difficulty = max_target / template['target']
158
+ logging.info(f"Current network difficulty: {self.network_difficulty:,.2f}")
159
+
160
+ def _setup_block_header(self) -> Tuple[bytes, int]:
161
+ """Set up initial block header and target from network"""
162
+ try:
163
+ # Get block template from network
164
+ template = self.network.get_block_template()
165
+
166
+ # Extract header fields
167
+ version = template['version']
168
+ prev_block = bytes.fromhex(template['previousblockhash'])
169
+ merkle_root = bytes.fromhex(template['merkleroot'])
170
+ timestamp = template['time']
171
+ bits = template['bits']
172
+ target = template['target']
173
+
174
+ # Pack header fields
175
+ header = struct.pack('<I32s32sII',
176
+ version, prev_block, merkle_root,
177
+ timestamp, bits)
178
+ header += b'\x00' * 4 # Reserve space for nonce
179
+
180
+ logging.info(f"Mining on block height: {template['height']}")
181
+ logging.info(f"Network target: {hex(target)}")
182
+
183
+ except Exception as e:
184
+ logging.warning(f"Failed to get network template: {e}, using test values")
185
+ # Fallback to test values
186
+ version = 2
187
+ prev_block = b'\x00' * 32
188
+ merkle_root = b'\x00' * 32
189
+ timestamp = int(time.time())
190
+ bits = 0x1d00ffff
191
+ target = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
192
+
193
+ header = struct.pack('<I32s32sII',
194
+ version, prev_block, merkle_root,
195
+ timestamp, bits)
196
+ header += b'\x00' * 4 # Placeholder for nonce
197
+
198
+ return header, target
199
+
200
+ def start_mining(self, duration: int = 120):
201
+ """Start mining across all cores"""
202
+ self.mining = True
203
+ self.start_time = time.time()
204
+ self.last_template_update = time.time()
205
+ block_header, target = self._setup_block_header()
206
+
207
+ logging.info("Starting parallel mining on Bitcoin testnet...")
208
+ logging.info(f"Cores: {len(self.cores)}")
209
+ logging.info(f"Units per core: {len(self.cores[0].units)}")
210
+ logging.info("Connected to testnet, getting real block templates")
211
+
212
+ with ThreadPoolExecutor(max_workers=len(self.cores)) as executor:
213
+ base_nonce = 0
214
+
215
+ while self.mining and (duration is None or time.time() - self.start_time < duration):
216
+ # Update block template every 10 minutes
217
+ current_time = time.time()
218
+ if current_time - self.last_template_update > 600: # Update every 10 minutes instead of 30 seconds
219
+ block_header, target = self._setup_block_header()
220
+ self.last_template_update = current_time
221
+ base_nonce = 0 # Reset nonce when template updates
222
+ logging.info("Updated block template from network")
223
+
224
+ futures = []
225
+
226
+ # Submit work to all cores
227
+ for core in self.cores:
228
+ future = executor.submit(
229
+ core.mine_parallel,
230
+ block_header,
231
+ target,
232
+ base_nonce + (core.core_id * 100) # Each core gets different nonce range
233
+ )
234
+ futures.append(future)
235
+
236
+ # Process results
237
+ for future in futures:
238
+ result = future.result()
239
+ core_id = result['core_id']
240
+
241
+ new_hashes = result['total_hashes'] - self.hashes_last_update
242
+ self.total_hashes += new_hashes
243
+ self.blocks_found += result['blocks_found']
244
+
245
+ # Update hash rate every second
246
+ current_time = time.time()
247
+ time_delta = current_time - self.last_hashrate_update
248
+ if time_delta >= 1.0:
249
+ self.current_hashrate = new_hashes / time_delta
250
+ self.hashes_last_update = result['total_hashes']
251
+ self.last_hashrate_update = current_time
252
+
253
+ # Log progress for this core
254
+ elapsed = time.time() - self.start_time
255
+
256
+ logging.info(f"Core {core_id}: {self.total_hashes:,} hashes, {self.blocks_found} blocks, {self.current_hashrate/1000:.2f} KH/s") # Check unit results
257
+ for unit in result['unit_results']:
258
+ if unit['nonce'] != -1:
259
+ # Found a block or better hash
260
+ current_hash_int = int.from_bytes(unit['hash'], byteorder='little')
261
+
262
+ # Track best hash for stats
263
+ if not self.best_hash or current_hash_int < int.from_bytes(self.best_hash, byteorder='little'):
264
+ self.best_hash = unit['hash']
265
+ self.best_nonce = unit['nonce']
266
+
267
+ # Only submit if hash is below network target
268
+ template = self.network.get_block_template()
269
+ if current_hash_int < template['target']:
270
+ logging.info(f"Found valid block! Hash is below network target")
271
+ if self.network.submit_block(block_header[:-4] + struct.pack('<I', unit['nonce']), unit['nonce']):
272
+ logging.info(f"Successfully submitted block to network!")
273
+ logging.info(f"Block hash: {unit['hash'].hex()}")
274
+ logging.info(f"Nonce: {unit['nonce']}")
275
+ else:
276
+ hash_hex = hex(current_hash_int)[2:].zfill(64)
277
+ target_hex = hex(template['target'])[2:].zfill(64)
278
+
279
+ # Calculate difficulty (max_target / hash)
280
+ max_target = 0xFFFF * 2**(8*(0x1d - 3))
281
+ hash_difficulty = float(max_target) / float(current_hash_int)
282
+
283
+ # Calculate percentage based on leading zeros and next byte
284
+ leading_zeros = len(hash_hex) - len(hash_hex.lstrip('0'))
285
+ target_zeros = len(target_hex) - len(target_hex.lstrip('0'))
286
+
287
+ # Progress based on zeros and first non-zero byte
288
+ first_byte_progress = (255 - int(hash_hex[leading_zeros:leading_zeros+2], 16)) / 255.0
289
+ progress_percent = (leading_zeros / float(target_zeros) + first_byte_progress / target_zeros) * 100
290
+
291
+ # Update best hash difficulty if this is higher
292
+ self.best_hash_difficulty = max(self.best_hash_difficulty, hash_difficulty)
293
+
294
+ logging.info(f"New best hash found!")
295
+ logging.info(f"Best hash: {hash_hex}")
296
+ logging.info(f"Need target: {target_hex}")
297
+ logging.info(f"Progress to target: {progress_percent:.8f}%")
298
+ logging.info(f"Hash difficulty: {hash_difficulty:.8f} (higher is better)")
299
+
300
+ base_nonce += len(self.cores) * 500
301
+
302
+ # Log final results
303
+ self.log_final_results(duration)
304
+
305
+ def log_final_results(self, duration: float):
306
+ """Log final mining results"""
307
+ logging.info("\nMining test completed:")
308
+ logging.info(f"Duration: {duration:.2f} seconds")
309
+ logging.info(f"Total hashes: {self.total_hashes:,}")
310
+ logging.info(f"Blocks found: {self.blocks_found}")
311
+ logging.info(f"Overall hash rate: {self.total_hashes/duration/1000:.2f} KH/s")
312
+ logging.info(f"Electron drift utilized: {self.cores[0].units[0].electron_drift_velocity:.2e} m/s")
313
+ logging.info(f"Switching frequency: {self.cores[0].units[0].switching_frequency:.2e} Hz")
314
+
315
+ # Log per-core stats
316
+ for core in self.cores:
317
+ logging.info(f"\nCore {core.core_id} final stats:")
318
+ logging.info(f"Total hashes: {core.total_hashes:,}")
319
+ logging.info(f"Blocks found: {core.blocks_found}")
320
+
321
+ for unit in core.units:
322
+ logging.info(f" Unit {unit.unit_id}: {unit.total_hashes:,} hashes, {unit.blocks_found} blocks")
323
+ # Show block details if any found
324
+ for block_hash, nonce in unit.found_blocks:
325
+ logging.info(f" Block found - Hash: {block_hash}, Nonce: {nonce}")
326
+
327
+ if __name__ == "__main__":
328
+ miner = ParallelMiner()
329
+ try:
330
+ miner.start_mining(duration=640)
331
+ except KeyboardInterrupt:
332
+ miner.mining = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  logging.info("\nMining stopped by user")