""" Integrates the mining system with Bitcoin mainnet """ from typing import Dict, Any, Optional import time import requests import hashlib import json import logging import struct # Configure detailed logging logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('network_debug.log'), logging.StreamHandler() ] ) class NetworkIntegration: def __init__(self, wallet_address: str = None, use_testnet: bool = False): self.is_mainnet = not use_testnet if use_testnet: self.api_base = "https://testnet.blockchain.info" self.node = "testnet-seed.bitcoin.jonasschnelli.ch" # Bitcoin testnet seed node else: self.api_base = "https://blockchain.info" # Changed to more reliable API self.node = "seed.bitcoin.sipa.be" # Bitcoin mainnet seed node # Use the provided wallet address or load from my_wallet.json if wallet_address: self.wallet_address = wallet_address else: try: with open('my_wallet.json', 'r') as f: wallet_data = json.load(f) self.wallet_address = wallet_data['address'] print(f"Using wallet address: {self.wallet_address}") except Exception as e: print(f"Error loading wallet: {e}") self.wallet_address = "1Ks4WtCEK96BaBF7HSuCGt3rEpVKPqcJKf" # Your default address def connect(self) -> bool: """Connect to Bitcoin mainnet""" try: # Test connection by getting latest block response = requests.get(f"{self.api_base}/blockchain/blocks/last") return response.status_code == 200 except Exception as e: print(f"Failed to connect to mainnet: {e}") return False def get_block_template(self) -> Dict[str, Any]: """Get current block template from mainnet""" try: # Cache the blockchain API response for 5 minutes current_time = time.time() if not hasattr(self, '_template_cache') or current_time - self._last_cache_time > 300: logging.debug("Cache expired, fetching new block template") # Get latest block info from a more reliable API response = requests.get("https://blockchain.info/latestblock") logging.debug(f"Latest block API response status: {response.status_code}") if response.status_code != 200: logging.error(f"Failed to get latest block. Status code: {response.status_code}") if hasattr(self, '_template_cache'): logging.info("Using cached template") return self._template_cache raise Exception("Failed to get latest block") latest = response.json() logging.debug(f"Latest block response: {latest}") height = latest['height'] current_block = latest['hash'] logging.info(f"Current block height: {height}, hash: {current_block}") # Get current network stats and difficulty logging.debug("Fetching network stats...") diff_response = requests.get("https://blockchain.info/q/getdifficulty") if diff_response.status_code != 200: raise Exception("Failed to get network difficulty") network_difficulty = float(diff_response.text) logging.info(f"Current network difficulty: {network_difficulty}") # Calculate target from real network difficulty max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 target = int(max_target / network_difficulty) # Calculate bits from real target exp = 0x1d coeff = (target >> (8 * (0x1d - 3))) & 0xffffff bits = (exp << 24) | coeff logging.debug(f"Target calculated from difficulty: {hex(target)}") current_target = target # Use actual network target # Create block template template = { 'version': 2, 'previousblockhash': current_block, 'merkleroot': '0' * 64, # Placeholder merkle root 'time': int(time.time()), 'bits': bits, 'target': current_target, 'height': height } logging.debug(f"Target calculated from bits {hex(bits)}: {hex(current_target)}") # Construct template with required fields template = { 'version': 2, # Current Bitcoin version 'previousblockhash': current_block, # Use current block as previous for next block 'merkleroot': '0' * 64, # Placeholder merkle root 'time': int(time.time()), 'bits': bits, # Original bits value 'height': int(height), # Ensure height is integer 'target': current_target # Correctly calculated target from bits } # Update cache self._template_cache = template self._last_cache_time = current_time return self._template_cache except Exception as e: logging.error(f"Error getting block template: {str(e)}") # Return fallback template # Get real mainnet difficulty from blockchain.info diff_url = "https://blockchain.info/q/getdifficulty" try: diff_response = requests.get(diff_url) if diff_response.status_code == 200: network_difficulty = float(diff_response.text) bits = hex(int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty))[2:] target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty) logging.info(f"Got mainnet difficulty: {network_difficulty}") else: # Use more reasonable fallback difficulty for mainnet network_difficulty = 137533144484879.19 # Recent mainnet difficulty target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty) bits = f"{0x1d:02x}{target & 0xffffff:06x}" except Exception as e: logging.error(f"Error getting mainnet difficulty: {e}") # Use more reasonable fallback difficulty for mainnet network_difficulty = 137533144484879.19 # Recent mainnet difficulty target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty) bits = f"{0x1d:02x}{target & 0xffffff:06x}" return { 'version': 2, 'previousblockhash': '0' * 64, 'merkleroot': '0' * 64, 'time': int(time.time()), 'bits': bits, 'height': 0, 'target': target } except Exception as e: logging.error(f"Error getting block template: {str(e)}") # Use fallback difficulty and target network_difficulty = 137533144484879.19 # Recent mainnet difficulty max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 target = int(max_target / network_difficulty) bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}" logging.info(f"Using fallback difficulty: {network_difficulty}") block_height = 917362 # Recent block height prev_block = "00000000000000000000635542f008dfb9ba9f4d25e53539c62918aa5c5b852a" # Recent block hash # Get real network difficulty even in fallback diff_url = "https://blockchain.info/q/getdifficulty" try: diff_response = requests.get(diff_url) if diff_response.status_code == 200: network_difficulty = float(diff_response.text) target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty) else: target = 0x00000000ffff0000000000000000000000000000000000000000000000000000 except: target = 0x00000000ffff0000000000000000000000000000000000000000000000000000 template = { 'version': 0x20000000, 'previous_block': prev_block, 'merkle_root': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b', 'timestamp': int(time.time()), 'bits': 0x1d00ffff, 'target': target, 'height': block_height, 'network_difficulty': network_difficulty if 'network_difficulty' in locals() else None } return template try: # Get latest block info response = requests.get(self.bitcoin_network.latest_block_url) if response.status_code != 200: raise Exception("Failed to get latest block") latest = response.json() # Construct proper block template with real network data template = { 'version': 0x20000000, # Version 2 with BIP9 bits 'previousblockhash': prev_block, # Changed to match Bitcoin Core naming 'merkleroot': '0' * 64, # Will be calculated from transactions 'time': int(time.time()), # Current time 'bits': bits_int, # Using parsed bits value 'height': height, 'target': target, 'difficulty': network_difficulty, 'coinbasetx': coinbase_tx, 'sizelimit': 4000000, # 4MB block size limit 'transactions': [] # Pending transactions (empty for now) } return template except Exception as e: print(f"Error getting block template: {str(e)}") # Create fallback template template = { 'version': 0x20000000, # Version 2 with BIP9 bits 'previousblockhash': '000000000000000000024bead8df69990852c202db0e0097c1a12ea637d7e96d', 'merkleroot': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b', 'time': int(time.time()), 'bits': 0x1d00ffff, 'target': 0x00000000ffff0000000000000000000000000000000000000000000000000000, 'height': 2_500_000, 'difficulty': 1.0, 'coinbasetx': { 'version': 1, 'vin': [{ 'txid': '0' * 64, 'vout': 0xFFFFFFFF, 'scriptSig': '03' + hex(2_500_000)[2:].zfill(6) + '0000000000000000', 'sequence': 0xFFFFFFFF }], 'vout': [{ 'value': 625000000, 'scriptPubKey': '76a914' + hashlib.new("ripemd160", hashlib.sha256(self.wallet_address.encode()).digest()).hexdigest() + '88ac' }] }, 'sizelimit': 4000000, 'transactions': [] } return template def submit_block(self, block_header: bytes, nonce: int) -> bool: """Submit found block to network""" try: # Get current template template = self.get_block_template() # Verify the block hash first full_header = block_header[:-4] + struct.pack('= template['target']: logging.error("Block hash doesn't meet target requirement") logging.error(f"Hash/Target ratio: {block_hash_int / template['target']:.2f}") return False # Create block data starting with header including nonce block_data = bytearray(full_header) # Add transaction count varint (1 for coinbase only) block_data.extend(bytes([1])) # Create proper coinbase transaction with our wallet address block_height = template['height'] block_height_hex = hex(block_height)[2:].zfill(6) # BIP34: Block height # Create proper coinbase script with required elements coinbase_script = ( bytes([3]) + # Push 3 bytes (block height) bytes.fromhex(block_height_hex) + # Block height (BIP34) bytes.fromhex("0000000000000000") + # Extra nonce space b"/Mined by Elias/" # Miner tag ) # Import required for base58 decoding from base58 import b58decode_check # Decode wallet address to get public key hash try: decoded = b58decode_check(self.wallet_address) pubkey_hash = decoded[1:] # Remove version byte except Exception as e: logging.error(f"Error decoding wallet address: {e}") return False # Create complete coinbase transaction coinbase_tx = ( struct.pack(' int: """Convert compact bits to target""" bits = int(bits, 16) shift = (bits >> 24) & 0xff target = (bits & 0x00ffffff) * (2 ** (8 * (shift - 3))) return target