Spaces:
Paused
Paused
File size: 18,999 Bytes
645b57e bd6de9f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 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 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
"""
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):
self.api_base = "https://blockchain.info" # Changed to more reliable API
self.node = "seed.bitcoin.sipa.be" # Bitcoin mainnet seed node
self.is_mainnet = True # Force mainnet mode
# 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 difficulty
max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
target = int(max_target / network_difficulty)
bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}"
logging.debug(f"Target calculated from difficulty: {hex(target)}")
# Use fixed bits for target calculation
bits = 0x1d00ffff # Standard Bitcoin difficulty 1 target
# Calculate target from bits
exp = ((bits >> 24) & 0xff)
coeff = bits & 0x00ffffff
current_target = coeff * (2 ** (8 * (exp - 3)))
# 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
}
print(f"Mining at difficulty: {network_difficulty}")
print(f"Network target: {hex(target)}")
# Create proper coinbase input script
block_height_hex = hex(height)[2:].zfill(6) # BIP34: Block height
coinbase_script = (
"03" + # Push 3 bytes
block_height_hex + # BIP34: Block height
"0000000000000000" + # Extra nonce space
"2f4d696e656420627920426974436f696e2d436f70696c6f742f" # /Mined by BitCoin-Copilot/
)
# Create coinbase transaction
coinbase_tx = {
'version': 1,
'vin': [{
'txid': '0' * 64, # Null hash for coinbase
'vout': 0xFFFFFFFF, # -1 (4 bytes) for coinbase
'scriptSig': coinbase_script, # Block height + extra nonce + miner tag
'sequence': 0xFFFFFFFF
}],
'vout': [{
'value': 625000000, # 6.25 BTC reward
'scriptPubKey': '76a914' + hashlib.new("ripemd160", hashlib.sha256(self.wallet_address.encode()).digest()).hexdigest() + '88ac' # P2PKH to miner address
}]
}
# 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': current_block['mrkl_root'], # Changed to match Bitcoin Core naming
'time': int(time.time()), # Changed to match Bitcoin Core naming
'bits': bits_int, # Using parsed bits value
'height': height,
'target': target,
'difficulty': network_difficulty, # Changed to match Bitcoin Core naming
'coinbasetx': coinbase_tx, # Changed to match Bitcoin Core naming
'sizelimit': 4000000, # Changed to match Bitcoin Core naming
'transactions': [] # Pending transactions (empty for now)
}
return template
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()
# Create block data starting with header including nonce
block_data = bytearray(block_header[:-4] + struct.pack('<I', nonce))
# Add transaction count varint (1 for coinbase only)
block_data.extend(bytes([1]))
# Create proper coinbase transaction
block_height = template['height']
block_height_hex = hex(block_height)[2:].zfill(6) # BIP34: Block height
# Create proper coinbase script
coinbase_script = bytes.fromhex(
"03" + # Push 3 bytes
block_height_hex + # Block height (BIP34)
"0000000000000000" + # Extra nonce
"2f4d696e656420627920426974436f696e2d436f70696c6f742f" # /Mined by BitCoin-Copilot/
)
# Start serializing the coinbase transaction
tx_data = struct.pack('<I', 1) # Version 1
# Input count (always 1 for coinbase)
tx_data += bytes([1])
# Coinbase input with proper null txid (must be exactly 32 bytes)
tx_data += b'\x00' * 32 # Previous txid (null for coinbase)
tx_data += struct.pack('<I', 0xFFFFFFFF) # Previous output index (-1 for coinbase)
# Create proper coinbase input script with proper length prefix
script_len = len(coinbase_script)
if script_len < 0xfd:
tx_data += bytes([script_len])
elif script_len <= 0xffff:
tx_data += bytes([0xfd]) + struct.pack('<H', script_len)
elif script_len <= 0xffffffff:
tx_data += bytes([0xfe]) + struct.pack('<I', script_len)
else:
tx_data += bytes([0xff]) + struct.pack('<Q', script_len)
tx_data += coinbase_script # Coinbase script
tx_data += struct.pack('<I', 0xFFFFFFFF) # Sequence
# Output count (1 output paying the miner)
tx_data += bytes([1])
# Miner's reward output (6.25 BTC)
tx_data += struct.pack('<Q', 625000000) # Value in satoshis
# Create proper P2PKH script for payout
# First decode the base58 address to get the pubkey hash
from base58 import b58decode_check
decoded = b58decode_check(self.wallet_address)
pubkey_hash = decoded[1:] # Skip version byte
# Build P2PKH script
script_pubkey = bytes([0x76, 0xa9, 0x14]) + pubkey_hash + bytes([0x88, 0xac])
tx_data += bytes([len(script_pubkey)]) # Script length
tx_data += script_pubkey # P2PKH script
# Add locktime
tx_data += struct.pack('<I', 0) # nLockTime
# Add serialized coinbase transaction to block
block_data.extend(tx_data)
# Submit block using blockchain.info API
submit_url = 'https://api.blockchain.info/haskoin-store/btc/block'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(submit_url, data={'block': block_data.hex()}, headers=headers)
if response.status_code == 200:
print(f"Block successfully submitted!")
logging.info("Block submission successful")
return True
elif response.status_code == 400 and 'bad-txns-vin-empty' in response.text:
print("Block rejected: Invalid coinbase transaction structure")
logging.error("Block rejected due to invalid coinbase transaction")
return False
else:
error_msg = response.text if response.text else f"Status code: {response.status_code}"
print(f"Block submission failed: {error_msg}")
logging.error(f"Block submission failed: {error_msg}")
return False
except Exception as e:
print(f"Error submitting block: {str(e)}")
return False
try:
block_hash = hashlib.sha256(hashlib.sha256(block_header).digest()).digest()
return self.bitcoin_network.submit_block(block_header, nonce)
except Exception as e:
print(f"Block submission error: {e}")
return False
def _bits_to_target(self, bits: str) -> int:
"""Convert compact bits to target"""
bits = int(bits, 16)
shift = (bits >> 24) & 0xff
target = (bits & 0x00ffffff) * (2 ** (8 * (shift - 3)))
return target |