Update parallel_miner_v3.py
Browse files- parallel_miner_v3.py +101 -236
parallel_miner_v3.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
"""
|
| 4 |
import hashlib
|
| 5 |
import struct
|
|
@@ -7,13 +7,11 @@ import time
|
|
| 7 |
import logging
|
| 8 |
import threading
|
| 9 |
import multiprocessing
|
| 10 |
-
import random # For quantum tunneling probability
|
| 11 |
from datetime import datetime
|
| 12 |
-
from
|
|
|
|
| 13 |
from multiprocessing import Manager, Lock
|
| 14 |
from network_integration import NetworkIntegration # Using consolidated network integration
|
| 15 |
-
from dataclasses import dataclass
|
| 16 |
-
import numpy as np
|
| 17 |
|
| 18 |
# Configure logging
|
| 19 |
logging.basicConfig(
|
|
@@ -26,23 +24,16 @@ logging.basicConfig(
|
|
| 26 |
)
|
| 27 |
|
| 28 |
class HashUnit:
|
| 29 |
-
"""Individual mining unit
|
| 30 |
def __init__(self, unit_id: int):
|
| 31 |
self.unit_id = unit_id
|
| 32 |
self.total_hashes = 0
|
| 33 |
self.blocks_found = 0
|
| 34 |
self.best_hash = None
|
| 35 |
self.found_blocks = [] # List to store (hash, nonce) tuples
|
| 36 |
-
|
| 37 |
-
# Quantum tunneling parameters
|
| 38 |
-
self.tunnel_probability = 0.98 # Probability of successful tunneling
|
| 39 |
-
self.entanglement_state = {} # Quantum state shared with other units
|
| 40 |
-
self.coherence_time = 1e-12 # Quantum coherence time in seconds
|
| 41 |
-
|
| 42 |
-
# Enhanced electron physics parameters
|
| 43 |
self.electron_drift_velocity = 1.96e7 # m/s in silicon
|
| 44 |
self.switching_frequency = 8.92e85 * 10020000 # Hz
|
| 45 |
-
self.quantum_tunnel_lock = threading.Lock() # Lock for quantum state updates
|
| 46 |
|
| 47 |
# Silicon process parameters
|
| 48 |
self.path_length = 14e-9 # meters (14nm process node)
|
|
@@ -55,37 +46,8 @@ class HashUnit:
|
|
| 55 |
|
| 56 |
self.last_cycle_time = time.time()
|
| 57 |
|
| 58 |
-
def quantum_tunnel_state(self, other_unit: 'HashUnit') -> bool:
|
| 59 |
-
"""Establish quantum tunneling between two hash units"""
|
| 60 |
-
with self.quantum_tunnel_lock:
|
| 61 |
-
if random.random() < self.tunnel_probability:
|
| 62 |
-
# Share quantum states between units
|
| 63 |
-
shared_state = {
|
| 64 |
-
'electron_state': (self.electron_drift_velocity + other_unit.electron_drift_velocity) / 2,
|
| 65 |
-
'switching_state': (self.switching_frequency + other_unit.switching_frequency) / 2,
|
| 66 |
-
'coherence_time': min(self.coherence_time, other_unit.coherence_time)
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
# Update both units' entanglement states
|
| 70 |
-
self.entanglement_state[other_unit.unit_id] = shared_state
|
| 71 |
-
other_unit.entanglement_state[self.unit_id] = shared_state
|
| 72 |
-
return True
|
| 73 |
-
return False
|
| 74 |
-
|
| 75 |
def double_sha256(self, header: bytes) -> bytes:
|
| 76 |
-
"""Perform real SHA-256 hash
|
| 77 |
-
# Check for entangled states that can speed up computation
|
| 78 |
-
entangled_boost = 1.0
|
| 79 |
-
for unit_id, state in self.entanglement_state.items():
|
| 80 |
-
if time.time() - state.get('last_update', 0) < self.coherence_time:
|
| 81 |
-
entangled_boost *= 1.2 # 20% speedup per entangled unit
|
| 82 |
-
|
| 83 |
-
# Apply quantum tunneling effect to hash computation
|
| 84 |
-
if entangled_boost > 1.0:
|
| 85 |
-
# Use quantum superposition for parallel hash computation
|
| 86 |
-
hash1 = hashlib.sha256(header).digest()
|
| 87 |
-
hash2 = hashlib.sha256(hash1).digest()
|
| 88 |
-
return hash2
|
| 89 |
return hashlib.sha256(hashlib.sha256(header).digest()).digest()
|
| 90 |
|
| 91 |
def mine_range(self, block_header: bytes, target: int, nonce_start: int, nonce_range: int) -> Tuple[int, int, bytes]:
|
|
@@ -134,91 +96,16 @@ class HashUnit:
|
|
| 134 |
return self.total_hashes, blocks_found, best_nonce or -1, best_hash or b'\xff' * 32
|
| 135 |
|
| 136 |
class MiningCore:
|
| 137 |
-
"""Mining core that manages multiple hash units
|
| 138 |
-
def __init__(self, core_id: int, num_units: int =
|
| 139 |
self.core_id = core_id
|
| 140 |
self.units = [HashUnit(i) for i in range(num_units)]
|
| 141 |
self.total_hashes = 0
|
| 142 |
self.blocks_found = 0
|
| 143 |
|
| 144 |
-
# Physical positioning for electron velocity calculations
|
| 145 |
-
self.position = position # (x, y) position on silicon die
|
| 146 |
-
self.unit_spacing = 14e-9 # 14nm spacing between units
|
| 147 |
-
|
| 148 |
-
# Electron synchronization parameters
|
| 149 |
-
self.switching_frequency = 8.92e85 # Base switching frequency in Hz
|
| 150 |
-
self.phase_alignment = 0.0 # Current phase alignment with other cores
|
| 151 |
-
self.quantum_state = 0 # Quantum state for entanglement
|
| 152 |
-
self.sync_interval = 1e-15 # Synchronization interval in seconds (femtosecond)
|
| 153 |
-
self.last_sync = time.time()
|
| 154 |
-
self.electron_sync_lock = threading.Lock() # Lock for electron state synchronization
|
| 155 |
-
|
| 156 |
-
# Electron velocity scaling
|
| 157 |
-
self.base_drift_velocity = 1.96e7 # Base electron drift velocity in m/s
|
| 158 |
-
self.temperature = 298.0 # Kelvin
|
| 159 |
-
self.thermal_voltage = 0.026 # Thermal voltage at room temperature (V)
|
| 160 |
-
|
| 161 |
-
# Position units in a grid pattern
|
| 162 |
-
for i, unit in enumerate(self.units):
|
| 163 |
-
x = (i % 4) * self.unit_spacing
|
| 164 |
-
y = (i // 4) * self.unit_spacing
|
| 165 |
-
unit.position = (x, y)
|
| 166 |
-
|
| 167 |
-
def calculate_electron_velocity(self, distance: float, electric_field: float = 1e5) -> float:
|
| 168 |
-
"""Calculate electron drift velocity based on distance and conditions"""
|
| 169 |
-
# Boltzmann constant
|
| 170 |
-
k_B = 1.380649e-23
|
| 171 |
-
# Electron charge
|
| 172 |
-
q = 1.602176634e-19
|
| 173 |
-
|
| 174 |
-
# Temperature effects on mobility
|
| 175 |
-
mobility = 1400 * (300 / self.temperature) ** 2.2 # cmΒ²/(Vβ
s)
|
| 176 |
-
mobility *= 1e-4 # Convert to mΒ²/(Vβ
s)
|
| 177 |
-
|
| 178 |
-
# Calculate velocity using advanced drift model
|
| 179 |
-
thermal_energy = k_B * self.temperature
|
| 180 |
-
scattering_length = mobility * thermal_energy / q
|
| 181 |
-
|
| 182 |
-
# Velocity saturation effects
|
| 183 |
-
saturation_velocity = 1e5 # m/s in silicon
|
| 184 |
-
field_velocity = mobility * electric_field
|
| 185 |
-
|
| 186 |
-
# Calculate actual drift velocity with distance consideration
|
| 187 |
-
drift_velocity = ((field_velocity * saturation_velocity) /
|
| 188 |
-
(field_velocity + saturation_velocity))
|
| 189 |
-
|
| 190 |
-
# Scale by distance (closer = faster due to stronger coupling)
|
| 191 |
-
scaling_factor = 1.0 / (1.0 + distance / scattering_length)
|
| 192 |
-
return drift_velocity * scaling_factor
|
| 193 |
-
|
| 194 |
-
def synchronize_electron_states(self, other_cores: list) -> None:
|
| 195 |
-
"""Synchronize electron states between cores using quantum entanglement"""
|
| 196 |
-
with self.electron_sync_lock:
|
| 197 |
-
# Calculate phase difference with other cores
|
| 198 |
-
total_phase = sum(core.phase_alignment for core in other_cores)
|
| 199 |
-
avg_phase = total_phase / len(other_cores) if other_cores else 0
|
| 200 |
-
|
| 201 |
-
# Adjust switching frequency based on phase difference
|
| 202 |
-
phase_error = avg_phase - self.phase_alignment
|
| 203 |
-
adjustment = phase_error * 1e12 # Picosecond adjustment
|
| 204 |
-
self.switching_frequency += adjustment
|
| 205 |
-
|
| 206 |
-
# Update quantum state based on entanglement
|
| 207 |
-
quantum_states = [core.quantum_state for core in other_cores]
|
| 208 |
-
# Use quantum superposition of states
|
| 209 |
-
self.quantum_state = sum(quantum_states) / (len(quantum_states) + 1)
|
| 210 |
-
|
| 211 |
-
# Align electron drift between cores
|
| 212 |
-
current_time = time.time()
|
| 213 |
-
if current_time - self.last_sync >= self.sync_interval:
|
| 214 |
-
# Perform femtosecond-scale synchronization
|
| 215 |
-
for unit in self.units:
|
| 216 |
-
unit.switching_frequency = self.switching_frequency
|
| 217 |
-
self.last_sync = current_time
|
| 218 |
-
|
| 219 |
def mine_parallel(self, block_header: bytes, target: int, base_nonce: int) -> Dict:
|
| 220 |
-
"""Mine in parallel across all units
|
| 221 |
-
nonces_per_unit =
|
| 222 |
results = []
|
| 223 |
|
| 224 |
for i, unit in enumerate(self.units):
|
|
@@ -245,70 +132,9 @@ class MiningCore:
|
|
| 245 |
'unit_results': results
|
| 246 |
}
|
| 247 |
|
| 248 |
-
@dataclass
|
| 249 |
-
class QuantumWorkPacket:
|
| 250 |
-
"""Work packet for quantum channel distribution"""
|
| 251 |
-
block_header: bytes
|
| 252 |
-
target: int
|
| 253 |
-
nonce_range: Tuple[int, int]
|
| 254 |
-
source_core: int
|
| 255 |
-
priority: float = 1.0
|
| 256 |
-
entanglement_state: Dict = None
|
| 257 |
-
|
| 258 |
-
class QuantumChannel:
|
| 259 |
-
"""Quantum channel for electron-speed work distribution"""
|
| 260 |
-
def __init__(self):
|
| 261 |
-
self.quantum_state = np.zeros(256, dtype=np.complex128) # Quantum state vector
|
| 262 |
-
self.entangled_cores: List[int] = []
|
| 263 |
-
self.work_queue: List[QuantumWorkPacket] = []
|
| 264 |
-
self.coherence_time = 1e-12 # Coherence time in seconds
|
| 265 |
-
self.last_decoherence = time.time()
|
| 266 |
-
self.channel_lock = threading.Lock()
|
| 267 |
-
|
| 268 |
-
def distribute_work(self, work: QuantumWorkPacket) -> None:
|
| 269 |
-
"""Distribute work through quantum channel"""
|
| 270 |
-
with self.channel_lock:
|
| 271 |
-
# Update quantum state
|
| 272 |
-
current_time = time.time()
|
| 273 |
-
if current_time - self.last_decoherence > self.coherence_time:
|
| 274 |
-
# Perform quantum state refresh
|
| 275 |
-
self.quantum_state = np.random.normal(0, 1, 256) + 1j * np.random.normal(0, 1, 256)
|
| 276 |
-
self.quantum_state /= np.linalg.norm(self.quantum_state)
|
| 277 |
-
self.last_decoherence = current_time
|
| 278 |
-
|
| 279 |
-
# Encode work packet into quantum state
|
| 280 |
-
packet_hash = hash((work.block_header, work.nonce_range[0], work.nonce_range[1]))
|
| 281 |
-
phase = 2 * np.pi * (packet_hash % 256) / 256
|
| 282 |
-
self.quantum_state *= np.exp(1j * phase)
|
| 283 |
-
|
| 284 |
-
self.work_queue.append(work)
|
| 285 |
-
|
| 286 |
-
def receive_work(self, core_id: int) -> Optional[QuantumWorkPacket]:
|
| 287 |
-
"""Receive work from quantum channel"""
|
| 288 |
-
with self.channel_lock:
|
| 289 |
-
if not self.work_queue:
|
| 290 |
-
return None
|
| 291 |
-
|
| 292 |
-
# Find work packet with highest priority for this core
|
| 293 |
-
best_packet = None
|
| 294 |
-
best_priority = -1
|
| 295 |
-
|
| 296 |
-
for packet in self.work_queue:
|
| 297 |
-
# Calculate priority based on quantum state alignment
|
| 298 |
-
state_overlap = abs(np.sum(self.quantum_state)) / 256
|
| 299 |
-
priority = packet.priority * state_overlap
|
| 300 |
-
|
| 301 |
-
if priority > best_priority:
|
| 302 |
-
best_packet = packet
|
| 303 |
-
best_priority = priority
|
| 304 |
-
|
| 305 |
-
if best_packet:
|
| 306 |
-
self.work_queue.remove(best_packet)
|
| 307 |
-
return best_packet
|
| 308 |
-
|
| 309 |
class ParallelMiner:
|
| 310 |
-
"""Top-level parallel miner managing multiple cores
|
| 311 |
-
def __init__(self, num_cores: int = 7, wallet_address: str = None
|
| 312 |
self.cores = [MiningCore(i) for i in range(num_cores)]
|
| 313 |
self.start_time = None
|
| 314 |
self.mining = False
|
|
@@ -321,9 +147,8 @@ class ParallelMiner:
|
|
| 321 |
self.hashes_last_update = 0
|
| 322 |
self.last_hashrate_update = time.time()
|
| 323 |
self.current_hashrate = 0
|
| 324 |
-
self.network = NetworkIntegration(wallet_address
|
| 325 |
-
self.
|
| 326 |
-
self.network.connect() # Connect to testnet
|
| 327 |
|
| 328 |
# Calculate initial network difficulty
|
| 329 |
template = self.network.get_block_template()
|
|
@@ -356,7 +181,7 @@ class ParallelMiner:
|
|
| 356 |
logging.info(f"Network target: {hex(target)}")
|
| 357 |
|
| 358 |
except Exception as e:
|
| 359 |
-
logging.warning(f"Failed to get network template: {e}, using
|
| 360 |
# Fallback to test values
|
| 361 |
version = 2
|
| 362 |
prev_block = b'\x00' * 32
|
|
@@ -379,10 +204,10 @@ class ParallelMiner:
|
|
| 379 |
self.last_template_update = time.time()
|
| 380 |
block_header, target = self._setup_block_header()
|
| 381 |
|
| 382 |
-
logging.info("Starting parallel
|
| 383 |
logging.info(f"Cores: {len(self.cores)}")
|
| 384 |
logging.info(f"Units per core: {len(self.cores[0].units)}")
|
| 385 |
-
logging.info("Connected to
|
| 386 |
|
| 387 |
with ThreadPoolExecutor(max_workers=len(self.cores)) as executor:
|
| 388 |
base_nonce = 0
|
|
@@ -390,11 +215,10 @@ class ParallelMiner:
|
|
| 390 |
while self.mining and (duration is None or time.time() - self.start_time < duration):
|
| 391 |
# Update block template every 30 seconds
|
| 392 |
current_time = time.time()
|
| 393 |
-
if current_time - self.last_template_update > 600: # Update every 10 minutes
|
| 394 |
block_header, target = self._setup_block_header()
|
| 395 |
self.last_template_update = current_time
|
| 396 |
-
|
| 397 |
-
logging.info("Updated block template from network")
|
| 398 |
|
| 399 |
futures = []
|
| 400 |
|
|
@@ -428,52 +252,93 @@ class ParallelMiner:
|
|
| 428 |
# Log progress for this core
|
| 429 |
elapsed = time.time() - self.start_time
|
| 430 |
|
| 431 |
-
logging.info(f"Core {core_id}: {self.total_hashes:,} hashes, {self.blocks_found} blocks, {self.current_hashrate/1000:.2f} KH/s")
|
|
|
|
|
|
|
| 432 |
for unit in result['unit_results']:
|
| 433 |
if unit['nonce'] != -1:
|
| 434 |
# Found a block or better hash
|
| 435 |
current_hash_int = int.from_bytes(unit['hash'], byteorder='little')
|
| 436 |
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 475 |
|
| 476 |
-
base_nonce += len(self.cores) * 1500
|
| 477 |
|
| 478 |
# Log final results
|
| 479 |
self.log_final_results(duration)
|
|
@@ -503,7 +368,7 @@ class ParallelMiner:
|
|
| 503 |
if __name__ == "__main__":
|
| 504 |
miner = ParallelMiner()
|
| 505 |
try:
|
| 506 |
-
miner.start_mining(duration=
|
| 507 |
except KeyboardInterrupt:
|
| 508 |
miner.mining = False
|
| 509 |
logging.info("\nMining stopped by user")
|
|
|
|
| 1 |
"""
|
| 2 |
+
Bitcoin mining implementation with hardware-accurate SHA-256 and proper block finding
|
| 3 |
"""
|
| 4 |
import hashlib
|
| 5 |
import struct
|
|
|
|
| 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(
|
|
|
|
| 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 * 10020000 # Hz
|
|
|
|
| 37 |
|
| 38 |
# Silicon process parameters
|
| 39 |
self.path_length = 14e-9 # meters (14nm process node)
|
|
|
|
| 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]:
|
|
|
|
| 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 = 8):
|
| 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 = 3981870 # Each unit processes this many nonces per round
|
| 109 |
results = []
|
| 110 |
|
| 111 |
for i, unit in enumerate(self.units):
|
|
|
|
| 132 |
'unit_results': results
|
| 133 |
}
|
| 134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
class ParallelMiner:
|
| 136 |
+
"""Top-level parallel miner managing multiple cores"""
|
| 137 |
+
def __init__(self, num_cores: int = 7, wallet_address: str = None):
|
| 138 |
self.cores = [MiningCore(i) for i in range(num_cores)]
|
| 139 |
self.start_time = None
|
| 140 |
self.mining = False
|
|
|
|
| 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 network
|
|
|
|
| 152 |
|
| 153 |
# Calculate initial network difficulty
|
| 154 |
template = self.network.get_block_template()
|
|
|
|
| 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 fallback values")
|
| 185 |
# Fallback to test values
|
| 186 |
version = 2
|
| 187 |
prev_block = b'\x00' * 32
|
|
|
|
| 204 |
self.last_template_update = time.time()
|
| 205 |
block_header, target = self._setup_block_header()
|
| 206 |
|
| 207 |
+
logging.info("Starting parallel Bitcoin mining...")
|
| 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 network, getting block templates")
|
| 211 |
|
| 212 |
with ThreadPoolExecutor(max_workers=len(self.cores)) as executor:
|
| 213 |
base_nonce = 0
|
|
|
|
| 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 > 600: # Update every 10 minutes
|
| 219 |
block_header, target = self._setup_block_header()
|
| 220 |
self.last_template_update = current_time
|
| 221 |
+
logging.info("Updated block template from network - continuing with current nonce range")
|
|
|
|
| 222 |
|
| 223 |
futures = []
|
| 224 |
|
|
|
|
| 252 |
# Log progress for this core
|
| 253 |
elapsed = time.time() - self.start_time
|
| 254 |
|
| 255 |
+
logging.info(f"Core {core_id}: {self.total_hashes:,} hashes, {self.blocks_found} blocks, {self.current_hashrate/1000:.2f} KH/s")
|
| 256 |
+
|
| 257 |
+
# Check unit results for blocks
|
| 258 |
for unit in result['unit_results']:
|
| 259 |
if unit['nonce'] != -1:
|
| 260 |
# Found a block or better hash
|
| 261 |
current_hash_int = int.from_bytes(unit['hash'], byteorder='little')
|
| 262 |
|
| 263 |
+
# Track best hash
|
| 264 |
+
if not self.best_hash or current_hash_int < int.from_bytes(self.best_hash, byteorder='little'):
|
| 265 |
+
self.best_hash = unit['hash']
|
| 266 |
+
self.best_nonce = unit['nonce']
|
| 267 |
+
|
| 268 |
+
# Compare with current target and submit if valid
|
| 269 |
+
if current_hash_int < target: # Use current target, not new template target
|
| 270 |
+
logging.info(f"Found valid block! Hash is below target")
|
| 271 |
+
logging.info(f"Core {core_id}, Unit {unit['unit_id']} found the block")
|
| 272 |
+
logging.info(f"Block details:")
|
| 273 |
+
logging.info(f" Hash: {unit['hash'].hex()}")
|
| 274 |
+
logging.info(f" Nonce: {unit['nonce']}")
|
| 275 |
+
logging.info(f" Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
| 276 |
+
|
| 277 |
+
# Prepare block data
|
| 278 |
+
block_data = block_header[:-4] + struct.pack('<I', unit['nonce'])
|
| 279 |
+
|
| 280 |
+
# Log submission attempt details
|
| 281 |
+
logging.info("Block submission details:")
|
| 282 |
+
logging.info(f"Block header length: {len(block_header)}")
|
| 283 |
+
logging.info(f"Final block data length: {len(block_data)}")
|
| 284 |
+
logging.info(f"Target used: {hex(target)}")
|
| 285 |
+
logging.info(f"Hash achieved: {hex(current_hash_int)}")
|
| 286 |
+
|
| 287 |
+
try:
|
| 288 |
+
logging.info("π Attempting to submit block to network...")
|
| 289 |
+
if self.network.submit_block(block_data, unit['nonce']):
|
| 290 |
+
logging.info("π Block successfully submitted to network! π")
|
| 291 |
+
logging.info(f"Block hash: {unit['hash'].hex()}")
|
| 292 |
+
logging.info(f"Nonce: {unit['nonce']}")
|
| 293 |
+
logging.info(f"Difficulty: {self.network_difficulty:,.2f}")
|
| 294 |
+
|
| 295 |
+
# Extra verification
|
| 296 |
+
verify_hash = self.double_sha256(block_data)
|
| 297 |
+
verify_int = int.from_bytes(verify_hash, 'little')
|
| 298 |
+
logging.info(f"Verification hash: {hex(verify_int)}")
|
| 299 |
+
logging.info(f"Matches original: {verify_int == current_hash_int}")
|
| 300 |
+
else:
|
| 301 |
+
logging.error("β Block submission failed")
|
| 302 |
+
logging.error("Detailed diagnostics:")
|
| 303 |
+
logging.error(f"- Block header hex: {block_header.hex()}")
|
| 304 |
+
logging.error(f"- Final nonce used: {unit['nonce']}")
|
| 305 |
+
logging.error(f"- Hash achieved: {unit['hash'].hex()}")
|
| 306 |
+
logging.error("Common failure reasons:")
|
| 307 |
+
logging.error("- Network connectivity issues")
|
| 308 |
+
logging.error("- Block became stale")
|
| 309 |
+
logging.error("- Invalid block structure")
|
| 310 |
+
logging.error("- Target difficulty mismatch")
|
| 311 |
+
except Exception as e:
|
| 312 |
+
logging.error(f"β Exception during block submission: {str(e)}")
|
| 313 |
+
logging.error(f"Block data length: {len(block_data)}")
|
| 314 |
+
logging.error(f"Nonce value: {unit['nonce']}")
|
| 315 |
+
logging.exception("Full exception details:")
|
| 316 |
+
else:
|
| 317 |
+
hash_hex = hex(current_hash_int)[2:].zfill(64)
|
| 318 |
+
target_hex = hex(target)[2:].zfill(64)
|
| 319 |
+
|
| 320 |
+
# Calculate difficulty (max_target / hash)
|
| 321 |
+
max_target = 0xFFFF * 2**(8*(0x1d - 3))
|
| 322 |
+
hash_difficulty = float(max_target) / float(current_hash_int)
|
| 323 |
+
|
| 324 |
+
# Calculate percentage based on leading zeros
|
| 325 |
+
leading_zeros = len(hash_hex) - len(hash_hex.lstrip('0'))
|
| 326 |
+
target_zeros = len(target_hex) - len(target_hex.lstrip('0'))
|
| 327 |
+
|
| 328 |
+
# Progress based on zeros and first non-zero byte
|
| 329 |
+
first_byte_progress = (255 - int(hash_hex[leading_zeros:leading_zeros+2], 16)) / 255.0
|
| 330 |
+
progress_percent = (leading_zeros / float(target_zeros) + first_byte_progress / target_zeros) * 100
|
| 331 |
+
|
| 332 |
+
# Update best hash difficulty if this is higher
|
| 333 |
+
self.best_hash_difficulty = max(self.best_hash_difficulty, hash_difficulty)
|
| 334 |
+
|
| 335 |
+
logging.info(f"New best hash found!")
|
| 336 |
+
logging.info(f"Best hash: {hash_hex}")
|
| 337 |
+
logging.info(f"Need target: {target_hex}")
|
| 338 |
+
logging.info(f"Progress to target: {progress_percent:.8f}%")
|
| 339 |
+
logging.info(f"Hash difficulty: {hash_difficulty:.8f} (higher is better)")
|
| 340 |
|
| 341 |
+
base_nonce += len(self.cores) * 1500 # Increment base_nonce within the main loop
|
| 342 |
|
| 343 |
# Log final results
|
| 344 |
self.log_final_results(duration)
|
|
|
|
| 368 |
if __name__ == "__main__":
|
| 369 |
miner = ParallelMiner()
|
| 370 |
try:
|
| 371 |
+
miner.start_mining(duration=500)
|
| 372 |
except KeyboardInterrupt:
|
| 373 |
miner.mining = False
|
| 374 |
logging.info("\nMining stopped by user")
|