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
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
|