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
core/wallet.py DELETED
@@ -1,408 +0,0 @@
1
- # wallet.py
2
- import time
3
- import hashlib
4
- import json
5
- from cryptography.fernet import Fernet
6
- import base64
7
- import os
8
-
9
- class LunaWallet:
10
- """Luna wallet implementation with proper key management"""
11
-
12
- def __init__(self, data_dir=None):
13
- self.data_dir = data_dir
14
- self.wallets = {} # Main wallet storage: {address: wallet_data}
15
- self.current_wallet_address = None # Track which wallet is active
16
-
17
- # Initialize with an empty current wallet state
18
- self._reset_current_wallet()
19
-
20
- def _reset_current_wallet(self):
21
- """Reset current wallet to empty state"""
22
- self.address = None
23
- self.balance = 0.0
24
- self.available_balance = 0.0
25
- self.created = time.time()
26
- self.private_key = None
27
- self.public_key = None
28
- self.encrypted_private_key = None
29
- self.label = "New Wallet"
30
- self.is_locked = True
31
- self.pending_transactions = {} # {tx_hash: amount}
32
-
33
- def _generate_address(self):
34
- """Generate wallet address"""
35
- base_data = f"LUN_{int(time.time()*1000)}_{hashlib.sha256(str(time.time()).encode()).hexdigest()[:8]}"
36
- return hashlib.sha256(base_data.encode()).hexdigest()[:32]
37
-
38
- def _generate_private_key(self):
39
- """Generate private key"""
40
- return f"priv_{hashlib.sha256(str(time.time()).encode()).hexdigest()}"
41
-
42
- def _derive_public_key(self, private_key=None):
43
- """Derive public key from private key"""
44
- priv_key = private_key or self.private_key
45
- if not priv_key:
46
- return None
47
- return f"pub_{priv_key[-16:]}"
48
-
49
- def get_wallet_info(self):
50
- """Get complete wallet information for current wallet"""
51
- if not self.address:
52
- return None
53
- return {
54
- 'address': self.address,
55
- 'balance': self.balance,
56
- 'available_balance': self.available_balance,
57
- 'pending_amount': self.get_pending_amount(),
58
- 'created': self.created,
59
- 'private_key': self.private_key,
60
- 'public_key': self.public_key,
61
- 'encrypted_private_key': self.encrypted_private_key,
62
- 'label': self.label,
63
- 'is_locked': self.is_locked
64
- }
65
-
66
- def create_new_wallet(self, name, password):
67
- """Create a new wallet and add to collection without switching"""
68
- # Generate new wallet data
69
- address = self._generate_address()
70
- private_key = self._generate_private_key()
71
- public_key = f"pub_{private_key[-16:]}"
72
-
73
- # Encrypt private key
74
- key = base64.urlsafe_b64encode(hashlib.sha256(password.encode()).digest())
75
- fernet = Fernet(key)
76
- encrypted_private_key = fernet.encrypt(private_key.encode())
77
-
78
- # Create new wallet data
79
- new_wallet_data = {
80
- 'address': address,
81
- 'balance': 0.0,
82
- 'available_balance': 0.0,
83
- 'created': time.time(),
84
- 'private_key': private_key,
85
- 'public_key': public_key,
86
- 'encrypted_private_key': encrypted_private_key,
87
- 'label': name,
88
- 'is_locked': True,
89
- 'pending_transactions': {}
90
- }
91
-
92
- # CRITICAL: Add to wallets collection
93
- self.wallets[address] = new_wallet_data
94
-
95
- print(f"DEBUG: Created new wallet {address}, total wallets: {len(self.wallets)}")
96
-
97
- return new_wallet_data
98
- def create_wallet(self, name, password):
99
- """Create a new wallet and set it as current"""
100
- # Generate new wallet data
101
- address = self._generate_address()
102
- private_key = self._generate_private_key()
103
- public_key = f"pub_{private_key[-16:]}"
104
-
105
- # Encrypt private key
106
- key = base64.urlsafe_b64encode(hashlib.sha256(password.encode()).digest())
107
- fernet = Fernet(key)
108
- encrypted_private_key = fernet.encrypt(private_key.encode())
109
-
110
- # Create wallet data
111
- wallet_data = {
112
- 'address': address,
113
- 'balance': 0.0,
114
- 'available_balance': 0.0,
115
- 'created': time.time(),
116
- 'private_key': private_key,
117
- 'public_key': public_key,
118
- 'encrypted_private_key': encrypted_private_key,
119
- 'label': name,
120
- 'is_locked': True,
121
- 'pending_transactions': {}
122
- }
123
-
124
- # CRITICAL: Add to wallets collection
125
- self.wallets[address] = wallet_data
126
-
127
- # Set as current wallet
128
- self._set_current_wallet(wallet_data)
129
-
130
- print(f"DEBUG: Created and switched to wallet {address}, total wallets: {len(self.wallets)}")
131
-
132
- return wallet_data
133
- def _set_current_wallet(self, wallet_data):
134
- """Set the current wallet from wallet data"""
135
- self.current_wallet_address = wallet_data['address']
136
- self.address = wallet_data['address']
137
- self.balance = wallet_data['balance']
138
- self.pending_transactions = wallet_data.get('pending_transactions', {})
139
- self._recalculate_available_balance()
140
- self.created = wallet_data['created']
141
- self.private_key = wallet_data['private_key']
142
- self.public_key = wallet_data['public_key']
143
- self.encrypted_private_key = wallet_data['encrypted_private_key']
144
- self.label = wallet_data['label']
145
- self.is_locked = wallet_data.get('is_locked', True)
146
-
147
- def switch_wallet(self, address, password=None):
148
- """Switch to a different wallet in the collection"""
149
- if address in self.wallets:
150
- wallet_data = self.wallets[address]
151
- self._set_current_wallet(wallet_data)
152
-
153
- # If password provided, unlock the wallet
154
- if password:
155
- return self.unlock_wallet(address, password)
156
-
157
- return True
158
- return False
159
-
160
- def unlock_wallet(self, address, password):
161
- """Unlock wallet with password"""
162
- if address not in self.wallets:
163
- return False
164
-
165
- wallet_data = self.wallets[address]
166
-
167
- try:
168
- if wallet_data.get('encrypted_private_key'):
169
- key = base64.urlsafe_b64encode(hashlib.sha256(password.encode()).digest())
170
- fernet = Fernet(key)
171
- decrypted_key = fernet.decrypt(wallet_data['encrypted_private_key'])
172
- wallet_data['private_key'] = decrypted_key.decode()
173
- wallet_data['is_locked'] = False
174
-
175
- # If this is the current wallet, update current state
176
- if self.current_wallet_address == address:
177
- self.private_key = wallet_data['private_key']
178
- self.is_locked = False
179
-
180
- return True
181
- except:
182
- pass
183
- return False
184
-
185
- @property
186
- def is_unlocked(self):
187
- """Check if current wallet is unlocked"""
188
- if not self.current_wallet_address:
189
- return False
190
- wallet_data = self.wallets.get(self.current_wallet_address, {})
191
- return not wallet_data.get('is_locked', True)
192
-
193
- def export_private_key(self, address, password):
194
- """Export private key with password decryption"""
195
- if address not in self.wallets:
196
- return None
197
-
198
- wallet_data = self.wallets[address]
199
-
200
- try:
201
- if wallet_data.get('encrypted_private_key'):
202
- key = base64.urlsafe_b64encode(hashlib.sha256(password.encode()).digest())
203
- fernet = Fernet(key)
204
- decrypted_key = fernet.decrypt(wallet_data['encrypted_private_key'])
205
- return decrypted_key.decode()
206
- except:
207
- pass
208
- return None
209
-
210
- def import_wallet(self, wallet_data, password=None):
211
- """Import wallet from data"""
212
- if isinstance(wallet_data, dict):
213
- address = wallet_data.get('address')
214
- if not address:
215
- return False
216
-
217
- # Ensure pending_transactions exists
218
- if 'pending_transactions' not in wallet_data:
219
- wallet_data['pending_transactions'] = {}
220
-
221
- # Add to wallets collection
222
- self.wallets[address] = wallet_data.copy()
223
-
224
- # Set as current wallet
225
- self._set_current_wallet(wallet_data)
226
-
227
- if password and wallet_data.get('encrypted_private_key'):
228
- return self.unlock_wallet(address, password)
229
-
230
- return True
231
- return False
232
-
233
- def update_balance(self, new_balance):
234
- """Update current wallet balance"""
235
- self.balance = float(new_balance)
236
- self._recalculate_available_balance()
237
-
238
- # Also update in wallets collection
239
- if self.current_wallet_address and self.current_wallet_address in self.wallets:
240
- self.wallets[self.current_wallet_address]['balance'] = self.balance
241
- self.wallets[self.current_wallet_address]['available_balance'] = self.available_balance
242
-
243
- return True
244
-
245
- def _recalculate_available_balance(self):
246
- """Recalculate available balance based on pending transactions"""
247
- pending_amount = sum(self.pending_transactions.values())
248
- self.available_balance = max(0.0, self.balance - pending_amount)
249
-
250
- def add_pending_transaction(self, tx_hash: str, amount: float) -> bool:
251
- """Add a transaction to pending list (e.g., when sent to mempool)"""
252
- if amount > self.available_balance:
253
- return False
254
- self.pending_transactions[tx_hash] = float(amount)
255
- self._recalculate_available_balance()
256
-
257
- # Update in wallets collection
258
- if self.current_wallet_address and self.current_wallet_address in self.wallets:
259
- self.wallets[self.current_wallet_address]['pending_transactions'] = self.pending_transactions
260
- self.wallets[self.current_wallet_address]['available_balance'] = self.available_balance
261
-
262
- return True
263
-
264
- def confirm_pending_transaction(self, tx_hash: str) -> bool:
265
- """Confirm a pending transaction (e.g., added to blockchain)"""
266
- if tx_hash in self.pending_transactions:
267
- del self.pending_transactions[tx_hash]
268
- self._recalculate_available_balance()
269
-
270
- # Update in wallets collection
271
- if self.current_wallet_address and self.current_wallet_address in self.wallets:
272
- self.wallets[self.current_wallet_address]['pending_transactions'] = self.pending_transactions
273
- self.wallets[self.current_wallet_address]['available_balance'] = self.available_balance
274
-
275
- return True
276
- return False
277
-
278
- def get_pending_amount(self) -> float:
279
- """Get total amount in pending transactions"""
280
- return sum(self.pending_transactions.values())
281
-
282
- def get_pending_transactions(self) -> dict:
283
- """Get all pending transactions"""
284
- return self.pending_transactions.copy()
285
-
286
- def clear_pending_transaction(self, tx_hash: str) -> bool:
287
- """Remove a pending transaction (e.g., if it failed)"""
288
- return self.confirm_pending_transaction(tx_hash)
289
-
290
- def get_balance(self):
291
- """Get current wallet balance"""
292
- return self.balance
293
-
294
- def get_wallet_by_address(self, address):
295
- """Get wallet by address from wallets collection"""
296
- return self.wallets.get(address)
297
-
298
- def list_wallets(self):
299
- """List all wallets in collection"""
300
- return list(self.wallets.keys())
301
-
302
- def get_current_wallet_info(self):
303
- """Get current wallet information"""
304
- if not self.current_wallet_address:
305
- return None
306
- return self.wallets.get(self.current_wallet_address)
307
-
308
- def save_to_file(self, filename=None):
309
- """Save wallet to file"""
310
- if not self.data_dir:
311
- return False
312
-
313
- if filename is None:
314
- filename = f"wallet_{self.address}.json"
315
-
316
- filepath = os.path.join(self.data_dir, filename)
317
-
318
- try:
319
- # Ensure directory exists
320
- os.makedirs(self.data_dir, exist_ok=True)
321
-
322
- # Prepare encrypted private key for serialization
323
- encrypted_key_data = None
324
- if self.encrypted_private_key:
325
- # Ensure it's bytes before encoding
326
- if isinstance(self.encrypted_private_key, bytes):
327
- encrypted_key_data = base64.b64encode(self.encrypted_private_key).decode('utf-8')
328
- else:
329
- encrypted_key_data = base64.b64encode(self.encrypted_private_key.encode()).decode('utf-8')
330
-
331
- # Prepare wallets for serialization (remove any non-serializable data)
332
- serializable_wallets = {}
333
- for addr, wallet_info in self.wallets.items():
334
- serializable_wallet = wallet_info.copy()
335
- # Ensure encrypted_private_key is serializable
336
- if serializable_wallet.get('encrypted_private_key') and isinstance(serializable_wallet['encrypted_private_key'], bytes):
337
- serializable_wallet['encrypted_private_key'] = base64.b64encode(
338
- serializable_wallet['encrypted_private_key']
339
- ).decode('utf-8')
340
- serializable_wallets[addr] = serializable_wallet
341
-
342
- wallet_data = {
343
- 'address': self.address,
344
- 'balance': self.balance,
345
- 'available_balance': self.available_balance,
346
- 'pending_amount': self.get_pending_amount(),
347
- 'pending_transactions': self.pending_transactions,
348
- 'created': self.created,
349
- 'public_key': self.public_key,
350
- 'encrypted_private_key': encrypted_key_data,
351
- 'label': self.label,
352
- 'is_locked': self.is_locked,
353
- 'wallets': serializable_wallets,
354
- 'current_wallet_address': self.current_wallet_address
355
- }
356
-
357
- with open(filepath, 'w') as f:
358
- json.dump(wallet_data, f, indent=2)
359
- return True
360
- except Exception as e:
361
- print(f"Error saving wallet: {e}")
362
- import traceback
363
- traceback.print_exc()
364
- return False
365
-
366
- def load_from_file(self, filename, password=None):
367
- """Load wallet from file"""
368
- if not self.data_dir:
369
- return False
370
-
371
- filepath = os.path.join(self.data_dir, filename)
372
-
373
- try:
374
- with open(filepath, 'r') as f:
375
- wallet_data = json.load(f)
376
-
377
- # Load wallets collection
378
- self.wallets = wallet_data.get('wallets', {})
379
-
380
- # Ensure all wallets have pending_transactions field
381
- for addr, w_data in self.wallets.items():
382
- if 'pending_transactions' not in w_data:
383
- w_data['pending_transactions'] = {}
384
-
385
- # Load current wallet address
386
- self.current_wallet_address = wallet_data.get('current_wallet_address')
387
-
388
- # If we have a current wallet, load its data
389
- if self.current_wallet_address and self.current_wallet_address in self.wallets:
390
- current_wallet_data = self.wallets[self.current_wallet_address]
391
- self._set_current_wallet(current_wallet_data)
392
-
393
- # Handle encrypted private key
394
- encrypted_key = wallet_data.get('encrypted_private_key')
395
- if encrypted_key:
396
- self.encrypted_private_key = base64.b64decode(encrypted_key.encode())
397
- # Also update in wallets collection
398
- if self.current_wallet_address in self.wallets:
399
- self.wallets[self.current_wallet_address]['encrypted_private_key'] = self.encrypted_private_key
400
-
401
- # If password provided and we have encrypted key, unlock
402
- if password and self.encrypted_private_key and self.current_wallet_address:
403
- return self.unlock_wallet(self.current_wallet_address, password)
404
-
405
- return True
406
- except Exception as e:
407
- print(f"Error loading wallet: {e}")
408
- return False
gtx/__init__.py DELETED
File without changes
gtx/bill_registry.py DELETED
@@ -1,122 +0,0 @@
1
- import os
2
- import json
3
- import sqlite3
4
- from typing import Dict, List, Optional
5
-
6
- class BillRegistry:
7
- """Manages bill database with verification links and metadata"""
8
-
9
- def __init__(self, db_path=None):
10
- self.db_path = db_path or os.path.join(os.path.expanduser("~"), ".luna_wallet", "bills.db")
11
- os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
12
- self._init_database()
13
-
14
- def _init_database(self):
15
- """Initialize bill database"""
16
- conn = sqlite3.connect(self.db_path)
17
- cursor = conn.cursor()
18
-
19
- cursor.execute('''
20
- CREATE TABLE IF NOT EXISTS bills (
21
- bill_serial TEXT PRIMARY KEY,
22
- denomination INTEGER,
23
- user_address TEXT,
24
- hash TEXT,
25
- mining_time REAL,
26
- difficulty INTEGER,
27
- luna_value REAL,
28
- timestamp REAL,
29
- verification_url TEXT,
30
- image_url TEXT,
31
- metadata TEXT,
32
- status TEXT DEFAULT 'active'
33
- )
34
- ''')
35
-
36
- conn.commit()
37
- conn.close()
38
-
39
- def register_bill(self, bill_info):
40
- """Register a new bill in the database"""
41
- conn = sqlite3.connect(self.db_path)
42
- cursor = conn.cursor()
43
-
44
- # Generate verification URL
45
- verification_url = f"https://bank.linglin.art/verify/{bill_info['hash']}"
46
- image_url = f"https://bank.linglin.art/bills/{bill_info['bill_serial']}.png"
47
-
48
- cursor.execute('''
49
- INSERT OR REPLACE INTO bills
50
- (bill_serial, denomination, user_address, hash, mining_time,
51
- difficulty, luna_value, timestamp, verification_url, image_url, metadata)
52
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
53
- ''', (
54
- bill_info['bill_serial'],
55
- bill_info['denomination'],
56
- bill_info['user_address'],
57
- bill_info['hash'],
58
- bill_info['mining_time'],
59
- bill_info['difficulty'],
60
- bill_info['luna_value'],
61
- bill_info['timestamp'],
62
- verification_url,
63
- image_url,
64
- json.dumps(bill_info.get('bill_data', {}))
65
- ))
66
-
67
- conn.commit()
68
- conn.close()
69
-
70
- def get_bill(self, bill_serial):
71
- """Retrieve bill information"""
72
- conn = sqlite3.connect(self.db_path)
73
- cursor = conn.cursor()
74
-
75
- cursor.execute('SELECT * FROM bills WHERE bill_serial = ?', (bill_serial,))
76
- result = cursor.fetchone()
77
- conn.close()
78
-
79
- if result:
80
- return {
81
- 'bill_serial': result[0],
82
- 'denomination': result[1],
83
- 'user_address': result[2],
84
- 'hash': result[3],
85
- 'mining_time': result[4],
86
- 'difficulty': result[5],
87
- 'luna_value': result[6],
88
- 'timestamp': result[7],
89
- 'verification_url': result[8],
90
- 'image_url': result[9],
91
- 'metadata': json.loads(result[10]) if result[10] else {},
92
- 'status': result[11]
93
- }
94
- return None
95
-
96
- def get_user_bills(self, user_address):
97
- """Get all bills for a user"""
98
- conn = sqlite3.connect(self.db_path)
99
- cursor = conn.cursor()
100
-
101
- cursor.execute('SELECT * FROM bills WHERE user_address = ? ORDER BY timestamp DESC', (user_address,))
102
- results = cursor.fetchall()
103
- conn.close()
104
-
105
- bills = []
106
- for result in results:
107
- bills.append({
108
- 'bill_serial': result[0],
109
- 'denomination': result[1],
110
- 'user_address': result[2],
111
- 'hash': result[3],
112
- 'mining_time': result[4],
113
- 'difficulty': result[5],
114
- 'luna_value': result[6],
115
- 'timestamp': result[7],
116
- 'verification_url': result[8],
117
- 'image_url': result[9],
118
- 'metadata': json.loads(result[10]) if result[10] else {},
119
- 'status': result[11]
120
- })
121
-
122
- return bills