Update parallel_miner_v3.py
Browse files- parallel_miner_v3.py +81 -55
parallel_miner_v3.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
-
|
| 3 |
"""
|
| 4 |
import hashlib
|
| 5 |
import struct
|
|
@@ -33,7 +33,7 @@ class HashUnit:
|
|
| 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
|
| 37 |
|
| 38 |
# Silicon process parameters
|
| 39 |
self.path_length = 14e-9 # meters (14nm process node)
|
|
@@ -42,7 +42,7 @@ class HashUnit:
|
|
| 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 =
|
| 46 |
|
| 47 |
self.last_cycle_time = time.time()
|
| 48 |
|
|
@@ -60,7 +60,7 @@ class HashUnit:
|
|
| 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.
|
| 64 |
# Factor in switching frequency to determine valid operations
|
| 65 |
operations_this_cycle = int(min(
|
| 66 |
electron_transits,
|
|
@@ -97,7 +97,7 @@ class HashUnit:
|
|
| 97 |
|
| 98 |
class MiningCore:
|
| 99 |
"""Mining core that manages multiple hash units"""
|
| 100 |
-
def __init__(self, core_id: int, num_units: int =
|
| 101 |
self.core_id = core_id
|
| 102 |
self.units = [HashUnit(i) for i in range(num_units)]
|
| 103 |
self.total_hashes = 0
|
|
@@ -105,7 +105,7 @@ class MiningCore:
|
|
| 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 =
|
| 109 |
results = []
|
| 110 |
|
| 111 |
for i, unit in enumerate(self.units):
|
|
@@ -134,7 +134,7 @@ class MiningCore:
|
|
| 134 |
|
| 135 |
class ParallelMiner:
|
| 136 |
"""Top-level parallel miner managing multiple cores"""
|
| 137 |
-
def __init__(self, num_cores: int =
|
| 138 |
self.cores = [MiningCore(i) for i in range(num_cores)]
|
| 139 |
self.start_time = None
|
| 140 |
self.mining = False
|
|
@@ -148,7 +148,7 @@ class ParallelMiner:
|
|
| 148 |
self.last_hashrate_update = time.time()
|
| 149 |
self.current_hashrate = 0
|
| 150 |
self.network = NetworkIntegration(wallet_address)
|
| 151 |
-
self.network.connect() # Connect to
|
| 152 |
|
| 153 |
# Calculate initial network difficulty
|
| 154 |
template = self.network.get_block_template()
|
|
@@ -181,7 +181,7 @@ class ParallelMiner:
|
|
| 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
|
| 185 |
# Fallback to test values
|
| 186 |
version = 2
|
| 187 |
prev_block = b'\x00' * 32
|
|
@@ -204,10 +204,10 @@ class ParallelMiner:
|
|
| 204 |
self.last_template_update = time.time()
|
| 205 |
block_header, target = self._setup_block_header()
|
| 206 |
|
| 207 |
-
logging.info("Starting parallel
|
| 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
|
| 211 |
|
| 212 |
with ThreadPoolExecutor(max_workers=len(self.cores)) as executor:
|
| 213 |
base_nonce = 0
|
|
@@ -215,11 +215,10 @@ class ParallelMiner:
|
|
| 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 >
|
| 219 |
block_header, target = self._setup_block_header()
|
| 220 |
self.last_template_update = current_time
|
| 221 |
-
|
| 222 |
-
logging.info("Updated block template from network")
|
| 223 |
|
| 224 |
futures = []
|
| 225 |
|
|
@@ -253,51 +252,78 @@ class ParallelMiner:
|
|
| 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")
|
|
|
|
|
|
|
| 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 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
|
| 302 |
# Log final results
|
| 303 |
self.log_final_results(duration)
|
|
@@ -327,7 +353,7 @@ class ParallelMiner:
|
|
| 327 |
if __name__ == "__main__":
|
| 328 |
miner = ParallelMiner()
|
| 329 |
try:
|
| 330 |
-
miner.start_mining(duration=
|
| 331 |
except KeyboardInterrupt:
|
| 332 |
miner.mining = False
|
| 333 |
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
|
|
|
|
| 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)
|
|
|
|
| 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 |
|
|
|
|
| 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.92e955
|
| 64 |
# Factor in switching frequency to determine valid operations
|
| 65 |
operations_this_cycle = int(min(
|
| 66 |
electron_transits,
|
|
|
|
| 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
|
|
|
|
| 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):
|
|
|
|
| 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
|
|
|
|
| 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 |
+
# Check if hash is below network target and submit immediately if it is
|
| 269 |
+
template = self.network.get_block_template()
|
| 270 |
+
logging.info(f"Checking hash against network target...")
|
| 271 |
+
logging.info(f"Current hash: {hex(current_hash_int)}")
|
| 272 |
+
logging.info(f"Network target: {hex(template['target'])}")
|
| 273 |
+
|
| 274 |
+
if current_hash_int < template['target']:
|
| 275 |
+
logging.info(f"Found valid block! Hash is below network target")
|
| 276 |
+
logging.info(f"Core {core_id}, Unit {unit['unit_id']} found the block")
|
| 277 |
+
logging.info(f"Block details:")
|
| 278 |
+
logging.info(f" Hash: {unit['hash'].hex()}")
|
| 279 |
+
logging.info(f" Nonce: {unit['nonce']}")
|
| 280 |
+
logging.info(f" Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
| 281 |
+
|
| 282 |
+
try:
|
| 283 |
+
block_data = block_header[:-4] + struct.pack('<I', unit['nonce'])
|
| 284 |
+
logging.info("Attempting to submit block to network...")
|
| 285 |
+
if self.network.submit_block(block_data, unit['nonce']):
|
| 286 |
+
logging.info("🎉 Block successfully submitted to network! 🎉")
|
| 287 |
+
logging.info(f"Block hash: {unit['hash'].hex()}")
|
| 288 |
+
logging.info(f"Nonce: {unit['nonce']}")
|
| 289 |
+
logging.info(f"Difficulty: {self.network_difficulty:,.2f}")
|
| 290 |
+
else:
|
| 291 |
+
logging.error("❌ Block submission failed")
|
| 292 |
+
logging.error("This could be due to:")
|
| 293 |
+
logging.error("- Network connectivity issues")
|
| 294 |
+
logging.error("- Block became stale")
|
| 295 |
+
logging.error("- Invalid block structure")
|
| 296 |
+
except Exception as e:
|
| 297 |
+
logging.error(f"❌ Exception during block submission: {str(e)}")
|
| 298 |
+
logging.error(f"Block data length: {len(block_data)}")
|
| 299 |
+
logging.error(f"Nonce value: {unit['nonce']}")
|
| 300 |
+
logging.exception("Full exception details:")
|
| 301 |
+
else:
|
| 302 |
+
hash_hex = hex(current_hash_int)[2:].zfill(64)
|
| 303 |
+
target_hex = hex(template['target'])[2:].zfill(64)
|
| 304 |
+
|
| 305 |
+
# Calculate difficulty (max_target / hash)
|
| 306 |
+
max_target = 0xFFFF * 2**(8*(0x1d - 3))
|
| 307 |
+
hash_difficulty = float(max_target) / float(current_hash_int)
|
| 308 |
+
|
| 309 |
+
# Calculate percentage based on leading zeros
|
| 310 |
+
leading_zeros = len(hash_hex) - len(hash_hex.lstrip('0'))
|
| 311 |
+
target_zeros = len(target_hex) - len(target_hex.lstrip('0'))
|
| 312 |
+
|
| 313 |
+
# Progress based on zeros and first non-zero byte
|
| 314 |
+
first_byte_progress = (255 - int(hash_hex[leading_zeros:leading_zeros+2], 16)) / 255.0
|
| 315 |
+
progress_percent = (leading_zeros / float(target_zeros) + first_byte_progress / target_zeros) * 100
|
| 316 |
+
|
| 317 |
+
# Update best hash difficulty if this is higher
|
| 318 |
+
self.best_hash_difficulty = max(self.best_hash_difficulty, hash_difficulty)
|
| 319 |
+
|
| 320 |
+
logging.info(f"New best hash found!")
|
| 321 |
+
logging.info(f"Best hash: {hash_hex}")
|
| 322 |
+
logging.info(f"Need target: {target_hex}")
|
| 323 |
+
logging.info(f"Progress to target: {progress_percent:.8f}%")
|
| 324 |
+
logging.info(f"Hash difficulty: {hash_difficulty:.8f} (higher is better)")
|
| 325 |
+
|
| 326 |
+
base_nonce += len(self.cores) * 1500
|
| 327 |
|
| 328 |
# Log final results
|
| 329 |
self.log_final_results(duration)
|
|
|
|
| 353 |
if __name__ == "__main__":
|
| 354 |
miner = ParallelMiner()
|
| 355 |
try:
|
| 356 |
+
miner.start_mining(duration=500)
|
| 357 |
except KeyboardInterrupt:
|
| 358 |
miner.mining = False
|
| 359 |
logging.info("\nMining stopped by user")
|