lunalib 1.5.1__py3-none-any.whl โ†’ 1.7.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of lunalib might be problematic. Click here for more details.

Files changed (48) hide show
  1. lunalib/core/__init__.py +14 -0
  2. lunalib/core/blockchain.py +183 -3
  3. lunalib/core/daemon.py +494 -0
  4. lunalib/core/p2p.py +361 -0
  5. lunalib/core/sm2.py +723 -723
  6. lunalib/core/wallet.py +714 -478
  7. lunalib/core/wallet_manager.py +638 -638
  8. lunalib/core/wallet_sync_helper.py +163 -163
  9. lunalib/gtx/digital_bill.py +10 -2
  10. lunalib/gtx/genesis.py +23 -24
  11. lunalib/mining/__init__.py +5 -0
  12. lunalib/mining/cuda_manager.py +23 -28
  13. lunalib/mining/difficulty.py +38 -0
  14. lunalib/mining/miner.py +526 -17
  15. lunalib/storage/cache.py +13 -4
  16. lunalib/storage/database.py +14 -5
  17. lunalib/storage/encryption.py +11 -2
  18. lunalib/transactions/security.py +19 -10
  19. lunalib/transactions/transactions.py +50 -41
  20. lunalib-1.7.2.dist-info/METADATA +27 -0
  21. lunalib-1.7.2.dist-info/RECORD +33 -0
  22. lunalib-1.7.2.dist-info/top_level.txt +1 -0
  23. core/__init__.py +0 -0
  24. core/blockchain.py +0 -172
  25. core/crypto.py +0 -32
  26. core/wallet.py +0 -408
  27. gtx/__init__.py +0 -0
  28. gtx/bill_registry.py +0 -122
  29. gtx/digital_bill.py +0 -273
  30. gtx/genesis.py +0 -338
  31. lunalib/requirements.txt +0 -44
  32. lunalib-1.5.1.dist-info/METADATA +0 -283
  33. lunalib-1.5.1.dist-info/RECORD +0 -53
  34. lunalib-1.5.1.dist-info/entry_points.txt +0 -2
  35. lunalib-1.5.1.dist-info/top_level.txt +0 -6
  36. mining/__init__.py +0 -0
  37. mining/cuda_manager.py +0 -137
  38. mining/difficulty.py +0 -106
  39. mining/miner.py +0 -107
  40. storage/__init__.py +0 -0
  41. storage/cache.py +0 -148
  42. storage/database.py +0 -222
  43. storage/encryption.py +0 -105
  44. transactions/__init__.py +0 -0
  45. transactions/security.py +0 -172
  46. transactions/transactions.py +0 -424
  47. transactions/validator.py +0 -71
  48. {lunalib-1.5.1.dist-info โ†’ lunalib-1.7.2.dist-info}/WHEEL +0 -0
lunalib/core/daemon.py ADDED
@@ -0,0 +1,494 @@
1
+ # lunalib/core/daemon.py
2
+ import time
3
+ import threading
4
+ from concurrent.futures import ThreadPoolExecutor
5
+ from typing import Dict, List, Optional, Callable
6
+ import json
7
+ from datetime import datetime
8
+
9
+
10
+ class BlockchainDaemon:
11
+ """
12
+ Primary blockchain daemon that manages the authoritative blockchain state.
13
+ Validates all transactions, manages peer registry, and serves as source of truth.
14
+ """
15
+
16
+ def __init__(self, blockchain_manager, mempool_manager, security_manager=None, max_workers=5):
17
+ self.blockchain = blockchain_manager
18
+ self.mempool = mempool_manager
19
+ self.security = security_manager
20
+
21
+ # Initialize difficulty system for validation
22
+ from ..mining.difficulty import DifficultySystem
23
+ self.difficulty_system = DifficultySystem()
24
+
25
+ # Thread pool for async operations
26
+ self.executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="DaemonWorker")
27
+ self._async_tasks = {} # Track async tasks
28
+
29
+ # Peer registry
30
+ self.peers = {} # {node_id: peer_info}
31
+ self.peer_lock = threading.Lock()
32
+
33
+ # Daemon state
34
+ self.is_running = False
35
+ self.validation_thread = None
36
+ self.cleanup_thread = None
37
+
38
+ # Statistics
39
+ self.stats = {
40
+ 'blocks_validated': 0,
41
+ 'transactions_validated': 0,
42
+ 'peers_registered': 0,
43
+ 'start_time': time.time()
44
+ }
45
+
46
+ def start(self):
47
+ """Start the blockchain daemon"""
48
+ if self.is_running:
49
+ return
50
+
51
+ self.is_running = True
52
+ print("๐Ÿ›๏ธ Blockchain Daemon starting...")
53
+
54
+ # Start background threads
55
+ self.validation_thread = threading.Thread(target=self._validation_loop, daemon=True)
56
+ self.validation_thread.start()
57
+
58
+ self.cleanup_thread = threading.Thread(target=self._cleanup_loop, daemon=True)
59
+ self.cleanup_thread.start()
60
+
61
+ print("โœ… Blockchain Daemon started")
62
+
63
+ def stop(self):
64
+ """Stop the blockchain daemon"""
65
+ self.is_running = False
66
+
67
+ if self.validation_thread:
68
+ self.validation_thread.join(timeout=5)
69
+ if self.cleanup_thread:
70
+ self.cleanup_thread.join(timeout=5)
71
+
72
+ # Shutdown executor
73
+ print("๐Ÿ›‘ Shutting down daemon executor...")
74
+ self.executor.shutdown(wait=True)
75
+
76
+ print("๐Ÿ›‘ Blockchain Daemon stopped")
77
+
78
+ def register_peer(self, peer_info: Dict) -> Dict:
79
+ """
80
+ Register a new peer node.
81
+ Returns: {'success': bool, 'node_id': str, 'message': str}
82
+ """
83
+ try:
84
+ node_id = peer_info.get('node_id')
85
+ if not node_id:
86
+ return {'success': False, 'message': 'Missing node_id'}
87
+
88
+ with self.peer_lock:
89
+ self.peers[node_id] = {
90
+ 'node_id': node_id,
91
+ 'registered_at': time.time(),
92
+ 'last_seen': time.time(),
93
+ 'capabilities': peer_info.get('capabilities', []),
94
+ 'url': peer_info.get('url'),
95
+ 'version': peer_info.get('version', 'unknown')
96
+ }
97
+
98
+ self.stats['peers_registered'] += 1
99
+
100
+ print(f"๐Ÿ‘ค New peer registered: {node_id}")
101
+ return {
102
+ 'success': True,
103
+ 'node_id': node_id,
104
+ 'message': 'Peer registered successfully'
105
+ }
106
+
107
+ except Exception as e:
108
+ return {'success': False, 'message': str(e)}
109
+
110
+ def unregister_peer(self, node_id: str) -> Dict:
111
+ """
112
+ Unregister a peer node.
113
+ Returns: {'success': bool, 'message': str}
114
+ """
115
+ try:
116
+ with self.peer_lock:
117
+ if node_id in self.peers:
118
+ del self.peers[node_id]
119
+ print(f"๐Ÿ‘‹ Peer unregistered: {node_id}")
120
+ return {'success': True, 'message': 'Peer unregistered'}
121
+ else:
122
+ return {'success': False, 'message': 'Peer not found'}
123
+ except Exception as e:
124
+ return {'success': False, 'message': str(e)}
125
+
126
+ def get_peer_list(self, exclude_node_id: Optional[str] = None) -> List[Dict]:
127
+ """
128
+ Get list of registered peers.
129
+ exclude_node_id: Optional node ID to exclude from results
130
+ """
131
+ with self.peer_lock:
132
+ peer_list = []
133
+ for node_id, peer_info in self.peers.items():
134
+ if exclude_node_id and node_id == exclude_node_id:
135
+ continue
136
+
137
+ peer_list.append({
138
+ 'node_id': peer_info['node_id'],
139
+ 'url': peer_info.get('url'),
140
+ 'last_seen': peer_info['last_seen'],
141
+ 'capabilities': peer_info.get('capabilities', [])
142
+ })
143
+
144
+ return peer_list
145
+
146
+ def update_peer_heartbeat(self, node_id: str):
147
+ """Update peer's last seen timestamp"""
148
+ with self.peer_lock:
149
+ if node_id in self.peers:
150
+ self.peers[node_id]['last_seen'] = time.time()
151
+
152
+ def validate_block_async(self, block: Dict, callback: Callable = None) -> str:
153
+ """Async version: Validate block in background thread
154
+
155
+ Returns: task_id that can be used to check status
156
+ """
157
+ task_id = f"validate_block_{block.get('index', 'unknown')}_{int(time.time())}"
158
+
159
+ def _validate_task():
160
+ try:
161
+ result = self.validate_block(block)
162
+ if callback:
163
+ callback(success=result['valid'], result=result, error=None if result['valid'] else result['message'])
164
+ return result
165
+ except Exception as e:
166
+ print(f"โŒ Async validation error: {e}")
167
+ if callback:
168
+ callback(success=False, result=None, error=str(e))
169
+ return {'valid': False, 'message': str(e), 'errors': [str(e)]}
170
+
171
+ future = self.executor.submit(_validate_task)
172
+ self._async_tasks[task_id] = future
173
+ print(f"๐Ÿ”„ Started async block validation: {task_id}")
174
+ return task_id
175
+
176
+ def validate_block(self, block: Dict) -> Dict:
177
+ """
178
+ Validate a block submitted by a peer or miner.
179
+ Returns: {'valid': bool, 'message': str, 'errors': List[str]}
180
+ """
181
+ errors = []
182
+
183
+ try:
184
+ # Basic structure validation using difficulty system
185
+ is_valid, error_msg = self.difficulty_system.validate_block_structure(block)
186
+ if not is_valid:
187
+ errors.append(error_msg)
188
+ return {'valid': False, 'message': 'Invalid block structure', 'errors': errors}
189
+
190
+ # Validate block index
191
+ latest_block = self.blockchain.get_latest_block()
192
+ if latest_block:
193
+ expected_index = latest_block.get('index', 0) + 1
194
+ if block['index'] != expected_index:
195
+ errors.append(f"Invalid block index: expected {expected_index}, got {block['index']}")
196
+
197
+ # Validate previous hash
198
+ if latest_block and block['previous_hash'] != latest_block.get('hash'):
199
+ expected_hash = latest_block.get('hash', '')
200
+ actual_hash = block.get('previous_hash', '')
201
+ errors.append(f"Previous hash mismatch: expected {expected_hash[:16]}..., got {actual_hash[:16]}...")
202
+
203
+ # Validate hash meets difficulty requirement using difficulty system
204
+ difficulty = block.get('difficulty', 0)
205
+ block_hash = block.get('hash', '')
206
+
207
+ if not self.difficulty_system.validate_block_hash(block_hash, difficulty):
208
+ errors.append(f"Hash doesn't meet difficulty {difficulty} requirement (needs {difficulty} leading zeros)")
209
+
210
+ # Validate reward matches difficulty
211
+ # Empty blocks use LINEAR system (difficulty = reward)
212
+ # Regular blocks use EXPONENTIAL system (10^(difficulty-1))
213
+ transactions = block.get('transactions', [])
214
+ is_empty_block = len(transactions) == 1 and transactions[0].get('is_empty_block', False)
215
+
216
+ if is_empty_block:
217
+ # Empty block: linear reward (difficulty 1 = 1 LKC, difficulty 2 = 2 LKC, etc.)
218
+ expected_reward = float(difficulty)
219
+ reward_type = "Linear"
220
+ else:
221
+ # Regular block: exponential reward (10^(difficulty-1))
222
+ expected_reward = self.difficulty_system.calculate_block_reward(difficulty)
223
+ reward_type = "Exponential"
224
+
225
+ actual_reward = block.get('reward', 0)
226
+
227
+ # Allow small tolerance for floating point comparison
228
+ if abs(actual_reward - expected_reward) > 0.01:
229
+ errors.append(f"Reward mismatch ({reward_type}): expected {expected_reward} LKC for difficulty {difficulty}, got {actual_reward} LKC")
230
+
231
+ # Validate transactions
232
+ for tx in block.get('transactions', []):
233
+ tx_validation = self.validate_transaction(tx)
234
+ if not tx_validation['valid']:
235
+ errors.append(f"Invalid transaction: {tx_validation['message']}")
236
+
237
+ if errors:
238
+ return {'valid': False, 'message': 'Block validation failed', 'errors': errors}
239
+
240
+ self.stats['blocks_validated'] += 1
241
+ print(f"โœ… Block #{block['index']} validated: Difficulty {difficulty}, Reward {actual_reward} LKC, Hash {block_hash[:16]}...")
242
+ return {'valid': True, 'message': 'Block is valid', 'errors': []}
243
+
244
+ except Exception as e:
245
+ return {'valid': False, 'message': f'Validation error: {str(e)}', 'errors': [str(e)]}
246
+
247
+ def validate_transaction(self, transaction: Dict) -> Dict:
248
+ """
249
+ Validate a transaction submitted by a peer.
250
+ Returns: {'valid': bool, 'message': str, 'errors': List[str]}
251
+ """
252
+ errors = []
253
+
254
+ try:
255
+ # Basic validation
256
+ tx_type = transaction.get('type')
257
+ if not tx_type:
258
+ errors.append("Missing transaction type")
259
+
260
+ # Type-specific validation
261
+ if tx_type == 'transaction':
262
+ required = ['from', 'to', 'amount', 'timestamp']
263
+ for field in required:
264
+ if field not in transaction:
265
+ errors.append(f"Missing field: {field}")
266
+
267
+ # Validate amount
268
+ amount = transaction.get('amount', 0)
269
+ if amount <= 0:
270
+ errors.append("Invalid amount: must be positive")
271
+
272
+ elif tx_type == 'genesis_bill':
273
+ if 'denomination' not in transaction:
274
+ errors.append("Missing denomination for genesis bill")
275
+
276
+ elif tx_type == 'reward':
277
+ required = ['to', 'amount']
278
+ for field in required:
279
+ if field not in transaction:
280
+ errors.append(f"Missing field: {field}")
281
+
282
+ # Security validation if available
283
+ if self.security and not errors:
284
+ try:
285
+ # Use security manager for advanced validation
286
+ # security_result = self.security.validate_transaction(transaction)
287
+ pass
288
+ except Exception as e:
289
+ errors.append(f"Security validation error: {e}")
290
+
291
+ if errors:
292
+ return {'valid': False, 'message': 'Transaction validation failed', 'errors': errors}
293
+
294
+ self.stats['transactions_validated'] += 1
295
+ return {'valid': True, 'message': 'Transaction is valid', 'errors': []}
296
+
297
+ except Exception as e:
298
+ return {'valid': False, 'message': f'Validation error: {str(e)}', 'errors': [str(e)]}
299
+
300
+ def process_incoming_block_async(self, block: Dict, from_peer: Optional[str] = None, callback: Callable = None) -> str:
301
+ """Async version: Process incoming block in background thread
302
+
303
+ Returns: task_id that can be used to check status
304
+ """
305
+ task_id = f"process_block_{block.get('index', 'unknown')}_{int(time.time())}"
306
+
307
+ def _process_task():
308
+ try:
309
+ result = self.process_incoming_block(block, from_peer)
310
+ if callback:
311
+ callback(success=result.get('success', False), result=result, error=None if result.get('success') else result.get('message'))
312
+ return result
313
+ except Exception as e:
314
+ print(f"โŒ Async block processing error: {e}")
315
+ if callback:
316
+ callback(success=False, result=None, error=str(e))
317
+ return {'success': False, 'message': str(e)}
318
+
319
+ future = self.executor.submit(_process_task)
320
+ self._async_tasks[task_id] = future
321
+ print(f"๐Ÿ”„ Started async block processing: {task_id}")
322
+ return task_id
323
+
324
+ def process_incoming_block(self, block: Dict, from_peer: Optional[str] = None) -> Dict:
325
+ """
326
+ Process an incoming block from P2P network.
327
+ Validates and adds to blockchain if valid.
328
+ """
329
+ try:
330
+ # Validate block
331
+ validation = self.validate_block(block)
332
+
333
+ if not validation['valid']:
334
+ print(f"โŒ Invalid block from peer {from_peer}: {validation['message']}")
335
+ return validation
336
+
337
+ # Add to blockchain
338
+ success = self.blockchain.submit_mined_block(block)
339
+
340
+ if success:
341
+ print(f"โœ… Block #{block['index']} accepted from peer {from_peer}")
342
+
343
+ # Broadcast to other peers
344
+ self._broadcast_block_to_peers(block, exclude=from_peer)
345
+
346
+ return {'success': True, 'message': 'Block accepted and propagated'}
347
+ else:
348
+ return {'success': False, 'message': 'Block submission failed'}
349
+
350
+ except Exception as e:
351
+ return {'success': False, 'message': f'Processing error: {str(e)}'}
352
+
353
+ def process_incoming_transaction(self, transaction: Dict, from_peer: Optional[str] = None) -> Dict:
354
+ """
355
+ Process an incoming transaction from P2P network.
356
+ Validates and adds to mempool if valid.
357
+ """
358
+ try:
359
+ # Validate transaction
360
+ validation = self.validate_transaction(transaction)
361
+
362
+ if not validation['valid']:
363
+ print(f"โŒ Invalid transaction from peer {from_peer}: {validation['message']}")
364
+ return validation
365
+
366
+ # Add to mempool
367
+ # self.mempool.add_transaction(transaction)
368
+ print(f"โœ… Transaction accepted from peer {from_peer}")
369
+
370
+ # Broadcast to other peers
371
+ self._broadcast_transaction_to_peers(transaction, exclude=from_peer)
372
+
373
+ return {'success': True, 'message': 'Transaction accepted and propagated'}
374
+
375
+ except Exception as e:
376
+ return {'success': False, 'message': f'Processing error: {str(e)}'}
377
+
378
+ def _broadcast_block_to_peers(self, block: Dict, exclude: Optional[str] = None):
379
+ """Broadcast block to all registered peers except excluded one"""
380
+ with self.peer_lock:
381
+ for node_id, peer_info in self.peers.items():
382
+ if node_id == exclude:
383
+ continue
384
+
385
+ # Send block to peer (implementation depends on transport)
386
+ # This would typically use HTTP POST or WebSocket
387
+ pass
388
+
389
+ def _broadcast_transaction_to_peers(self, transaction: Dict, exclude: Optional[str] = None):
390
+ """Broadcast transaction to all registered peers except excluded one"""
391
+ with self.peer_lock:
392
+ for node_id, peer_info in self.peers.items():
393
+ if node_id == exclude:
394
+ continue
395
+
396
+ # Send transaction to peer
397
+ pass
398
+
399
+ def _validation_loop(self):
400
+ """Background thread for continuous validation"""
401
+ while self.is_running:
402
+ try:
403
+ # Periodic mempool validation
404
+ # Remove invalid transactions from mempool
405
+ time.sleep(30)
406
+
407
+ except Exception as e:
408
+ print(f"โŒ Validation loop error: {e}")
409
+ time.sleep(10)
410
+
411
+ def _cleanup_loop(self):
412
+ """Background thread for peer cleanup"""
413
+ while self.is_running:
414
+ try:
415
+ current_time = time.time()
416
+ timeout = 300 # 5 minutes
417
+
418
+ with self.peer_lock:
419
+ inactive_peers = []
420
+ for node_id, peer_info in self.peers.items():
421
+ if current_time - peer_info['last_seen'] > timeout:
422
+ inactive_peers.append(node_id)
423
+
424
+ # Remove inactive peers
425
+ for node_id in inactive_peers:
426
+ del self.peers[node_id]
427
+ print(f"๐Ÿงน Removed inactive peer: {node_id}")
428
+
429
+ time.sleep(60) # Check every minute
430
+
431
+ except Exception as e:
432
+ print(f"โŒ Cleanup loop error: {e}")
433
+ time.sleep(60)
434
+
435
+ def get_task_status(self, task_id: str) -> Dict:
436
+ """Check status of an async task
437
+
438
+ Returns: {'status': 'running'|'completed'|'failed'|'not_found', 'result': any, 'error': str}
439
+ """
440
+ if task_id not in self._async_tasks:
441
+ return {'status': 'not_found', 'result': None, 'error': 'Task not found'}
442
+
443
+ future = self._async_tasks[task_id]
444
+
445
+ if future.running():
446
+ return {'status': 'running', 'result': None, 'error': None}
447
+ elif future.done():
448
+ try:
449
+ result = future.result(timeout=0)
450
+ return {'status': 'completed', 'result': result, 'error': None}
451
+ except Exception as e:
452
+ return {'status': 'failed', 'result': None, 'error': str(e)}
453
+ else:
454
+ return {'status': 'pending', 'result': None, 'error': None}
455
+
456
+ def get_active_tasks(self) -> List[str]:
457
+ """Get list of active task IDs"""
458
+ return [task_id for task_id, future in self._async_tasks.items() if future.running()]
459
+
460
+ def cleanup_completed_tasks(self):
461
+ """Remove completed tasks from tracking"""
462
+ completed = [task_id for task_id, future in self._async_tasks.items() if future.done()]
463
+ for task_id in completed:
464
+ del self._async_tasks[task_id]
465
+ if completed:
466
+ print(f"๐Ÿงน Cleaned up {len(completed)} completed tasks")
467
+
468
+ def get_stats(self) -> Dict:
469
+ """Get daemon statistics"""
470
+ uptime = time.time() - self.stats['start_time']
471
+
472
+ with self.peer_lock:
473
+ peer_count = len(self.peers)
474
+
475
+ return {
476
+ 'uptime_seconds': uptime,
477
+ 'blocks_validated': self.stats['blocks_validated'],
478
+ 'transactions_validated': self.stats['transactions_validated'],
479
+ 'peers_registered': self.stats['peers_registered'],
480
+ 'active_peers': peer_count,
481
+ 'mempool_size': len(self.mempool.get_pending_transactions()) if self.mempool else 0
482
+ }
483
+
484
+ def get_blockchain_state(self) -> Dict:
485
+ """Get current blockchain state for peers"""
486
+ latest_block = self.blockchain.get_latest_block()
487
+ height = self.blockchain.get_blockchain_height()
488
+
489
+ return {
490
+ 'height': height,
491
+ 'latest_block': latest_block,
492
+ 'mempool_size': len(self.mempool.get_pending_transactions()) if self.mempool else 0,
493
+ 'timestamp': time.time()
494
+ }