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.
- lunalib/core/__init__.py +14 -0
- lunalib/core/blockchain.py +183 -3
- lunalib/core/daemon.py +494 -0
- lunalib/core/p2p.py +361 -0
- lunalib/core/sm2.py +723 -723
- lunalib/core/wallet.py +714 -478
- lunalib/core/wallet_manager.py +638 -638
- lunalib/core/wallet_sync_helper.py +163 -163
- lunalib/gtx/digital_bill.py +10 -2
- lunalib/gtx/genesis.py +23 -24
- lunalib/mining/__init__.py +5 -0
- lunalib/mining/cuda_manager.py +23 -28
- lunalib/mining/difficulty.py +38 -0
- lunalib/mining/miner.py +526 -17
- lunalib/storage/cache.py +13 -4
- lunalib/storage/database.py +14 -5
- lunalib/storage/encryption.py +11 -2
- lunalib/transactions/security.py +19 -10
- lunalib/transactions/transactions.py +50 -41
- lunalib-1.7.2.dist-info/METADATA +27 -0
- lunalib-1.7.2.dist-info/RECORD +33 -0
- lunalib-1.7.2.dist-info/top_level.txt +1 -0
- core/__init__.py +0 -0
- core/blockchain.py +0 -172
- core/crypto.py +0 -32
- core/wallet.py +0 -408
- gtx/__init__.py +0 -0
- gtx/bill_registry.py +0 -122
- gtx/digital_bill.py +0 -273
- gtx/genesis.py +0 -338
- lunalib/requirements.txt +0 -44
- lunalib-1.5.1.dist-info/METADATA +0 -283
- lunalib-1.5.1.dist-info/RECORD +0 -53
- lunalib-1.5.1.dist-info/entry_points.txt +0 -2
- lunalib-1.5.1.dist-info/top_level.txt +0 -6
- mining/__init__.py +0 -0
- mining/cuda_manager.py +0 -137
- mining/difficulty.py +0 -106
- mining/miner.py +0 -107
- storage/__init__.py +0 -0
- storage/cache.py +0 -148
- storage/database.py +0 -222
- storage/encryption.py +0 -105
- transactions/__init__.py +0 -0
- transactions/security.py +0 -172
- transactions/transactions.py +0 -424
- transactions/validator.py +0 -71
- {lunalib-1.5.1.dist-info → lunalib-1.7.2.dist-info}/WHEEL +0 -0
lunalib/core/__init__.py
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .blockchain import BlockchainManager
|
|
2
|
+
from .wallet import LunaWallet
|
|
3
|
+
from .mempool import MempoolManager
|
|
4
|
+
from .p2p import P2PClient, HybridBlockchainClient
|
|
5
|
+
from .daemon import BlockchainDaemon
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
'BlockchainManager',
|
|
9
|
+
'LunaWallet',
|
|
10
|
+
'MempoolManager',
|
|
11
|
+
'P2PClient',
|
|
12
|
+
'HybridBlockchainClient',
|
|
13
|
+
'BlockchainDaemon'
|
|
14
|
+
]
|
lunalib/core/blockchain.py
CHANGED
|
@@ -4,17 +4,23 @@ from ..storage.cache import BlockchainCache
|
|
|
4
4
|
import requests
|
|
5
5
|
import time
|
|
6
6
|
import json
|
|
7
|
-
|
|
7
|
+
import asyncio
|
|
8
|
+
import threading
|
|
9
|
+
from concurrent.futures import ThreadPoolExecutor, Future
|
|
10
|
+
from typing import Dict, List, Optional, Tuple, Callable
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class BlockchainManager:
|
|
11
14
|
"""Manages blockchain interactions and scanning with transaction broadcasting"""
|
|
12
15
|
|
|
13
|
-
def __init__(self, endpoint_url="https://bank.linglin.art"):
|
|
16
|
+
def __init__(self, endpoint_url="https://bank.linglin.art", max_workers=10):
|
|
14
17
|
self.endpoint_url = endpoint_url.rstrip('/')
|
|
15
18
|
self.cache = BlockchainCache()
|
|
16
19
|
self.network_connected = False
|
|
17
20
|
self._stop_events = [] # Track background monitors so they can be stopped
|
|
21
|
+
self.executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="BlockchainWorker")
|
|
22
|
+
self._async_tasks = {} # Track async tasks by ID
|
|
23
|
+
self._task_callbacks = {} # Callbacks for task completion
|
|
18
24
|
|
|
19
25
|
# ------------------------------------------------------------------
|
|
20
26
|
# Address helpers
|
|
@@ -26,6 +32,30 @@ class BlockchainManager:
|
|
|
26
32
|
addr_str = str(addr).strip("'\" ").lower()
|
|
27
33
|
return addr_str[4:] if addr_str.startswith('lun_') else addr_str
|
|
28
34
|
|
|
35
|
+
def broadcast_transaction_async(self, transaction: Dict, callback: Callable = None) -> str:
|
|
36
|
+
"""Async version: Broadcast transaction in background thread
|
|
37
|
+
|
|
38
|
+
Returns: task_id that can be used to check status
|
|
39
|
+
"""
|
|
40
|
+
task_id = f"broadcast_{transaction.get('hash', 'unknown')}_{int(time.time())}"
|
|
41
|
+
|
|
42
|
+
def _broadcast_task():
|
|
43
|
+
try:
|
|
44
|
+
success, message = self.broadcast_transaction(transaction)
|
|
45
|
+
if callback:
|
|
46
|
+
callback(success=success, result=message, error=None if success else message)
|
|
47
|
+
return (success, message)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"❌ Async broadcast error: {e}")
|
|
50
|
+
if callback:
|
|
51
|
+
callback(success=False, result=None, error=str(e))
|
|
52
|
+
return (False, str(e))
|
|
53
|
+
|
|
54
|
+
future = self.executor.submit(_broadcast_task)
|
|
55
|
+
self._async_tasks[task_id] = future
|
|
56
|
+
print(f"🔄 Started async broadcast: {task_id}")
|
|
57
|
+
return task_id
|
|
58
|
+
|
|
29
59
|
def broadcast_transaction(self, transaction: Dict) -> Tuple[bool, str]:
|
|
30
60
|
"""Broadcast transaction to mempool with enhanced error handling"""
|
|
31
61
|
try:
|
|
@@ -210,6 +240,30 @@ class BlockchainManager:
|
|
|
210
240
|
|
|
211
241
|
return None
|
|
212
242
|
|
|
243
|
+
def get_blocks_range_async(self, start_height: int, end_height: int, callback: Callable = None) -> str:
|
|
244
|
+
"""Async version: Get range of blocks in background thread
|
|
245
|
+
|
|
246
|
+
Returns: task_id that can be used to check status
|
|
247
|
+
"""
|
|
248
|
+
task_id = f"blocks_range_{start_height}_{end_height}_{int(time.time())}"
|
|
249
|
+
|
|
250
|
+
def _fetch_task():
|
|
251
|
+
try:
|
|
252
|
+
result = self.get_blocks_range(start_height, end_height)
|
|
253
|
+
if callback:
|
|
254
|
+
callback(success=True, result=result, error=None)
|
|
255
|
+
return result
|
|
256
|
+
except Exception as e:
|
|
257
|
+
print(f"❌ Async blocks fetch error: {e}")
|
|
258
|
+
if callback:
|
|
259
|
+
callback(success=False, result=None, error=str(e))
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
future = self.executor.submit(_fetch_task)
|
|
263
|
+
self._async_tasks[task_id] = future
|
|
264
|
+
print(f"🔄 Started async blocks fetch: {task_id}")
|
|
265
|
+
return task_id
|
|
266
|
+
|
|
213
267
|
def get_blocks_range(self, start_height: int, end_height: int) -> List[Dict]:
|
|
214
268
|
"""Get range of blocks"""
|
|
215
269
|
blocks = []
|
|
@@ -286,6 +340,31 @@ class BlockchainManager:
|
|
|
286
340
|
|
|
287
341
|
print(f"[SCAN] Found {len(transactions)} total transactions for {address}")
|
|
288
342
|
return transactions
|
|
343
|
+
|
|
344
|
+
def scan_transactions_for_address_async(self, address: str, callback: Callable = None,
|
|
345
|
+
start_height: int = 0, end_height: int = None) -> str:
|
|
346
|
+
"""Async version: Scan blockchain in background thread, call callback when done
|
|
347
|
+
|
|
348
|
+
Returns: task_id that can be used to check status
|
|
349
|
+
"""
|
|
350
|
+
task_id = f"scan_{address}_{int(time.time())}"
|
|
351
|
+
|
|
352
|
+
def _scan_task():
|
|
353
|
+
try:
|
|
354
|
+
result = self.scan_transactions_for_address(address, start_height, end_height)
|
|
355
|
+
if callback:
|
|
356
|
+
callback(success=True, result=result, error=None)
|
|
357
|
+
return result
|
|
358
|
+
except Exception as e:
|
|
359
|
+
print(f"❌ Async scan error: {e}")
|
|
360
|
+
if callback:
|
|
361
|
+
callback(success=False, result=None, error=str(e))
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
future = self.executor.submit(_scan_task)
|
|
365
|
+
self._async_tasks[task_id] = future
|
|
366
|
+
print(f"🔄 Started async scan task: {task_id}")
|
|
367
|
+
return task_id
|
|
289
368
|
|
|
290
369
|
def scan_transactions_for_addresses(self, addresses: List[str], start_height: int = 0, end_height: int = None) -> Dict[str, List[Dict]]:
|
|
291
370
|
"""Scan the blockchain once for multiple addresses (rewards and transfers)."""
|
|
@@ -328,7 +407,84 @@ class BlockchainManager:
|
|
|
328
407
|
print(f" - {addr}: {len(results[addr])} transactions")
|
|
329
408
|
|
|
330
409
|
return results
|
|
410
|
+
|
|
411
|
+
def scan_transactions_for_addresses_async(self, addresses: List[str], callback: Callable = None,
|
|
412
|
+
start_height: int = 0, end_height: int = None) -> str:
|
|
413
|
+
"""Async version: Scan blockchain for multiple addresses in background thread
|
|
414
|
+
|
|
415
|
+
Returns: task_id that can be used to check status
|
|
416
|
+
"""
|
|
417
|
+
task_id = f"multi_scan_{int(time.time())}"
|
|
418
|
+
|
|
419
|
+
def _scan_task():
|
|
420
|
+
try:
|
|
421
|
+
result = self.scan_transactions_for_addresses(addresses, start_height, end_height)
|
|
422
|
+
if callback:
|
|
423
|
+
callback(success=True, result=result, error=None)
|
|
424
|
+
return result
|
|
425
|
+
except Exception as e:
|
|
426
|
+
print(f"❌ Async multi-scan error: {e}")
|
|
427
|
+
if callback:
|
|
428
|
+
callback(success=False, result=None, error=str(e))
|
|
429
|
+
return None
|
|
430
|
+
|
|
431
|
+
future = self.executor.submit(_scan_task)
|
|
432
|
+
self._async_tasks[task_id] = future
|
|
433
|
+
print(f"🔄 Started async multi-scan task: {task_id}")
|
|
434
|
+
return task_id
|
|
331
435
|
|
|
436
|
+
def get_task_status(self, task_id: str) -> Dict:
|
|
437
|
+
"""Check status of an async task
|
|
438
|
+
|
|
439
|
+
Returns: {'status': 'running'|'completed'|'failed'|'not_found', 'result': any, 'error': str}
|
|
440
|
+
"""
|
|
441
|
+
if task_id not in self._async_tasks:
|
|
442
|
+
return {'status': 'not_found', 'result': None, 'error': 'Task not found'}
|
|
443
|
+
|
|
444
|
+
future = self._async_tasks[task_id]
|
|
445
|
+
|
|
446
|
+
if future.running():
|
|
447
|
+
return {'status': 'running', 'result': None, 'error': None}
|
|
448
|
+
elif future.done():
|
|
449
|
+
try:
|
|
450
|
+
result = future.result(timeout=0)
|
|
451
|
+
return {'status': 'completed', 'result': result, 'error': None}
|
|
452
|
+
except Exception as e:
|
|
453
|
+
return {'status': 'failed', 'result': None, 'error': str(e)}
|
|
454
|
+
else:
|
|
455
|
+
return {'status': 'pending', 'result': None, 'error': None}
|
|
456
|
+
|
|
457
|
+
def cancel_task(self, task_id: str) -> bool:
|
|
458
|
+
"""Cancel a running async task
|
|
459
|
+
|
|
460
|
+
Returns: True if cancelled, False otherwise
|
|
461
|
+
"""
|
|
462
|
+
if task_id in self._async_tasks:
|
|
463
|
+
future = self._async_tasks[task_id]
|
|
464
|
+
if future.cancel():
|
|
465
|
+
del self._async_tasks[task_id]
|
|
466
|
+
print(f"✅ Task cancelled: {task_id}")
|
|
467
|
+
return True
|
|
468
|
+
return False
|
|
469
|
+
|
|
470
|
+
def get_active_tasks(self) -> List[str]:
|
|
471
|
+
"""Get list of active task IDs"""
|
|
472
|
+
return [task_id for task_id, future in self._async_tasks.items() if future.running()]
|
|
473
|
+
|
|
474
|
+
def cleanup_completed_tasks(self):
|
|
475
|
+
"""Remove completed tasks from tracking"""
|
|
476
|
+
completed = [task_id for task_id, future in self._async_tasks.items() if future.done()]
|
|
477
|
+
for task_id in completed:
|
|
478
|
+
del self._async_tasks[task_id]
|
|
479
|
+
if completed:
|
|
480
|
+
print(f"🧹 Cleaned up {len(completed)} completed tasks")
|
|
481
|
+
|
|
482
|
+
def shutdown(self):
|
|
483
|
+
"""Shutdown the thread pool executor"""
|
|
484
|
+
print("🛑 Shutting down BlockchainManager executor...")
|
|
485
|
+
self.executor.shutdown(wait=True)
|
|
486
|
+
print("✅ Executor shutdown complete")
|
|
487
|
+
|
|
332
488
|
def monitor_addresses(self, addresses: List[str], on_update, poll_interval: int = 15):
|
|
333
489
|
"""Start background monitor for addresses; returns a stop event."""
|
|
334
490
|
import threading
|
|
@@ -379,6 +535,30 @@ class BlockchainManager:
|
|
|
379
535
|
thread.start()
|
|
380
536
|
return stop_event
|
|
381
537
|
|
|
538
|
+
def submit_mined_block_async(self, block_data: Dict, callback: Callable = None) -> str:
|
|
539
|
+
"""Async version: Submit mined block in background thread
|
|
540
|
+
|
|
541
|
+
Returns: task_id that can be used to check status
|
|
542
|
+
"""
|
|
543
|
+
task_id = f"submit_block_{block_data.get('index', 'unknown')}_{int(time.time())}"
|
|
544
|
+
|
|
545
|
+
def _submit_task():
|
|
546
|
+
try:
|
|
547
|
+
success = self.submit_mined_block(block_data)
|
|
548
|
+
if callback:
|
|
549
|
+
callback(success=success, result=block_data if success else None, error=None if success else "Submission failed")
|
|
550
|
+
return success
|
|
551
|
+
except Exception as e:
|
|
552
|
+
print(f"❌ Async block submission error: {e}")
|
|
553
|
+
if callback:
|
|
554
|
+
callback(success=False, result=None, error=str(e))
|
|
555
|
+
return False
|
|
556
|
+
|
|
557
|
+
future = self.executor.submit(_submit_task)
|
|
558
|
+
self._async_tasks[task_id] = future
|
|
559
|
+
print(f"🔄 Started async block submission: {task_id}")
|
|
560
|
+
return task_id
|
|
561
|
+
|
|
382
562
|
def submit_mined_block(self, block_data: Dict) -> bool:
|
|
383
563
|
"""Submit a mined block to the network with built-in validation"""
|
|
384
564
|
try:
|
|
@@ -736,7 +916,7 @@ class BlockchainManager:
|
|
|
736
916
|
transactions.append(enhanced_tx)
|
|
737
917
|
print(f"⬇️ Found outgoing transaction: {amount} LUN + {fee} fee")
|
|
738
918
|
|
|
739
|
-
print(f"
|
|
919
|
+
print(f" Scan complete for block #{block.get('index')}: {len(transactions)} transactions found")
|
|
740
920
|
return transactions
|
|
741
921
|
def _handle_regular_transfers(self, tx: Dict, address_lower: str) -> Dict:
|
|
742
922
|
"""Handle regular transfer transactions that might be in different formats"""
|