favoredone commited on
Commit
3ee386e
·
verified ·
1 Parent(s): 988373f

Update network_integration.py

Browse files
Files changed (1) hide show
  1. network_integration.py +450 -398
network_integration.py CHANGED
@@ -1,399 +1,451 @@
1
- """
2
- Integrates the mining system with Bitcoin mainnet
3
- """
4
- from typing import Dict, Any, Optional
5
- import time
6
- import requests
7
- import hashlib
8
- import json
9
- import logging
10
- import struct
11
-
12
- # Configure detailed logging
13
- logging.basicConfig(
14
- level=logging.DEBUG,
15
- format='%(asctime)s - %(levelname)s - %(message)s',
16
- handlers=[
17
- logging.FileHandler('network_debug.log'),
18
- logging.StreamHandler()
19
- ]
20
- )
21
-
22
- class NetworkIntegration:
23
- def __init__(self, wallet_address: str = None):
24
- self.api_base = "https://blockchain.info" # Changed to more reliable API
25
- self.node = "seed.bitcoin.sipa.be" # Bitcoin mainnet seed node
26
- self.is_mainnet = True # Force mainnet mode
27
- # Use the provided wallet address or load from my_wallet.json
28
- if wallet_address:
29
- self.wallet_address = wallet_address
30
- else:
31
- try:
32
- with open('my_wallet.json', 'r') as f:
33
- wallet_data = json.load(f)
34
- self.wallet_address = wallet_data['address']
35
- print(f"Using wallet address: {self.wallet_address}")
36
- except Exception as e:
37
- print(f"Error loading wallet: {e}")
38
- self.wallet_address = "1Ks4WtCEK96BaBF7HSuCGt3rEpVKPqcJKf" # Your default address
39
-
40
- def connect(self) -> bool:
41
- """Connect to Bitcoin mainnet"""
42
- try:
43
- # Test connection by getting latest block
44
- response = requests.get(f"{self.api_base}/blockchain/blocks/last")
45
- return response.status_code == 200
46
- except Exception as e:
47
- print(f"Failed to connect to mainnet: {e}")
48
- return False
49
-
50
- def get_block_template(self) -> Dict[str, Any]:
51
- """Get current block template from mainnet"""
52
- try:
53
- # Cache the blockchain API response for 5 minutes
54
- current_time = time.time()
55
- if not hasattr(self, '_template_cache') or current_time - self._last_cache_time > 300:
56
- logging.debug("Cache expired, fetching new block template")
57
- # Get latest block info from a more reliable API
58
- response = requests.get("https://blockchain.info/latestblock")
59
- logging.debug(f"Latest block API response status: {response.status_code}")
60
-
61
- if response.status_code != 200:
62
- logging.error(f"Failed to get latest block. Status code: {response.status_code}")
63
- if hasattr(self, '_template_cache'):
64
- logging.info("Using cached template")
65
- return self._template_cache
66
- raise Exception("Failed to get latest block")
67
-
68
- latest = response.json()
69
- logging.debug(f"Latest block response: {latest}")
70
-
71
- height = latest['height']
72
- current_block = latest['hash']
73
- logging.info(f"Current block height: {height}, hash: {current_block}")
74
-
75
- # Get current network stats and difficulty
76
- logging.debug("Fetching network stats...")
77
- diff_response = requests.get("https://blockchain.info/q/getdifficulty")
78
- if diff_response.status_code != 200:
79
- raise Exception("Failed to get network difficulty")
80
-
81
- network_difficulty = float(diff_response.text)
82
- logging.info(f"Current network difficulty: {network_difficulty}")
83
-
84
- # Calculate target from difficulty
85
- max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
86
- target = int(max_target / network_difficulty)
87
- bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}"
88
-
89
- logging.debug(f"Target calculated from difficulty: {hex(target)}")
90
-
91
- # Use fixed bits for target calculation
92
- bits = 0x1d00ffff # Standard Bitcoin difficulty 1 target
93
-
94
- # Calculate target from bits
95
- exp = ((bits >> 24) & 0xff)
96
- coeff = bits & 0x00ffffff
97
- current_target = coeff * (2 ** (8 * (exp - 3)))
98
-
99
- # Create block template
100
- template = {
101
- 'version': 2,
102
- 'previousblockhash': current_block,
103
- 'merkleroot': '0' * 64, # Placeholder merkle root
104
- 'time': int(time.time()),
105
- 'bits': bits,
106
- 'target': current_target,
107
- 'height': height
108
- }
109
-
110
- logging.debug(f"Target calculated from bits {hex(bits)}: {hex(current_target)}")
111
-
112
- # Construct template with required fields
113
- template = {
114
- 'version': 2, # Current Bitcoin version
115
- 'previousblockhash': current_block, # Use current block as previous for next block
116
- 'merkleroot': '0' * 64, # Placeholder merkle root
117
- 'time': int(time.time()),
118
- 'bits': bits, # Original bits value
119
- 'height': int(height), # Ensure height is integer
120
- 'target': current_target # Correctly calculated target from bits
121
- }
122
-
123
- # Update cache
124
- self._template_cache = template
125
- self._last_cache_time = current_time
126
-
127
- return self._template_cache
128
-
129
- except Exception as e:
130
- logging.error(f"Error getting block template: {str(e)}")
131
- # Return fallback template
132
- # Get real mainnet difficulty from blockchain.info
133
- diff_url = "https://blockchain.info/q/getdifficulty"
134
- try:
135
- diff_response = requests.get(diff_url)
136
- if diff_response.status_code == 200:
137
- network_difficulty = float(diff_response.text)
138
- bits = hex(int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty))[2:]
139
- target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
140
- logging.info(f"Got mainnet difficulty: {network_difficulty}")
141
- else:
142
- # Use more reasonable fallback difficulty for mainnet
143
- network_difficulty = 137533144484879.19 # Recent mainnet difficulty
144
- target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
145
- bits = f"{0x1d:02x}{target & 0xffffff:06x}"
146
- except Exception as e:
147
- logging.error(f"Error getting mainnet difficulty: {e}")
148
- # Use more reasonable fallback difficulty for mainnet
149
- network_difficulty = 137533144484879.19 # Recent mainnet difficulty
150
- target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
151
- bits = f"{0x1d:02x}{target & 0xffffff:06x}"
152
-
153
- return {
154
- 'version': 2,
155
- 'previousblockhash': '0' * 64,
156
- 'merkleroot': '0' * 64,
157
- 'time': int(time.time()),
158
- 'bits': bits,
159
- 'height': 0,
160
- 'target': target
161
- }
162
-
163
- print(f"Mining at difficulty: {network_difficulty}")
164
- print(f"Network target: {hex(target)}")
165
-
166
- # Create proper coinbase input script
167
- block_height_hex = hex(height)[2:].zfill(6) # BIP34: Block height
168
- coinbase_script = (
169
- "03" + # Push 3 bytes
170
- block_height_hex + # BIP34: Block height
171
- "0000000000000000" + # Extra nonce space
172
- "2f4d696e656420627920426974436f696e2d436f70696c6f742f" # /Mined by BitCoin-Copilot/
173
- )
174
-
175
- # Create coinbase transaction
176
- coinbase_tx = {
177
- 'version': 1,
178
- 'vin': [{
179
- 'txid': '0' * 64, # Null hash for coinbase
180
- 'vout': 0xFFFFFFFF, # -1 (4 bytes) for coinbase
181
- 'scriptSig': coinbase_script, # Block height + extra nonce + miner tag
182
- 'sequence': 0xFFFFFFFF
183
- }],
184
- 'vout': [{
185
- 'value': 625000000, # 6.25 BTC reward
186
- 'scriptPubKey': '76a914' + hashlib.new("ripemd160", hashlib.sha256(self.wallet_address.encode()).digest()).hexdigest() + '88ac' # P2PKH to miner address
187
- }]
188
- }
189
-
190
- # Construct proper block template with real network data
191
- template = {
192
- 'version': 0x20000000, # Version 2 with BIP9 bits
193
- 'previousblockhash': prev_block, # Changed to match Bitcoin Core naming
194
- 'merkleroot': current_block['mrkl_root'], # Changed to match Bitcoin Core naming
195
- 'time': int(time.time()), # Changed to match Bitcoin Core naming
196
- 'bits': bits_int, # Using parsed bits value
197
- 'height': height,
198
- 'target': target,
199
- 'difficulty': network_difficulty, # Changed to match Bitcoin Core naming
200
- 'coinbasetx': coinbase_tx, # Changed to match Bitcoin Core naming
201
- 'sizelimit': 4000000, # Changed to match Bitcoin Core naming
202
- 'transactions': [] # Pending transactions (empty for now)
203
- }
204
-
205
- return template
206
-
207
- except Exception as e:
208
- logging.error(f"Error getting block template: {str(e)}")
209
- # Use fallback difficulty and target
210
- network_difficulty = 137533144484879.19 # Recent mainnet difficulty
211
- max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
212
- target = int(max_target / network_difficulty)
213
- bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}"
214
-
215
- logging.info(f"Using fallback difficulty: {network_difficulty}")
216
- block_height = 917362 # Recent block height
217
- prev_block = "00000000000000000000635542f008dfb9ba9f4d25e53539c62918aa5c5b852a" # Recent block hash
218
-
219
- # Get real network difficulty even in fallback
220
- diff_url = "https://blockchain.info/q/getdifficulty"
221
- try:
222
- diff_response = requests.get(diff_url)
223
- if diff_response.status_code == 200:
224
- network_difficulty = float(diff_response.text)
225
- target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
226
- else:
227
- target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
228
- except:
229
- target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
230
-
231
- template = {
232
- 'version': 0x20000000,
233
- 'previous_block': prev_block,
234
- 'merkle_root': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
235
- 'timestamp': int(time.time()),
236
- 'bits': 0x1d00ffff,
237
- 'target': target,
238
- 'height': block_height,
239
- 'network_difficulty': network_difficulty if 'network_difficulty' in locals() else None
240
- }
241
- return template
242
- try:
243
- # Get latest block info
244
- response = requests.get(self.bitcoin_network.latest_block_url)
245
- if response.status_code != 200:
246
- raise Exception("Failed to get latest block")
247
-
248
- latest = response.json()
249
- # Construct proper block template with real network data
250
- template = {
251
- 'version': 0x20000000, # Version 2 with BIP9 bits
252
- 'previousblockhash': prev_block, # Changed to match Bitcoin Core naming
253
- 'merkleroot': '0' * 64, # Will be calculated from transactions
254
- 'time': int(time.time()), # Current time
255
- 'bits': bits_int, # Using parsed bits value
256
- 'height': height,
257
- 'target': target,
258
- 'difficulty': network_difficulty,
259
- 'coinbasetx': coinbase_tx,
260
- 'sizelimit': 4000000, # 4MB block size limit
261
- 'transactions': [] # Pending transactions (empty for now)
262
- }
263
- return template
264
- except Exception as e:
265
- print(f"Error getting block template: {str(e)}")
266
- # Create fallback template
267
- template = {
268
- 'version': 0x20000000, # Version 2 with BIP9 bits
269
- 'previousblockhash': '000000000000000000024bead8df69990852c202db0e0097c1a12ea637d7e96d',
270
- 'merkleroot': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
271
- 'time': int(time.time()),
272
- 'bits': 0x1d00ffff,
273
- 'target': 0x00000000ffff0000000000000000000000000000000000000000000000000000,
274
- 'height': 2_500_000,
275
- 'difficulty': 1.0,
276
- 'coinbasetx': {
277
- 'version': 1,
278
- 'vin': [{
279
- 'txid': '0' * 64,
280
- 'vout': 0xFFFFFFFF,
281
- 'scriptSig': '03' + hex(2_500_000)[2:].zfill(6) + '0000000000000000',
282
- 'sequence': 0xFFFFFFFF
283
- }],
284
- 'vout': [{
285
- 'value': 625000000,
286
- 'scriptPubKey': '76a914' + hashlib.new("ripemd160", hashlib.sha256(self.wallet_address.encode()).digest()).hexdigest() + '88ac'
287
- }]
288
- },
289
- 'sizelimit': 4000000,
290
- 'transactions': []
291
- }
292
- return template
293
-
294
- def submit_block(self, block_header: bytes, nonce: int) -> bool:
295
- """Submit found block to network"""
296
- try:
297
- # Get current template
298
- template = self.get_block_template()
299
-
300
- # Create block data starting with header including nonce
301
- block_data = bytearray(block_header[:-4] + struct.pack('<I', nonce))
302
-
303
- # Add transaction count varint (1 for coinbase only)
304
- block_data.extend(bytes([1]))
305
-
306
- # Create proper coinbase transaction
307
- block_height = template['height']
308
- block_height_hex = hex(block_height)[2:].zfill(6) # BIP34: Block height
309
-
310
- # Create proper coinbase script
311
- coinbase_script = bytes.fromhex(
312
- "03" + # Push 3 bytes
313
- block_height_hex + # Block height (BIP34)
314
- "0000000000000000" + # Extra nonce
315
- "2f4d696e656420627920426974436f696e2d436f70696c6f742f" # /Mined by BitCoin-Copilot/
316
- )
317
-
318
- # Start serializing the coinbase transaction
319
- tx_data = struct.pack('<I', 1) # Version 1
320
-
321
- # Input count (always 1 for coinbase)
322
- tx_data += bytes([1])
323
-
324
- # Coinbase input with proper null txid (must be exactly 32 bytes)
325
- tx_data += b'\x00' * 32 # Previous txid (null for coinbase)
326
- tx_data += struct.pack('<I', 0xFFFFFFFF) # Previous output index (-1 for coinbase)
327
-
328
- # Create proper coinbase input script with proper length prefix
329
- script_len = len(coinbase_script)
330
- if script_len < 0xfd:
331
- tx_data += bytes([script_len])
332
- elif script_len <= 0xffff:
333
- tx_data += bytes([0xfd]) + struct.pack('<H', script_len)
334
- elif script_len <= 0xffffffff:
335
- tx_data += bytes([0xfe]) + struct.pack('<I', script_len)
336
- else:
337
- tx_data += bytes([0xff]) + struct.pack('<Q', script_len)
338
-
339
- tx_data += coinbase_script # Coinbase script
340
- tx_data += struct.pack('<I', 0xFFFFFFFF) # Sequence
341
-
342
- # Output count (1 output paying the miner)
343
- tx_data += bytes([1])
344
-
345
- # Miner's reward output (6.25 BTC)
346
- tx_data += struct.pack('<Q', 625000000) # Value in satoshis
347
-
348
- # Create proper P2PKH script for payout
349
- # First decode the base58 address to get the pubkey hash
350
- from base58 import b58decode_check
351
- decoded = b58decode_check(self.wallet_address)
352
- pubkey_hash = decoded[1:] # Skip version byte
353
-
354
- # Build P2PKH script
355
- script_pubkey = bytes([0x76, 0xa9, 0x14]) + pubkey_hash + bytes([0x88, 0xac])
356
- tx_data += bytes([len(script_pubkey)]) # Script length
357
- tx_data += script_pubkey # P2PKH script
358
-
359
- # Add locktime
360
- tx_data += struct.pack('<I', 0) # nLockTime
361
-
362
- # Add serialized coinbase transaction to block
363
- block_data.extend(tx_data)
364
-
365
- # Submit block using blockchain.info API
366
- submit_url = 'https://api.blockchain.info/haskoin-store/btc/block'
367
- headers = {'Content-Type': 'application/x-www-form-urlencoded'}
368
- response = requests.post(submit_url, data={'block': block_data.hex()}, headers=headers)
369
-
370
- if response.status_code == 200:
371
- print(f"Block successfully submitted!")
372
- logging.info("Block submission successful")
373
- return True
374
- elif response.status_code == 400 and 'bad-txns-vin-empty' in response.text:
375
- print("Block rejected: Invalid coinbase transaction structure")
376
- logging.error("Block rejected due to invalid coinbase transaction")
377
- return False
378
- else:
379
- error_msg = response.text if response.text else f"Status code: {response.status_code}"
380
- print(f"Block submission failed: {error_msg}")
381
- logging.error(f"Block submission failed: {error_msg}")
382
- return False
383
-
384
- except Exception as e:
385
- print(f"Error submitting block: {str(e)}")
386
- return False
387
- try:
388
- block_hash = hashlib.sha256(hashlib.sha256(block_header).digest()).digest()
389
- return self.bitcoin_network.submit_block(block_header, nonce)
390
- except Exception as e:
391
- print(f"Block submission error: {e}")
392
- return False
393
-
394
- def _bits_to_target(self, bits: str) -> int:
395
- """Convert compact bits to target"""
396
- bits = int(bits, 16)
397
- shift = (bits >> 24) & 0xff
398
- target = (bits & 0x00ffffff) * (2 ** (8 * (shift - 3)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  return target
 
1
+ """
2
+ Integrates the mining system with Bitcoin mainnet
3
+ """
4
+ from typing import Dict, Any, Optional
5
+ import time
6
+ import requests
7
+ import hashlib
8
+ import json
9
+ import logging
10
+ import struct
11
+
12
+ # Configure detailed logging
13
+ logging.basicConfig(
14
+ level=logging.DEBUG,
15
+ format='%(asctime)s - %(levelname)s - %(message)s',
16
+ handlers=[
17
+ logging.FileHandler('network_debug.log'),
18
+ logging.StreamHandler()
19
+ ]
20
+ )
21
+
22
+ class NetworkIntegration:
23
+ def __init__(self, wallet_address: str = None):
24
+ self.api_base = "https://blockchain.info" # Changed to more reliable API
25
+ self.node = "seed.bitcoin.sipa.be" # Bitcoin mainnet seed node
26
+ self.is_mainnet = True # Force mainnet mode
27
+ # Use the provided wallet address or load from my_wallet.json
28
+ if wallet_address:
29
+ self.wallet_address = wallet_address
30
+ else:
31
+ try:
32
+ with open('my_wallet.json', 'r') as f:
33
+ wallet_data = json.load(f)
34
+ self.wallet_address = wallet_data['address']
35
+ print(f"Using wallet address: {self.wallet_address}")
36
+ except Exception as e:
37
+ print(f"Error loading wallet: {e}")
38
+ self.wallet_address = "1Ks4WtCEK96BaBF7HSuCGt3rEpVKPqcJKf" # Your default address
39
+
40
+ def connect(self) -> bool:
41
+ """Connect to Bitcoin mainnet"""
42
+ try:
43
+ # Test connection by getting latest block
44
+ response = requests.get(f"{self.api_base}/blockchain/blocks/last")
45
+ return response.status_code == 200
46
+ except Exception as e:
47
+ print(f"Failed to connect to mainnet: {e}")
48
+ return False
49
+
50
+ def get_block_template(self) -> Dict[str, Any]:
51
+ """Get current block template from mainnet"""
52
+ try:
53
+ # Cache the blockchain API response for 5 minutes
54
+ current_time = time.time()
55
+ if not hasattr(self, '_template_cache') or current_time - self._last_cache_time > 300:
56
+ logging.debug("Cache expired, fetching new block template")
57
+ # Get latest block info from a more reliable API
58
+ response = requests.get("https://blockchain.info/latestblock")
59
+ logging.debug(f"Latest block API response status: {response.status_code}")
60
+
61
+ if response.status_code != 200:
62
+ logging.error(f"Failed to get latest block. Status code: {response.status_code}")
63
+ if hasattr(self, '_template_cache'):
64
+ logging.info("Using cached template")
65
+ return self._template_cache
66
+ raise Exception("Failed to get latest block")
67
+
68
+ latest = response.json()
69
+ logging.debug(f"Latest block response: {latest}")
70
+
71
+ height = latest['height']
72
+ current_block = latest['hash']
73
+ logging.info(f"Current block height: {height}, hash: {current_block}")
74
+
75
+ # Get current network stats and difficulty
76
+ logging.debug("Fetching network stats...")
77
+ diff_response = requests.get("https://blockchain.info/q/getdifficulty")
78
+ if diff_response.status_code != 200:
79
+ raise Exception("Failed to get network difficulty")
80
+
81
+ network_difficulty = float(diff_response.text)
82
+ logging.info(f"Current network difficulty: {network_difficulty}")
83
+
84
+ # Calculate target from difficulty
85
+ max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
86
+ target = int(max_target / network_difficulty)
87
+ bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}"
88
+
89
+ logging.debug(f"Target calculated from difficulty: {hex(target)}")
90
+
91
+ # Use fixed bits for target calculation
92
+ bits = 0x1d00ffff # Standard Bitcoin difficulty 1 target
93
+
94
+ # Calculate target from bits
95
+ exp = ((bits >> 24) & 0xff)
96
+ coeff = bits & 0x00ffffff
97
+ current_target = coeff * (2 ** (8 * (exp - 3)))
98
+
99
+ # Create block template
100
+ template = {
101
+ 'version': 2,
102
+ 'previousblockhash': current_block,
103
+ 'merkleroot': '0' * 64, # Placeholder merkle root
104
+ 'time': int(time.time()),
105
+ 'bits': bits,
106
+ 'target': current_target,
107
+ 'height': height
108
+ }
109
+
110
+ logging.debug(f"Target calculated from bits {hex(bits)}: {hex(current_target)}")
111
+
112
+ # Construct template with required fields
113
+ template = {
114
+ 'version': 2, # Current Bitcoin version
115
+ 'previousblockhash': current_block, # Use current block as previous for next block
116
+ 'merkleroot': '0' * 64, # Placeholder merkle root
117
+ 'time': int(time.time()),
118
+ 'bits': bits, # Original bits value
119
+ 'height': int(height), # Ensure height is integer
120
+ 'target': current_target # Correctly calculated target from bits
121
+ }
122
+
123
+ # Update cache
124
+ self._template_cache = template
125
+ self._last_cache_time = current_time
126
+
127
+ return self._template_cache
128
+
129
+ except Exception as e:
130
+ logging.error(f"Error getting block template: {str(e)}")
131
+ # Return fallback template
132
+ # Get real mainnet difficulty from blockchain.info
133
+ diff_url = "https://blockchain.info/q/getdifficulty"
134
+ try:
135
+ diff_response = requests.get(diff_url)
136
+ if diff_response.status_code == 200:
137
+ network_difficulty = float(diff_response.text)
138
+ bits = hex(int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty))[2:]
139
+ target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
140
+ logging.info(f"Got mainnet difficulty: {network_difficulty}")
141
+ else:
142
+ # Use more reasonable fallback difficulty for mainnet
143
+ network_difficulty = 137533144484879.19 # Recent mainnet difficulty
144
+ target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
145
+ bits = f"{0x1d:02x}{target & 0xffffff:06x}"
146
+ except Exception as e:
147
+ logging.error(f"Error getting mainnet difficulty: {e}")
148
+ # Use more reasonable fallback difficulty for mainnet
149
+ network_difficulty = 137533144484879.19 # Recent mainnet difficulty
150
+ target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
151
+ bits = f"{0x1d:02x}{target & 0xffffff:06x}"
152
+
153
+ return {
154
+ 'version': 2,
155
+ 'previousblockhash': '0' * 64,
156
+ 'merkleroot': '0' * 64,
157
+ 'time': int(time.time()),
158
+ 'bits': bits,
159
+ 'height': 0,
160
+ 'target': target
161
+ }
162
+
163
+
164
+ except Exception as e:
165
+ logging.error(f"Error getting block template: {str(e)}")
166
+ # Use fallback difficulty and target
167
+ network_difficulty = 137533144484879.19 # Recent mainnet difficulty
168
+ max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
169
+ target = int(max_target / network_difficulty)
170
+ bits = f"{0x1d:02x}{(target >> 208) & 0xffffff:06x}"
171
+
172
+ logging.info(f"Using fallback difficulty: {network_difficulty}")
173
+ block_height = 917362 # Recent block height
174
+ prev_block = "00000000000000000000635542f008dfb9ba9f4d25e53539c62918aa5c5b852a" # Recent block hash
175
+
176
+ # Get real network difficulty even in fallback
177
+ diff_url = "https://blockchain.info/q/getdifficulty"
178
+ try:
179
+ diff_response = requests.get(diff_url)
180
+ if diff_response.status_code == 200:
181
+ network_difficulty = float(diff_response.text)
182
+ target = int((0xffff * 2**(8*(0x1d - 3))) / network_difficulty)
183
+ else:
184
+ target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
185
+ except:
186
+ target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
187
+
188
+ template = {
189
+ 'version': 0x20000000,
190
+ 'previous_block': prev_block,
191
+ 'merkle_root': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
192
+ 'timestamp': int(time.time()),
193
+ 'bits': 0x1d00ffff,
194
+ 'target': target,
195
+ 'height': block_height,
196
+ 'network_difficulty': network_difficulty if 'network_difficulty' in locals() else None
197
+ }
198
+ return template
199
+ try:
200
+ # Get latest block info
201
+ response = requests.get(self.bitcoin_network.latest_block_url)
202
+ if response.status_code != 200:
203
+ raise Exception("Failed to get latest block")
204
+
205
+ latest = response.json()
206
+ # Construct proper block template with real network data
207
+ template = {
208
+ 'version': 0x20000000, # Version 2 with BIP9 bits
209
+ 'previousblockhash': prev_block, # Changed to match Bitcoin Core naming
210
+ 'merkleroot': '0' * 64, # Will be calculated from transactions
211
+ 'time': int(time.time()), # Current time
212
+ 'bits': bits_int, # Using parsed bits value
213
+ 'height': height,
214
+ 'target': target,
215
+ 'difficulty': network_difficulty,
216
+ 'coinbasetx': coinbase_tx,
217
+ 'sizelimit': 4000000, # 4MB block size limit
218
+ 'transactions': [] # Pending transactions (empty for now)
219
+ }
220
+ return template
221
+ except Exception as e:
222
+ print(f"Error getting block template: {str(e)}")
223
+ # Create fallback template
224
+ template = {
225
+ 'version': 0x20000000, # Version 2 with BIP9 bits
226
+ 'previousblockhash': '000000000000000000024bead8df69990852c202db0e0097c1a12ea637d7e96d',
227
+ 'merkleroot': '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b',
228
+ 'time': int(time.time()),
229
+ 'bits': 0x1d00ffff,
230
+ 'target': 0x00000000ffff0000000000000000000000000000000000000000000000000000,
231
+ 'height': 2_500_000,
232
+ 'difficulty': 1.0,
233
+ 'coinbasetx': {
234
+ 'version': 1,
235
+ 'vin': [{
236
+ 'txid': '0' * 64,
237
+ 'vout': 0xFFFFFFFF,
238
+ 'scriptSig': '03' + hex(2_500_000)[2:].zfill(6) + '0000000000000000',
239
+ 'sequence': 0xFFFFFFFF
240
+ }],
241
+ 'vout': [{
242
+ 'value': 625000000,
243
+ 'scriptPubKey': '76a914' + hashlib.new("ripemd160", hashlib.sha256(self.wallet_address.encode()).digest()).hexdigest() + '88ac'
244
+ }]
245
+ },
246
+ 'sizelimit': 4000000,
247
+ 'transactions': []
248
+ }
249
+ return template
250
+
251
+ def submit_block(self, block_header: bytes, nonce: int) -> bool:
252
+ """Submit found block to network"""
253
+ try:
254
+ # Get current template
255
+ template = self.get_block_template()
256
+
257
+ # Verify the block hash first
258
+ full_header = block_header[:-4] + struct.pack('<I', nonce)
259
+ block_hash = hashlib.sha256(hashlib.sha256(full_header).digest()).digest()
260
+ block_hash_hex = block_hash.hex()
261
+ block_hash_int = int.from_bytes(block_hash, 'little')
262
+
263
+ # Log detailed hash information
264
+ logging.info(f"Block hash: {block_hash_hex}")
265
+ logging.info(f"Leading zeros: {len(block_hash_hex) - len(block_hash_hex.lstrip('0'))}")
266
+ logging.info(f"Hash value: {int(block_hash_hex, 16)}")
267
+ logging.info(f"Target value: {template['target']}")
268
+
269
+ if block_hash_int >= template['target']:
270
+ logging.error("Block hash doesn't meet target requirement")
271
+ logging.error(f"Hash/Target ratio: {block_hash_int / template['target']:.2f}")
272
+ return False
273
+
274
+ # Create block data starting with header including nonce
275
+ block_data = bytearray(full_header)
276
+
277
+ # Add transaction count varint (1 for coinbase only)
278
+ block_data.extend(bytes([1]))
279
+
280
+ # Create proper coinbase transaction with our wallet address
281
+ block_height = template['height']
282
+ block_height_hex = hex(block_height)[2:].zfill(6) # BIP34: Block height
283
+
284
+ # Create proper coinbase script with required elements
285
+ coinbase_script = (
286
+ bytes([3]) + # Push 3 bytes (block height)
287
+ bytes.fromhex(block_height_hex) + # Block height (BIP34)
288
+ bytes.fromhex("0000000000000000") + # Extra nonce space
289
+ b"/Mined by Elias/" # Miner tag
290
+ )
291
+
292
+ # Import required for base58 decoding
293
+ from base58 import b58decode_check
294
+
295
+ # Decode wallet address to get public key hash
296
+ try:
297
+ decoded = b58decode_check(self.wallet_address)
298
+ pubkey_hash = decoded[1:] # Remove version byte
299
+ except Exception as e:
300
+ logging.error(f"Error decoding wallet address: {e}")
301
+ return False
302
+
303
+ # Create complete coinbase transaction
304
+ coinbase_tx = (
305
+ struct.pack('<I', 1) + # Version
306
+ bytes([1]) + # Input count
307
+ bytes.fromhex('0' * 64) + # Previous tx hash (null for coinbase)
308
+ struct.pack('<I', 0xFFFFFFFF) + # Previous output index
309
+ bytes([len(coinbase_script)]) + # Script length
310
+ coinbase_script + # Coinbase script
311
+ struct.pack('<I', 0xFFFFFFFF) + # Sequence
312
+ bytes([1]) + # Output count
313
+ struct.pack('<Q', 625000000) + # 6.25 BTC reward in satoshis
314
+ bytes([25]) + # Output script length (25 bytes for P2PKH)
315
+ bytes([
316
+ 0x76, # OP_DUP
317
+ 0xa9, # OP_HASH160
318
+ 0x14 # Push 20 bytes
319
+ ]) +
320
+ pubkey_hash + # Public key hash from decoded address
321
+ bytes([
322
+ 0x88, # OP_EQUALVERIFY
323
+ 0xac # OP_CHECKSIG
324
+ ]) +
325
+ struct.pack('<I', 0) # Locktime
326
+ )
327
+
328
+ # Add coinbase transaction to block
329
+ block_data.extend(coinbase_tx)
330
+
331
+ # Add empty witness commitment
332
+ block_data.extend(bytes([0])) # No witness data
333
+
334
+ # Submit to more reliable nodes
335
+ successful = False
336
+ nodes = [
337
+ "https://btc.getblock.io/mainnet/", # Primary
338
+ "https://blockchain.info/pushtx", # Backup 1
339
+ "https://api.bitcore.io/api/BTC/mainnet/tx/send", # Backup 2
340
+ self.api_base + "/submitblock" # Original endpoint as fallback
341
+ ]
342
+
343
+ for node in nodes:
344
+ try:
345
+ logging.info(f"Attempting submission to {node}")
346
+ response = requests.post(
347
+ node,
348
+ data={'block': block_data.hex()},
349
+ headers={'Content-Type': 'application/x-www-form-urlencoded'},
350
+ timeout=10
351
+ )
352
+
353
+ if response.status_code == 200:
354
+ logging.info(f"Successfully submitted block {block_hash.hex()}")
355
+ logging.info(f"Block reward sent to {self.wallet_address}")
356
+ successful = True
357
+ break
358
+ else:
359
+ logging.warning(f"Submission failed for {node}: {response.text}")
360
+ except Exception as e:
361
+ logging.warning(f"Error submitting to {node}: {e}")
362
+ continue
363
+
364
+ return successful
365
+
366
+ except Exception as e:
367
+ logging.error(f"Error submitting block: {str(e)}")
368
+ return False
369
+
370
+ # Start serializing the coinbase transaction
371
+ tx_data = struct.pack('<I', 1) # Version 1
372
+
373
+ # Input count (always 1 for coinbase)
374
+ tx_data += bytes([1])
375
+
376
+ # Coinbase input with proper null txid (must be exactly 32 bytes)
377
+ tx_data += b'\x00' * 32 # Previous txid (null for coinbase)
378
+ tx_data += struct.pack('<I', 0xFFFFFFFF) # Previous output index (-1 for coinbase)
379
+
380
+ # Create proper coinbase input script with proper length prefix
381
+ script_len = len(coinbase_script)
382
+ if script_len < 0xfd:
383
+ tx_data += bytes([script_len])
384
+ elif script_len <= 0xffff:
385
+ tx_data += bytes([0xfd]) + struct.pack('<H', script_len)
386
+ elif script_len <= 0xffffffff:
387
+ tx_data += bytes([0xfe]) + struct.pack('<I', script_len)
388
+ else:
389
+ tx_data += bytes([0xff]) + struct.pack('<Q', script_len)
390
+
391
+ tx_data += coinbase_script # Coinbase script
392
+ tx_data += struct.pack('<I', 0xFFFFFFFF) # Sequence
393
+
394
+ # Output count (1 output paying the miner)
395
+ tx_data += bytes([1])
396
+
397
+ # Miner's reward output (6.25 BTC)
398
+ tx_data += struct.pack('<Q', 625000000) # Value in satoshis
399
+
400
+ # Create proper P2PKH script for payout
401
+ # First decode the base58 address to get the pubkey hash
402
+ from base58 import b58decode_check
403
+ decoded = b58decode_check(self.wallet_address)
404
+ pubkey_hash = decoded[1:] # Skip version byte
405
+
406
+ # Build P2PKH script
407
+ script_pubkey = bytes([0x76, 0xa9, 0x14]) + pubkey_hash + bytes([0x88, 0xac])
408
+ tx_data += bytes([len(script_pubkey)]) # Script length
409
+ tx_data += script_pubkey # P2PKH script
410
+
411
+ # Add locktime
412
+ tx_data += struct.pack('<I', 0) # nLockTime
413
+
414
+ # Add serialized coinbase transaction to block
415
+ block_data.extend(tx_data)
416
+
417
+ # Submit block using blockchain.info API
418
+ submit_url = 'https://api.blockchain.info/haskoin-store/btc/block'
419
+ headers = {'Content-Type': 'application/x-www-form-urlencoded'}
420
+ response = requests.post(submit_url, data={'block': block_data.hex()}, headers=headers)
421
+
422
+ if response.status_code == 200:
423
+ print(f"Block successfully submitted!")
424
+ logging.info("Block submission successful")
425
+ return True
426
+ elif response.status_code == 400 and 'bad-txns-vin-empty' in response.text:
427
+ print("Block rejected: Invalid coinbase transaction structure")
428
+ logging.error("Block rejected due to invalid coinbase transaction")
429
+ return False
430
+ else:
431
+ error_msg = response.text if response.text else f"Status code: {response.status_code}"
432
+ print(f"Block submission failed: {error_msg}")
433
+ logging.error(f"Block submission failed: {error_msg}")
434
+ return False
435
+
436
+ except Exception as e:
437
+ print(f"Error submitting block: {str(e)}")
438
+ return False
439
+ try:
440
+ block_hash = hashlib.sha256(hashlib.sha256(block_header).digest()).digest()
441
+ return self.bitcoin_network.submit_block(block_header, nonce)
442
+ except Exception as e:
443
+ print(f"Block submission error: {e}")
444
+ return False
445
+
446
+ def _bits_to_target(self, bits: str) -> int:
447
+ """Convert compact bits to target"""
448
+ bits = int(bits, 16)
449
+ shift = (bits >> 24) & 0xff
450
+ target = (bits & 0x00ffffff) * (2 ** (8 * (shift - 3)))
451
  return target