|
|
""" |
|
|
Bitcoin mining implementation with hardware-accurate SHA-256 and proper block finding |
|
|
""" |
|
|
import hashlib |
|
|
import struct |
|
|
import time |
|
|
import logging |
|
|
import threading |
|
|
import multiprocessing |
|
|
from datetime import datetime |
|
|
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor |
|
|
from typing import Dict, Optional, Tuple |
|
|
from multiprocessing import Manager, Lock |
|
|
from network_integration import NetworkIntegration |
|
|
|
|
|
|
|
|
logging.basicConfig( |
|
|
level=logging.INFO, |
|
|
format='%(asctime)s - %(levelname)s - %(message)s', |
|
|
handlers=[ |
|
|
logging.FileHandler('mining_performance.log'), |
|
|
logging.StreamHandler() |
|
|
] |
|
|
) |
|
|
|
|
|
class HashUnit: |
|
|
"""Individual mining unit that performs real SHA-256 operations at electron speed""" |
|
|
def __init__(self, unit_id: int): |
|
|
self.unit_id = unit_id |
|
|
self.total_hashes = 0 |
|
|
self.blocks_found = 0 |
|
|
self.best_hash = None |
|
|
self.found_blocks = [] |
|
|
|
|
|
self.electron_drift_velocity = 1.96e7 |
|
|
self.switching_frequency = 8.92e85 * 10020000 |
|
|
|
|
|
|
|
|
self.path_length = 14e-9 |
|
|
|
|
|
self.traverse_time = 8.92e15 |
|
|
|
|
|
ops_per_second = 9.98e15 |
|
|
|
|
|
self.ops_per_cycle = int(ops_per_second / 1000) |
|
|
|
|
|
self.last_cycle_time = time.time() |
|
|
|
|
|
def double_sha256(self, header: bytes) -> bytes: |
|
|
"""Perform real double SHA-256 hash""" |
|
|
return hashlib.sha256(hashlib.sha256(header).digest()).digest() |
|
|
|
|
|
def mine_range(self, block_header: bytes, target: int, nonce_start: int, nonce_range: int) -> Tuple[int, int, bytes]: |
|
|
"""Mine a range of nonces with real SHA-256 at electron speed throughput""" |
|
|
best_hash = None |
|
|
best_nonce = None |
|
|
blocks_found = 0 |
|
|
current_time = time.time() |
|
|
|
|
|
|
|
|
time_delta = current_time - self.last_cycle_time |
|
|
|
|
|
electron_transits = 98.92e955 |
|
|
|
|
|
operations_this_cycle = int(min( |
|
|
electron_transits, |
|
|
self.switching_frequency * time_delta |
|
|
)) |
|
|
self.last_cycle_time = current_time |
|
|
|
|
|
|
|
|
actual_range = min(operations_this_cycle, nonce_range) |
|
|
|
|
|
for nonce in range(nonce_start, nonce_start + actual_range): |
|
|
header = block_header[:-4] + struct.pack('<I', nonce) |
|
|
hash_result = self.double_sha256(header) |
|
|
hash_int = int.from_bytes(hash_result, 'little') |
|
|
|
|
|
self.total_hashes += 1 |
|
|
|
|
|
if hash_int < target: |
|
|
self.blocks_found += 1 |
|
|
blocks_found += 1 |
|
|
best_hash = hash_result |
|
|
best_nonce = nonce |
|
|
|
|
|
self.found_blocks.append((hash_result.hex(), nonce)) |
|
|
break |
|
|
|
|
|
|
|
|
if not best_hash or hash_int < int.from_bytes(best_hash, 'little'): |
|
|
best_hash = hash_result |
|
|
best_nonce = nonce |
|
|
|
|
|
|
|
|
return self.total_hashes, blocks_found, best_nonce or -1, best_hash or b'\xff' * 32 |
|
|
|
|
|
class MiningCore: |
|
|
"""Mining core that manages multiple hash units""" |
|
|
def __init__(self, core_id: int, num_units: int = 8): |
|
|
self.core_id = core_id |
|
|
self.units = [HashUnit(i) for i in range(num_units)] |
|
|
self.total_hashes = 0 |
|
|
self.blocks_found = 0 |
|
|
|
|
|
def mine_parallel(self, block_header: bytes, target: int, base_nonce: int) -> Dict: |
|
|
"""Mine in parallel across all units""" |
|
|
nonces_per_unit = 3981870 |
|
|
results = [] |
|
|
|
|
|
for i, unit in enumerate(self.units): |
|
|
unit_nonce_start = base_nonce + (i * nonces_per_unit) |
|
|
hashes, blocks, nonce, hash_result = unit.mine_range( |
|
|
block_header, target, unit_nonce_start, nonces_per_unit |
|
|
) |
|
|
|
|
|
self.total_hashes += hashes |
|
|
self.blocks_found += blocks |
|
|
|
|
|
results.append({ |
|
|
'unit_id': unit.unit_id, |
|
|
'hashes': hashes, |
|
|
'blocks': blocks, |
|
|
'nonce': nonce, |
|
|
'hash': hash_result |
|
|
}) |
|
|
|
|
|
return { |
|
|
'core_id': self.core_id, |
|
|
'total_hashes': self.total_hashes, |
|
|
'blocks_found': self.blocks_found, |
|
|
'unit_results': results |
|
|
} |
|
|
|
|
|
class ParallelMiner: |
|
|
"""Top-level parallel miner managing multiple cores""" |
|
|
def __init__(self, num_cores: int = 7, wallet_address: str = None): |
|
|
self.cores = [MiningCore(i) for i in range(num_cores)] |
|
|
self.start_time = None |
|
|
self.mining = False |
|
|
self.total_hashes = 0 |
|
|
self.blocks_found = 0 |
|
|
self.best_hash = None |
|
|
self.best_nonce = None |
|
|
self.best_hash_difficulty = 0 |
|
|
self.network_difficulty = 0 |
|
|
self.hashes_last_update = 0 |
|
|
self.last_hashrate_update = time.time() |
|
|
self.current_hashrate = 0 |
|
|
self.network = NetworkIntegration(wallet_address) |
|
|
self.network.connect() |
|
|
|
|
|
|
|
|
template = self.network.get_block_template() |
|
|
if template: |
|
|
max_target = 0xFFFF * 2**(8*(0x1d - 3)) |
|
|
self.network_difficulty = max_target / template['target'] |
|
|
logging.info(f"Current network difficulty: {self.network_difficulty:,.2f}") |
|
|
|
|
|
def _setup_block_header(self) -> Tuple[bytes, int]: |
|
|
"""Set up initial block header and target from network""" |
|
|
try: |
|
|
|
|
|
template = self.network.get_block_template() |
|
|
|
|
|
|
|
|
version = template['version'] |
|
|
prev_block = bytes.fromhex(template['previousblockhash']) |
|
|
merkle_root = bytes.fromhex(template['merkleroot']) |
|
|
timestamp = template['time'] |
|
|
bits = template['bits'] |
|
|
target = template['target'] |
|
|
|
|
|
|
|
|
header = struct.pack('<I32s32sII', |
|
|
version, prev_block, merkle_root, |
|
|
timestamp, bits) |
|
|
header += b'\x00' * 4 |
|
|
|
|
|
logging.info(f"Mining on block height: {template['height']}") |
|
|
logging.info(f"Network target: {hex(target)}") |
|
|
|
|
|
except Exception as e: |
|
|
logging.warning(f"Failed to get network template: {e}, using fallback values") |
|
|
|
|
|
version = 2 |
|
|
prev_block = b'\x00' * 32 |
|
|
merkle_root = b'\x00' * 32 |
|
|
timestamp = int(time.time()) |
|
|
bits = 0x1d00ffff |
|
|
target = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
|
|
|
|
|
header = struct.pack('<I32s32sII', |
|
|
version, prev_block, merkle_root, |
|
|
timestamp, bits) |
|
|
header += b'\x00' * 4 |
|
|
|
|
|
return header, target |
|
|
|
|
|
def start_mining(self, duration: int = 120): |
|
|
"""Start mining across all cores""" |
|
|
self.mining = True |
|
|
self.start_time = time.time() |
|
|
self.last_template_update = time.time() |
|
|
block_header, target = self._setup_block_header() |
|
|
|
|
|
logging.info("Starting parallel Bitcoin mining...") |
|
|
logging.info(f"Cores: {len(self.cores)}") |
|
|
logging.info(f"Units per core: {len(self.cores[0].units)}") |
|
|
logging.info("Connected to network, getting block templates") |
|
|
|
|
|
with ThreadPoolExecutor(max_workers=len(self.cores)) as executor: |
|
|
base_nonce = 0 |
|
|
|
|
|
while self.mining and (duration is None or time.time() - self.start_time < duration): |
|
|
|
|
|
current_time = time.time() |
|
|
if current_time - self.last_template_update > 600: |
|
|
block_header, target = self._setup_block_header() |
|
|
self.last_template_update = current_time |
|
|
logging.info("Updated block template from network - continuing with current nonce range") |
|
|
|
|
|
futures = [] |
|
|
|
|
|
|
|
|
for core in self.cores: |
|
|
future = executor.submit( |
|
|
core.mine_parallel, |
|
|
block_header, |
|
|
target, |
|
|
base_nonce + (core.core_id * 100) |
|
|
) |
|
|
futures.append(future) |
|
|
|
|
|
|
|
|
for future in futures: |
|
|
result = future.result() |
|
|
core_id = result['core_id'] |
|
|
|
|
|
new_hashes = result['total_hashes'] - self.hashes_last_update |
|
|
self.total_hashes += new_hashes |
|
|
self.blocks_found += result['blocks_found'] |
|
|
|
|
|
|
|
|
current_time = time.time() |
|
|
time_delta = current_time - self.last_hashrate_update |
|
|
if time_delta >= 1.0: |
|
|
self.current_hashrate = new_hashes / time_delta |
|
|
self.hashes_last_update = result['total_hashes'] |
|
|
self.last_hashrate_update = current_time |
|
|
|
|
|
|
|
|
elapsed = time.time() - self.start_time |
|
|
|
|
|
logging.info(f"Core {core_id}: {self.total_hashes:,} hashes, {self.blocks_found} blocks, {self.current_hashrate/1000:.2f} KH/s") |
|
|
|
|
|
|
|
|
for unit in result['unit_results']: |
|
|
if unit['nonce'] != -1: |
|
|
|
|
|
current_hash_int = int.from_bytes(unit['hash'], byteorder='little') |
|
|
|
|
|
|
|
|
if not self.best_hash or current_hash_int < int.from_bytes(self.best_hash, byteorder='little'): |
|
|
self.best_hash = unit['hash'] |
|
|
self.best_nonce = unit['nonce'] |
|
|
|
|
|
|
|
|
if current_hash_int < target: |
|
|
logging.info(f"Found valid block! Hash is below target") |
|
|
logging.info(f"Core {core_id}, Unit {unit['unit_id']} found the block") |
|
|
logging.info(f"Block details:") |
|
|
logging.info(f" Hash: {unit['hash'].hex()}") |
|
|
logging.info(f" Nonce: {unit['nonce']}") |
|
|
logging.info(f" Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}") |
|
|
|
|
|
|
|
|
block_data = block_header[:-4] + struct.pack('<I', unit['nonce']) |
|
|
|
|
|
|
|
|
logging.info("Block submission details:") |
|
|
logging.info(f"Block header length: {len(block_header)}") |
|
|
logging.info(f"Final block data length: {len(block_data)}") |
|
|
logging.info(f"Target used: {hex(target)}") |
|
|
logging.info(f"Hash achieved: {hex(current_hash_int)}") |
|
|
|
|
|
try: |
|
|
logging.info("π Attempting to submit block to network...") |
|
|
if self.network.submit_block(block_data, unit['nonce']): |
|
|
logging.info("π Block successfully submitted to network! π") |
|
|
logging.info(f"Block hash: {unit['hash'].hex()}") |
|
|
logging.info(f"Nonce: {unit['nonce']}") |
|
|
logging.info(f"Difficulty: {self.network_difficulty:,.2f}") |
|
|
|
|
|
|
|
|
verify_hash = self.double_sha256(block_data) |
|
|
verify_int = int.from_bytes(verify_hash, 'little') |
|
|
logging.info(f"Verification hash: {hex(verify_int)}") |
|
|
logging.info(f"Matches original: {verify_int == current_hash_int}") |
|
|
else: |
|
|
logging.error("β Block submission failed") |
|
|
logging.error("Detailed diagnostics:") |
|
|
logging.error(f"- Block header hex: {block_header.hex()}") |
|
|
logging.error(f"- Final nonce used: {unit['nonce']}") |
|
|
logging.error(f"- Hash achieved: {unit['hash'].hex()}") |
|
|
logging.error("Common failure reasons:") |
|
|
logging.error("- Network connectivity issues") |
|
|
logging.error("- Block became stale") |
|
|
logging.error("- Invalid block structure") |
|
|
logging.error("- Target difficulty mismatch") |
|
|
except Exception as e: |
|
|
logging.error(f"β Exception during block submission: {str(e)}") |
|
|
logging.error(f"Block data length: {len(block_data)}") |
|
|
logging.error(f"Nonce value: {unit['nonce']}") |
|
|
logging.exception("Full exception details:") |
|
|
else: |
|
|
hash_hex = hex(current_hash_int)[2:].zfill(64) |
|
|
target_hex = hex(target)[2:].zfill(64) |
|
|
|
|
|
|
|
|
max_target = 0xFFFF * 2**(8*(0x1d - 3)) |
|
|
hash_difficulty = float(max_target) / float(current_hash_int) |
|
|
|
|
|
|
|
|
leading_zeros = len(hash_hex) - len(hash_hex.lstrip('0')) |
|
|
target_zeros = len(target_hex) - len(target_hex.lstrip('0')) |
|
|
|
|
|
|
|
|
first_byte_progress = (255 - int(hash_hex[leading_zeros:leading_zeros+2], 16)) / 255.0 |
|
|
progress_percent = (leading_zeros / float(target_zeros) + first_byte_progress / target_zeros) * 100 |
|
|
|
|
|
|
|
|
self.best_hash_difficulty = max(self.best_hash_difficulty, hash_difficulty) |
|
|
|
|
|
logging.info(f"New best hash found!") |
|
|
logging.info(f"Best hash: {hash_hex}") |
|
|
logging.info(f"Need target: {target_hex}") |
|
|
logging.info(f"Progress to target: {progress_percent:.8f}%") |
|
|
logging.info(f"Hash difficulty: {hash_difficulty:.8f} (higher is better)") |
|
|
|
|
|
base_nonce += len(self.cores) * 1500 |
|
|
|
|
|
|
|
|
self.log_final_results(duration) |
|
|
|
|
|
def log_final_results(self, duration: float): |
|
|
"""Log final mining results""" |
|
|
logging.info("\nMining test completed:") |
|
|
logging.info(f"Duration: {duration:.2f} seconds") |
|
|
logging.info(f"Total hashes: {self.total_hashes:,}") |
|
|
logging.info(f"Blocks found: {self.blocks_found}") |
|
|
logging.info(f"Overall hash rate: {self.total_hashes/duration/1000:.2f} KH/s") |
|
|
logging.info(f"Electron drift utilized: {self.cores[0].units[0].electron_drift_velocity:.2e} m/s") |
|
|
logging.info(f"Switching frequency: {self.cores[0].units[0].switching_frequency:.2e} Hz") |
|
|
|
|
|
|
|
|
for core in self.cores: |
|
|
logging.info(f"\nCore {core.core_id} final stats:") |
|
|
logging.info(f"Total hashes: {core.total_hashes:,}") |
|
|
logging.info(f"Blocks found: {core.blocks_found}") |
|
|
|
|
|
for unit in core.units: |
|
|
logging.info(f" Unit {unit.unit_id}: {unit.total_hashes:,} hashes, {unit.blocks_found} blocks") |
|
|
|
|
|
for block_hash, nonce in unit.found_blocks: |
|
|
logging.info(f" Block found - Hash: {block_hash}, Nonce: {nonce}") |
|
|
|
|
|
if __name__ == "__main__": |
|
|
miner = ParallelMiner() |
|
|
try: |
|
|
miner.start_mining(duration=500) |
|
|
except KeyboardInterrupt: |
|
|
miner.mining = False |
|
|
logging.info("\nMining stopped by user") |