lunalib 1.5.0__py3-none-any.whl → 1.5.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.
@@ -1,424 +0,0 @@
1
- import time
2
- import hashlib
3
- import json
4
- from typing import Dict, Optional, Tuple, List
5
-
6
- class TransactionSecurity:
7
- """Transaction security validation and risk assessment"""
8
-
9
- def validate_transaction(self, transaction: Dict) -> Tuple[bool, str]:
10
- """Validate transaction structure"""
11
- required_fields = ['from', 'to', 'amount', 'timestamp']
12
- for field in required_fields:
13
- if field not in transaction:
14
- return False, f'Missing required field: {field}'
15
-
16
- # Validate amount
17
- if transaction['amount'] <= 0:
18
- return False, 'Amount must be positive'
19
-
20
- return True, 'Valid'
21
-
22
- def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
23
- """Enhanced security validation"""
24
- required_fields = ['from', 'to', 'amount', 'timestamp', 'type']
25
- for field in required_fields:
26
- if field not in transaction:
27
- return False, f'Missing required field: {field}'
28
-
29
- # Validate amount
30
- if transaction['amount'] <= 0:
31
- return False, 'Invalid amount'
32
-
33
- return True, 'Secure'
34
-
35
- def assess_risk(self, transaction: Dict) -> Tuple[str, str]:
36
- """Assess transaction risk level"""
37
- amount = transaction.get('amount', 0)
38
-
39
- if amount > 100000:
40
- return 'high', 'Large transaction amount'
41
- elif amount > 10000:
42
- return 'medium', 'Medium transaction amount'
43
- else:
44
- return 'low', 'Normal transaction'
45
-
46
- class KeyManager:
47
- """Key management for transaction signing"""
48
-
49
- def derive_public_key(self, private_key: str) -> str:
50
- """Derive public key from private key"""
51
- if not private_key:
52
- return "default_public_key"
53
- return f"pub_{private_key[-16:]}"
54
-
55
- def sign_data(self, data: str, private_key: str) -> str:
56
- """Sign data with private key"""
57
- if not private_key:
58
- return "default_signature"
59
- return hashlib.sha256(f"{data}{private_key}".encode()).hexdigest()
60
-
61
- class FeePoolManager:
62
- """Decentralized fee pool management"""
63
-
64
- def __init__(self):
65
- self.fee_pool_address = self._generate_fee_pool_address()
66
- self.pending_fees = 0.0
67
- self.distribution_blocks = 100 # Distribute fees every 100 blocks
68
- self.last_distribution_block = 0
69
-
70
- def _generate_fee_pool_address(self) -> str:
71
- """Generate deterministic fee pool address"""
72
- base_data = "LUNA_FEE_POOL_V1"
73
- return hashlib.sha256(base_data.encode()).hexdigest()[:32]
74
-
75
- def collect_fee(self, fee_amount: float, transaction_hash: str) -> bool:
76
- """Collect fee into the pool"""
77
- if fee_amount > 0:
78
- self.pending_fees += fee_amount
79
- return True
80
- return False
81
-
82
- def should_distribute(self, current_block_height: int) -> bool:
83
- """Check if it's time to distribute fees"""
84
- return (current_block_height - self.last_distribution_block) >= self.distribution_blocks
85
-
86
- def calculate_rewards(self, stakers: List[Dict], total_stake: float) -> List[Dict]:
87
- """Calculate rewards for stakers based on their stake"""
88
- if total_stake <= 0 or self.pending_fees <= 0:
89
- return []
90
-
91
- rewards = []
92
- for staker in stakers:
93
- stake_amount = staker.get('stake', 0)
94
- if stake_amount > 0:
95
- share = stake_amount / total_stake
96
- reward = self.pending_fees * share
97
- rewards.append({
98
- 'address': staker['address'],
99
- 'reward': reward,
100
- 'stake_share': share
101
- })
102
-
103
- return rewards
104
-
105
- def create_distribution_transactions(self, current_block_height: int,
106
- stakers: List[Dict], total_stake: float) -> List[Dict]:
107
- """Create fee distribution transactions to stakers"""
108
- if not self.should_distribute(current_block_height) or self.pending_fees <= 0:
109
- return []
110
-
111
- rewards = self.calculate_rewards(stakers, total_stake)
112
- distribution_txs = []
113
-
114
- for reward_info in rewards:
115
- distribution_tx = {
116
- "type": "fee_distribution",
117
- "from": self.fee_pool_address,
118
- "to": reward_info['address'],
119
- "amount": reward_info['reward'],
120
- "fee": 0.0,
121
- "block_height": current_block_height,
122
- "distribution_cycle": current_block_height // self.distribution_blocks,
123
- "stake_share": reward_info['stake_share'],
124
- "timestamp": time.time(),
125
- "hash": self._generate_distribution_hash(reward_info['address'], reward_info['reward'], current_block_height)
126
- }
127
- distribution_txs.append(distribution_tx)
128
-
129
- # Reset pending fees after distribution
130
- self.pending_fees = 0.0
131
- self.last_distribution_block = current_block_height
132
-
133
- return distribution_txs
134
-
135
- def _generate_distribution_hash(self, address: str, amount: float, block_height: int) -> str:
136
- """Generate unique hash for distribution transaction"""
137
- data = f"fee_dist_{address}_{amount}_{block_height}_{time.time()}"
138
- return hashlib.sha256(data.encode()).hexdigest()
139
-
140
- class FeeCalculator:
141
- """Configurable fee calculation system"""
142
-
143
- def __init__(self, fee_pool_manager: FeePoolManager):
144
- self.fee_pool_manager = fee_pool_manager
145
- self.fee_config = {
146
- 'transfer': 0.00001, # Default transfer fee
147
- 'gtx_genesis': 0.0, # No fee for GTX genesis
148
- 'reward': 0.0, # No fee for rewards
149
- 'stake': 0.0001, # Staking fee
150
- 'unstake': 0.0001, # Unstaking fee
151
- 'delegate': 0.00005, # Delegation fee
152
- 'fee_distribution': 0.0, # No fee for fee distributions
153
- }
154
-
155
- # Dynamic fee tiers based on transaction amount
156
- self.amount_tiers = {
157
- 'micro': (0, 1, 0.000001),
158
- 'small': (1, 100, 0.00001),
159
- 'medium': (100, 10000, 0.0001),
160
- 'large': (10000, 100000, 0.001),
161
- 'xlarge': (100000, float('inf'), 0.01)
162
- }
163
-
164
- def set_fee(self, transaction_type: str, fee_amount: float):
165
- """Set custom fee for a transaction type"""
166
- self.fee_config[transaction_type] = max(0.0, fee_amount)
167
-
168
- def get_fee(self, transaction_type: str, amount: float = 0.0) -> float:
169
- """Get fee for transaction type and amount"""
170
- base_fee = self.fee_config.get(transaction_type, 0.00001)
171
-
172
- # Apply amount-based fee scaling
173
- for tier_name, (min_amt, max_amt, tier_fee) in self.amount_tiers.items():
174
- if min_amt <= amount < max_amt:
175
- return max(base_fee, tier_fee)
176
-
177
- return base_fee
178
-
179
- def calculate_network_fee(self, transaction_size: int, priority: str = 'normal') -> float:
180
- """Calculate fee based on transaction size and priority"""
181
- base_fee_per_byte = 0.0000001 # Base fee per byte
182
-
183
- priority_multipliers = {
184
- 'low': 0.5,
185
- 'normal': 1.0,
186
- 'high': 2.0,
187
- 'urgent': 5.0
188
- }
189
-
190
- multiplier = priority_multipliers.get(priority, 1.0)
191
- return transaction_size * base_fee_per_byte * multiplier
192
-
193
- def process_transaction_fee(self, transaction: Dict) -> bool:
194
- """Process and collect transaction fee"""
195
- fee = transaction.get('fee', 0)
196
- if fee > 0:
197
- return self.fee_pool_manager.collect_fee(fee, transaction.get('hash', ''))
198
- return True
199
-
200
- class TransactionManager:
201
- """Handles transaction creation, signing, and validation"""
202
-
203
- def __init__(self):
204
- self.security = TransactionSecurity()
205
- self.key_manager = KeyManager()
206
- self.fee_pool_manager = FeePoolManager()
207
- self.fee_calculator = FeeCalculator(self.fee_pool_manager)
208
- self.pending_by_address = {} # Track pending transactions by address
209
-
210
- def create_transaction(self, from_address: str, to_address: str, amount: float,
211
- private_key: Optional[str] = None, memo: str = "",
212
- transaction_type: str = "transfer", fee_override: Optional[float] = None,
213
- priority: str = 'normal') -> Dict:
214
- """Create and sign a transaction with configurable fees"""
215
-
216
- # Calculate fee
217
- if fee_override is not None:
218
- fee = max(0.0, fee_override)
219
- else:
220
- fee = self.fee_calculator.get_fee(transaction_type, amount)
221
-
222
- transaction = {
223
- "type": transaction_type,
224
- "from": from_address,
225
- "to": to_address,
226
- "amount": float(amount),
227
- "fee": fee,
228
- "nonce": int(time.time() * 1000),
229
- "timestamp": time.time(),
230
- "memo": memo,
231
- "priority": priority,
232
- }
233
-
234
- # Only add cryptographic fields if private key is provided
235
- if private_key:
236
- transaction["public_key"] = self.key_manager.derive_public_key(private_key)
237
- sign_data = self._get_signing_data(transaction)
238
- signature = self.key_manager.sign_data(sign_data, private_key)
239
- transaction["signature"] = signature
240
- else:
241
- # For unsigned transactions (like rewards or test transactions)
242
- transaction["public_key"] = "unsigned"
243
- transaction["signature"] = "unsigned"
244
-
245
- transaction["hash"] = self._calculate_transaction_hash(transaction)
246
-
247
- # Automatically collect fee
248
- self.fee_calculator.process_transaction_fee(transaction)
249
-
250
- return transaction
251
-
252
- def distribute_fees(self, current_block_height: int, stakers: List[Dict], total_stake: float) -> List[Dict]:
253
- """Distribute collected fees to stakers"""
254
- return self.fee_pool_manager.create_distribution_transactions(
255
- current_block_height, stakers, total_stake
256
- )
257
-
258
- def get_fee_pool_balance(self) -> float:
259
- """Get current fee pool balance"""
260
- return self.fee_pool_manager.pending_fees
261
-
262
- def get_fee_pool_address(self) -> str:
263
- """Get fee pool address"""
264
- return self.fee_pool_manager.fee_pool_address
265
-
266
- def create_gtx_transaction(self, bill_info: Dict) -> Dict:
267
- """Create GTX Genesis transaction from mined bill"""
268
- # Ensure we return a proper transaction structure
269
- if "transaction_data" in bill_info:
270
- return bill_info["transaction_data"]
271
- else:
272
- # Fallback: create basic transaction from bill info
273
- return {
274
- "type": "gtx_genesis",
275
- "from": "mining",
276
- "to": bill_info.get("owner_address", "unknown"),
277
- "amount": bill_info.get("denomination", 0),
278
- "fee": 0.0, # No fee for GTX genesis
279
- "timestamp": time.time(),
280
- "hash": f"gtx_{hashlib.sha256(json.dumps(bill_info).encode()).hexdigest()[:16]}"
281
- }
282
-
283
- def create_reward_transaction(self, to_address: str, amount: float, block_height: int) -> Dict:
284
- """Create block reward transaction"""
285
- transaction = {
286
- "type": "reward",
287
- "from": "network",
288
- "to": to_address,
289
- "amount": float(amount),
290
- "fee": 0.0, # No fee for rewards
291
- "block_height": block_height,
292
- "timestamp": time.time(),
293
- "hash": self._generate_reward_hash(to_address, amount, block_height)
294
- }
295
-
296
- return transaction
297
-
298
- def create_stake_transaction(self, from_address: str, amount: float,
299
- private_key: Optional[str] = None) -> Dict:
300
- """Create staking transaction"""
301
- return self.create_transaction(
302
- from_address=from_address,
303
- to_address="staking_pool",
304
- amount=amount,
305
- private_key=private_key,
306
- transaction_type="stake"
307
- )
308
-
309
- def create_unstake_transaction(self, from_address: str, amount: float,
310
- private_key: Optional[str] = None) -> Dict:
311
- """Create unstaking transaction"""
312
- return self.create_transaction(
313
- from_address="staking_pool",
314
- to_address=from_address,
315
- amount=amount,
316
- private_key=private_key,
317
- transaction_type="unstake"
318
- )
319
-
320
- def validate_transaction(self, transaction: Dict) -> Tuple[bool, str]:
321
- """Validate transaction using security module"""
322
- return self.security.validate_transaction(transaction)
323
-
324
- def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
325
- """Validate transaction security"""
326
- return self.security.validate_transaction_security(transaction)
327
-
328
- def assess_transaction_risk(self, transaction: Dict) -> Tuple[str, str]:
329
- """Assess transaction risk level"""
330
- return self.security.assess_risk(transaction)
331
-
332
- def set_transaction_fee(self, transaction_type: str, fee_amount: float):
333
- """Set custom fee for transaction type"""
334
- self.fee_calculator.set_fee(transaction_type, fee_amount)
335
-
336
- def calculate_network_fee(self, transaction_size: int, priority: str = 'normal') -> float:
337
- """Calculate network fee based on size and priority"""
338
- return self.fee_calculator.calculate_network_fee(transaction_size, priority)
339
-
340
- def _get_signing_data(self, transaction: Dict) -> str:
341
- """Create data string for signing"""
342
- parts = [
343
- transaction["from"],
344
- transaction["to"],
345
- str(transaction["amount"]),
346
- str(transaction.get("nonce", 0)),
347
- str(transaction["timestamp"]),
348
- transaction.get("memo", ""),
349
- str(transaction.get("fee", 0)),
350
- transaction.get("type", "transfer")
351
- ]
352
- return "".join(parts)
353
-
354
- def _calculate_transaction_hash(self, transaction: Dict) -> str:
355
- """Calculate transaction hash"""
356
- # Create a copy without signature for consistent hashing
357
- tx_copy = transaction.copy()
358
- tx_copy.pop("signature", None)
359
- data_string = json.dumps(tx_copy, sort_keys=True)
360
- return hashlib.sha256(data_string.encode()).hexdigest() # FIXED: data_string instead of data
361
-
362
- def _generate_reward_hash(self, to_address: str, amount: float, block_height: int) -> str:
363
- """Generate unique hash for reward transaction"""
364
- data = f"reward_{to_address}_{amount}_{block_height}_{time.time()}"
365
- return hashlib.sha256(data.encode()).hexdigest()
366
-
367
- def validate_against_available_balance(self, from_address: str, amount: float,
368
- available_balance: float) -> Tuple[bool, str]:
369
- """Validate that transaction amount doesn't exceed available balance"""
370
- pending_amount = self.pending_by_address.get(from_address, 0.0)
371
- total_pending = pending_amount + amount
372
-
373
- if total_pending > available_balance:
374
- shortage = total_pending - available_balance
375
- return False, f'Insufficient available balance. Need {shortage} more (accounting for {pending_amount} in pending transactions)'
376
-
377
- return True, 'Sufficient balance'
378
-
379
- def add_pending_transaction(self, from_address: str, tx_hash: str, amount: float) -> bool:
380
- """Track a pending transaction (added to mempool)"""
381
- if from_address not in self.pending_by_address:
382
- self.pending_by_address[from_address] = 0.0
383
-
384
- self.pending_by_address[from_address] += float(amount)
385
- return True
386
-
387
- def confirm_transaction(self, from_address: str, amount: float) -> bool:
388
- """Confirm a transaction (moved from mempool to blockchain)"""
389
- if from_address in self.pending_by_address:
390
- pending = self.pending_by_address[from_address]
391
- new_pending = max(0.0, pending - float(amount))
392
-
393
- if new_pending == 0:
394
- del self.pending_by_address[from_address]
395
- else:
396
- self.pending_by_address[from_address] = new_pending
397
-
398
- return True
399
- return False
400
-
401
- def get_pending_amount(self, from_address: str) -> float:
402
- """Get total pending transaction amount for address"""
403
- return self.pending_by_address.get(from_address, 0.0)
404
-
405
- def clear_pending_for_address(self, from_address: str) -> bool:
406
- """Clear all pending transactions for address (e.g., if they failed)"""
407
- if from_address in self.pending_by_address:
408
- del self.pending_by_address[from_address]
409
- return True
410
-
411
- # Additional validator class for backward compatibility
412
- class TransactionValidator:
413
- """Transaction validator for risk assessment and validation"""
414
-
415
- def __init__(self):
416
- self.security = TransactionSecurity()
417
-
418
- def assess_risk(self, transaction: Dict) -> Tuple[str, str]:
419
- """Assess transaction risk level"""
420
- return self.security.assess_risk(transaction)
421
-
422
- def validate(self, transaction: Dict) -> Tuple[bool, str]:
423
- """Validate transaction"""
424
- return self.security.validate_transaction(transaction)
transactions/validator.py DELETED
@@ -1,71 +0,0 @@
1
- import time
2
- from typing import Dict, Tuple, List
3
- from .security import TransactionSecurity
4
-
5
- class TransactionValidator:
6
- """Network-level transaction validation"""
7
-
8
- def __init__(self):
9
- self.security = TransactionSecurity()
10
- self.recent_transactions = set()
11
- self.max_recent_size = 10000
12
-
13
- def validate_transaction(self, transaction: Dict) -> Tuple[bool, str]:
14
- """Main transaction validation entry point"""
15
-
16
- # Check for duplicate transaction
17
- tx_hash = transaction.get("hash")
18
- if tx_hash in self.recent_transactions:
19
- return False, "Duplicate transaction detected"
20
-
21
- # Security validation
22
- is_valid, message = self.security.validate_transaction_security(transaction)
23
- if not is_valid:
24
- return False, message
25
-
26
- # Add to recent transactions
27
- self._add_to_recent(tx_hash)
28
-
29
- return True, message
30
-
31
- def validate_transaction_batch(self, transactions: List[Dict]) -> Tuple[bool, List[str]]:
32
- """Validate multiple transactions"""
33
- results = []
34
- all_valid = True
35
-
36
- for tx in transactions:
37
- is_valid, message = self.validate_transaction(tx)
38
- results.append(message)
39
- if not is_valid:
40
- all_valid = False
41
-
42
- return all_valid, results
43
-
44
- def verify_transaction_inclusion(self, transaction_hash: str, block_height: int) -> bool:
45
- """Verify transaction is included in blockchain"""
46
- # This would typically query the blockchain
47
- # For now, we'll assume if it passed validation it's included
48
- return transaction_hash in self.recent_transactions
49
-
50
- def get_transaction_risk_level(self, transaction: Dict) -> str:
51
- """Assess transaction risk level"""
52
- amount = transaction.get("amount", 0)
53
- security_score = self.security.calculate_security_score(transaction)
54
-
55
- if amount > 1000000 and security_score < 80:
56
- return "HIGH"
57
- elif amount > 10000 and security_score < 60:
58
- return "MEDIUM"
59
- elif security_score < 40:
60
- return "LOW"
61
- else:
62
- return "VERY_LOW"
63
-
64
- def _add_to_recent(self, tx_hash: str):
65
- """Add transaction to recent set with size management"""
66
- self.recent_transactions.add(tx_hash)
67
-
68
- # Manage set size
69
- if len(self.recent_transactions) > self.max_recent_size:
70
- # Remove oldest entries (this is simplified)
71
- self.recent_transactions = set(list(self.recent_transactions)[-self.max_recent_size:])