favoredone commited on
Commit
fdf3524
·
verified ·
1 Parent(s): bd6de9f

Update parallel_miner_v3.py

Browse files
Files changed (1) hide show
  1. parallel_miner_v3.py +353 -323
parallel_miner_v3.py CHANGED
@@ -1,324 +1,354 @@
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
-
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 = 70 # 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 = 5, 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 30 seconds
217
- current_time = time.time()
218
- if current_time - self.last_template_update > 300: # Update every 5 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 = max_target / current_hash_int
282
-
283
- # Update best hash difficulty if this is higher
284
- self.best_hash_difficulty = max(self.best_hash_difficulty, hash_difficulty)
285
-
286
- logging.info(f"New best hash found with difficulty: {hash_difficulty:.2f}")
287
- logging.info(f"Best hash: {hash_hex}")
288
- logging.info(f"Need target: {target_hex}")
289
- logging.info(f"Hash difficulty: {hash_difficulty:.2f} (higher is better)")
290
-
291
- base_nonce += len(self.cores) * 500
292
-
293
- # Log final results
294
- self.log_final_results(duration)
295
-
296
- def log_final_results(self, duration: float):
297
- """Log final mining results"""
298
- logging.info("\nMining test completed:")
299
- logging.info(f"Duration: {duration:.2f} seconds")
300
- logging.info(f"Total hashes: {self.total_hashes:,}")
301
- logging.info(f"Blocks found: {self.blocks_found}")
302
- logging.info(f"Overall hash rate: {self.total_hashes/duration/1000:.2f} KH/s")
303
- logging.info(f"Electron drift utilized: {self.cores[0].units[0].electron_drift_velocity:.2e} m/s")
304
- logging.info(f"Switching frequency: {self.cores[0].units[0].switching_frequency:.2e} Hz")
305
-
306
- # Log per-core stats
307
- for core in self.cores:
308
- logging.info(f"\nCore {core.core_id} final stats:")
309
- logging.info(f"Total hashes: {core.total_hashes:,}")
310
- logging.info(f"Blocks found: {core.blocks_found}")
311
-
312
- for unit in core.units:
313
- logging.info(f" Unit {unit.unit_id}: {unit.total_hashes:,} hashes, {unit.blocks_found} blocks")
314
- # Show block details if any found
315
- for block_hash, nonce in unit.found_blocks:
316
- logging.info(f" Block found - Hash: {block_hash}, Nonce: {nonce}")
317
-
318
- if __name__ == "__main__":
319
- miner = ParallelMiner()
320
- try:
321
- miner.start_mining(duration=120)
322
- except KeyboardInterrupt:
323
- miner.mining = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  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 = 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")