lunalib 1.1.0__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.
@@ -0,0 +1,583 @@
1
+ # lunalib/transactions/transactions.py
2
+ import time
3
+ import hashlib
4
+ import json
5
+ from typing import Dict, Optional, Tuple, List
6
+ from ..core.mempool import MempoolManager
7
+
8
+ class TransactionSecurity:
9
+ """Transaction security validation and risk assessment"""
10
+
11
+ def validate_transaction(self, transaction: Dict) -> Tuple[bool, str]:
12
+ """Validate transaction structure"""
13
+ required_fields = ['type', 'from', 'to', 'amount', 'timestamp']
14
+ for field in required_fields:
15
+ if field not in transaction:
16
+ return False, f'Missing required field: {field}'
17
+
18
+ # Validate amount
19
+ if transaction['amount'] <= 0:
20
+ return False, 'Amount must be positive'
21
+
22
+ return True, 'Valid'
23
+
24
+ def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
25
+ """Enhanced security validation"""
26
+ required_fields = ['type', 'from', 'to', 'amount', 'timestamp', 'hash']
27
+ for field in required_fields:
28
+ if field not in transaction:
29
+ return False, f'Missing required field: {field}'
30
+
31
+ # Validate amount
32
+ if transaction['amount'] <= 0:
33
+ return False, 'Invalid amount'
34
+
35
+ # Validate transaction type
36
+ valid_types = ['transfer', 'stake', 'unstake', 'delegate', 'reward',
37
+ 'fee_distribution', 'gtx_genesis', 'validator_join',
38
+ 'validator_leave', 'governance_vote']
39
+ if transaction['type'] not in valid_types:
40
+ return False, f'Invalid transaction type: {transaction["type"]}'
41
+
42
+ return True, 'Secure'
43
+
44
+ def assess_risk(self, transaction: Dict) -> Tuple[str, str]:
45
+ """Assess transaction risk level"""
46
+ amount = transaction.get('amount', 0)
47
+ tx_type = transaction.get('type', 'transfer')
48
+
49
+ if tx_type in ['gtx_genesis', 'reward', 'fee_distribution']:
50
+ return 'very_low', 'System transaction'
51
+
52
+ if amount > 1000000:
53
+ return 'high', 'Very large transaction amount'
54
+ elif amount > 100000:
55
+ return 'high', 'Large transaction amount'
56
+ elif amount > 10000:
57
+ return 'medium', 'Medium transaction amount'
58
+ elif amount > 1000:
59
+ return 'low', 'Small transaction amount'
60
+ else:
61
+ return 'very_low', 'Normal transaction'
62
+
63
+ class KeyManager:
64
+ """Key management for transaction signing"""
65
+
66
+ def derive_public_key(self, private_key: str) -> str:
67
+ """Derive public key from private key"""
68
+ if not private_key:
69
+ return "unsigned_public_key"
70
+ return f"pub_{hashlib.sha256(private_key.encode()).hexdigest()[:32]}"
71
+
72
+ def sign_data(self, data: str, private_key: str) -> str:
73
+ """Sign data with private key"""
74
+ if not private_key:
75
+ return "unsigned_signature"
76
+ return hashlib.sha256(f"{data}{private_key}".encode()).hexdigest()
77
+
78
+ def verify_signature(self, data: str, signature: str, public_key: str) -> bool:
79
+ """Verify signature (simplified - in production use proper ECDSA)"""
80
+ if signature == "unsigned_signature" or public_key == "unsigned_public_key":
81
+ return True # Allow unsigned system transactions
82
+
83
+ # Simplified verification - in real implementation, use proper cryptographic verification
84
+ expected_signature = hashlib.sha256(f"{data}{public_key}".encode()).hexdigest()
85
+ return signature == expected_signature
86
+
87
+ class FeePoolManager:
88
+ """Decentralized fee pool management"""
89
+
90
+ def __init__(self):
91
+ self.fee_pool_address = self._generate_fee_pool_address()
92
+ self.pending_fees = 0.0
93
+ self.distribution_blocks = 100 # Distribute fees every 100 blocks
94
+ self.last_distribution_block = 0
95
+ self.collected_fees = [] # Track fee collection history
96
+
97
+ def _generate_fee_pool_address(self) -> str:
98
+ """Generate deterministic fee pool address"""
99
+ base_data = "LUNA_FEE_POOL_V2"
100
+ return hashlib.sha256(base_data.encode()).hexdigest()[:32]
101
+
102
+ def collect_fee(self, fee_amount: float, transaction_hash: str) -> bool:
103
+ """Collect fee into the pool"""
104
+ if fee_amount > 0:
105
+ self.pending_fees += fee_amount
106
+ self.collected_fees.append({
107
+ 'amount': fee_amount,
108
+ 'tx_hash': transaction_hash,
109
+ 'timestamp': time.time()
110
+ })
111
+ print(f"DEBUG: Collected fee {fee_amount} from transaction {transaction_hash}")
112
+ return True
113
+ return False
114
+
115
+ def should_distribute(self, current_block_height: int) -> bool:
116
+ """Check if it's time to distribute fees"""
117
+ return (current_block_height - self.last_distribution_block) >= self.distribution_blocks
118
+
119
+ def calculate_rewards(self, stakers: List[Dict], total_stake: float) -> List[Dict]:
120
+ """Calculate rewards for stakers based on their stake"""
121
+ if total_stake <= 0 or self.pending_fees <= 0:
122
+ return []
123
+
124
+ rewards = []
125
+ for staker in stakers:
126
+ stake_amount = staker.get('stake', 0)
127
+ if stake_amount > 0:
128
+ share = stake_amount / total_stake
129
+ reward = self.pending_fees * share
130
+ rewards.append({
131
+ 'address': staker['address'],
132
+ 'reward': reward,
133
+ 'stake_share': share,
134
+ 'stake_amount': stake_amount
135
+ })
136
+
137
+ return rewards
138
+
139
+ def create_distribution_transactions(self, current_block_height: int,
140
+ stakers: List[Dict], total_stake: float) -> List[Dict]:
141
+ """Create fee distribution transactions to stakers"""
142
+ if not self.should_distribute(current_block_height) or self.pending_fees <= 0:
143
+ return []
144
+
145
+ rewards = self.calculate_rewards(stakers, total_stake)
146
+ distribution_txs = []
147
+
148
+ total_distributed = 0
149
+ for reward_info in rewards:
150
+ if reward_info['reward'] > 0:
151
+ distribution_tx = {
152
+ "type": "fee_distribution",
153
+ "from": self.fee_pool_address,
154
+ "to": reward_info['address'],
155
+ "amount": reward_info['reward'],
156
+ "fee": 0.0,
157
+ "block_height": current_block_height,
158
+ "distribution_cycle": current_block_height // self.distribution_blocks,
159
+ "stake_share": reward_info['stake_share'],
160
+ "stake_amount": reward_info['stake_amount'],
161
+ "timestamp": time.time(),
162
+ "hash": self._generate_distribution_hash(reward_info['address'], reward_info['reward'], current_block_height)
163
+ }
164
+ distribution_txs.append(distribution_tx)
165
+ total_distributed += reward_info['reward']
166
+
167
+ # Reset pending fees after distribution
168
+ self.pending_fees = 0.0
169
+ self.last_distribution_block = current_block_height
170
+
171
+ print(f"DEBUG: Distributed {total_distributed} fees to {len(distribution_txs)} stakers")
172
+ return distribution_txs
173
+
174
+ def _generate_distribution_hash(self, address: str, amount: float, block_height: int) -> str:
175
+ """Generate unique hash for distribution transaction"""
176
+ data = f"fee_dist_{address}_{amount}_{block_height}_{time.time_ns()}"
177
+ return hashlib.sha256(data.encode()).hexdigest()
178
+
179
+ def get_fee_statistics(self) -> Dict:
180
+ """Get fee pool statistics"""
181
+ total_collected = sum(fee['amount'] for fee in self.collected_fees)
182
+ return {
183
+ 'pending_fees': self.pending_fees,
184
+ 'total_collected': total_collected,
185
+ 'distribution_count': len(self.collected_fees),
186
+ 'last_distribution_block': self.last_distribution_block,
187
+ 'pool_address': self.fee_pool_address
188
+ }
189
+
190
+ class FeeCalculator:
191
+ """Configurable fee calculation system"""
192
+
193
+ def __init__(self, fee_pool_manager: FeePoolManager):
194
+ self.fee_pool_manager = fee_pool_manager
195
+ self.fee_config = {
196
+ 'transfer': 0.00001, # Default transfer fee
197
+ 'stake': 0.0001, # Staking fee
198
+ 'unstake': 0.0001, # Unstaking fee
199
+ 'delegate': 0.00005, # Delegation fee
200
+ 'validator_join': 0.001, # Validator registration fee
201
+ 'validator_leave': 0.0001, # Validator exit fee
202
+ 'governance_vote': 0.00001, # Governance voting fee
203
+ 'gtx_genesis': 0.0, # No fee for GTX genesis
204
+ 'reward': 0.0, # No fee for rewards
205
+ 'fee_distribution': 0.0, # No fee for fee distributions
206
+ }
207
+
208
+ # Dynamic fee tiers based on transaction amount
209
+ self.amount_tiers = {
210
+ 'micro': (0, 1, 0.000001),
211
+ 'small': (1, 100, 0.00001),
212
+ 'medium': (100, 10000, 0.0001),
213
+ 'large': (10000, 100000, 0.001),
214
+ 'xlarge': (100000, float('inf'), 0.01)
215
+ }
216
+
217
+ def set_fee(self, transaction_type: str, fee_amount: float):
218
+ """Set custom fee for a transaction type"""
219
+ self.fee_config[transaction_type] = max(0.0, fee_amount)
220
+
221
+ def get_fee(self, transaction_type: str, amount: float = 0.0) -> float:
222
+ """Get fee for transaction type and amount"""
223
+ base_fee = self.fee_config.get(transaction_type, 0.00001)
224
+
225
+ # Apply amount-based fee scaling
226
+ for tier_name, (min_amt, max_amt, tier_fee) in self.amount_tiers.items():
227
+ if min_amt <= amount < max_amt:
228
+ return max(base_fee, tier_fee)
229
+
230
+ return base_fee
231
+
232
+ def calculate_network_fee(self, transaction_size: int, priority: str = 'normal') -> float:
233
+ """Calculate fee based on transaction size and priority"""
234
+ base_fee_per_byte = 0.0000001 # Base fee per byte
235
+
236
+ priority_multipliers = {
237
+ 'low': 0.5,
238
+ 'normal': 1.0,
239
+ 'high': 2.0,
240
+ 'urgent': 5.0
241
+ }
242
+
243
+ multiplier = priority_multipliers.get(priority, 1.0)
244
+ return transaction_size * base_fee_per_byte * multiplier
245
+
246
+ def process_transaction_fee(self, transaction: Dict) -> bool:
247
+ """Process and collect transaction fee"""
248
+ fee = transaction.get('fee', 0)
249
+ if fee > 0:
250
+ return self.fee_pool_manager.collect_fee(fee, transaction.get('hash', ''))
251
+ return True
252
+
253
+ class TransactionManager:
254
+ """Handles transaction creation, signing, validation, and broadcasting"""
255
+
256
+ def __init__(self, network_endpoints: List[str] = None):
257
+ self.security = TransactionSecurity()
258
+ self.key_manager = KeyManager()
259
+ self.fee_pool_manager = FeePoolManager()
260
+ self.fee_calculator = FeeCalculator(self.fee_pool_manager)
261
+ self.mempool_manager = MempoolManager(network_endpoints)
262
+
263
+ def create_transaction(self, from_address: str, to_address: str, amount: float,
264
+ private_key: Optional[str] = None, memo: str = "",
265
+ transaction_type: str = "transfer", fee_override: Optional[float] = None,
266
+ priority: str = 'normal') -> Dict:
267
+ """Create and sign a transaction with configurable fees"""
268
+
269
+ # Calculate fee
270
+ if fee_override is not None:
271
+ fee = max(0.0, fee_override)
272
+ else:
273
+ fee = self.fee_calculator.get_fee(transaction_type, amount)
274
+
275
+ transaction = {
276
+ "type": transaction_type,
277
+ "from": from_address,
278
+ "to": to_address,
279
+ "amount": float(amount),
280
+ "fee": fee,
281
+ "nonce": int(time.time() * 1000),
282
+ "timestamp": time.time(),
283
+ "memo": memo,
284
+ "priority": priority,
285
+ "version": "1.0"
286
+ }
287
+
288
+ # Only add cryptographic fields if private key is provided
289
+ if private_key:
290
+ transaction["public_key"] = self.key_manager.derive_public_key(private_key)
291
+ sign_data = self._get_signing_data(transaction)
292
+ signature = self.key_manager.sign_data(sign_data, private_key)
293
+ transaction["signature"] = signature
294
+ else:
295
+ # For unsigned transactions (like rewards or system transactions)
296
+ transaction["public_key"] = "unsigned"
297
+ transaction["signature"] = "unsigned"
298
+
299
+ transaction["hash"] = self._calculate_transaction_hash(transaction)
300
+
301
+ # Automatically collect fee
302
+ self.fee_calculator.process_transaction_fee(transaction)
303
+
304
+ return transaction
305
+
306
+ def send_transaction(self, transaction: Dict) -> Tuple[bool, str]:
307
+ """Send transaction to mempool for broadcasting"""
308
+ try:
309
+ # Validate transaction first
310
+ is_valid, message = self.validate_transaction(transaction)
311
+ if not is_valid:
312
+ return False, f"Validation failed: {message}"
313
+
314
+ # Add to mempool
315
+ success = self.mempool_manager.add_transaction(transaction)
316
+ if success:
317
+ return True, f"Transaction added to mempool: {transaction.get('hash')}"
318
+ else:
319
+ return False, "Failed to add transaction to mempool"
320
+
321
+ except Exception as e:
322
+ return False, f"Error sending transaction: {str(e)}"
323
+
324
+ # TRANSFER TRANSACTIONS
325
+ def create_transfer(self, from_address: str, to_address: str, amount: float,
326
+ private_key: str, memo: str = "", fee_override: Optional[float] = None) -> Dict:
327
+ """Create a transfer transaction"""
328
+ return self.create_transaction(
329
+ from_address=from_address,
330
+ to_address=to_address,
331
+ amount=amount,
332
+ private_key=private_key,
333
+ memo=memo,
334
+ transaction_type="transfer",
335
+ fee_override=fee_override
336
+ )
337
+
338
+ # STAKING TRANSACTIONS
339
+ def create_stake(self, from_address: str, amount: float, private_key: str) -> Dict:
340
+ """Create staking transaction"""
341
+ return self.create_transaction(
342
+ from_address=from_address,
343
+ to_address="staking_pool",
344
+ amount=amount,
345
+ private_key=private_key,
346
+ transaction_type="stake"
347
+ )
348
+
349
+ def create_unstake(self, from_address: str, amount: float, private_key: str) -> Dict:
350
+ """Create unstaking transaction"""
351
+ return self.create_transaction(
352
+ from_address="staking_pool",
353
+ to_address=from_address,
354
+ amount=amount,
355
+ private_key=private_key,
356
+ transaction_type="unstake"
357
+ )
358
+
359
+ def create_delegate(self, from_address: str, to_validator: str, amount: float,
360
+ private_key: str) -> Dict:
361
+ """Create delegation transaction"""
362
+ return self.create_transaction(
363
+ from_address=from_address,
364
+ to_address=to_validator,
365
+ amount=amount,
366
+ private_key=private_key,
367
+ transaction_type="delegate"
368
+ )
369
+
370
+ # VALIDATOR TRANSACTIONS
371
+ def create_validator_join(self, from_address: str, validator_info: Dict,
372
+ private_key: str) -> Dict:
373
+ """Create validator registration transaction"""
374
+ transaction = self.create_transaction(
375
+ from_address=from_address,
376
+ to_address="validator_registry",
377
+ amount=validator_info.get('stake', 0),
378
+ private_key=private_key,
379
+ transaction_type="validator_join"
380
+ )
381
+ # Add validator-specific info
382
+ transaction.update({
383
+ "validator_name": validator_info.get('name', ''),
384
+ "validator_url": validator_info.get('url', ''),
385
+ "commission_rate": validator_info.get('commission_rate', 0.0)
386
+ })
387
+ return transaction
388
+
389
+ def create_validator_leave(self, from_address: str, private_key: str) -> Dict:
390
+ """Create validator exit transaction"""
391
+ return self.create_transaction(
392
+ from_address=from_address,
393
+ to_address="validator_exit",
394
+ amount=0, # No amount for exit
395
+ private_key=private_key,
396
+ transaction_type="validator_leave"
397
+ )
398
+
399
+ # GOVERNANCE TRANSACTIONS
400
+ def create_governance_vote(self, from_address: str, proposal_id: str,
401
+ vote: str, private_key: str) -> Dict:
402
+ """Create governance vote transaction"""
403
+ transaction = self.create_transaction(
404
+ from_address=from_address,
405
+ to_address="governance",
406
+ amount=0, # No amount for voting
407
+ private_key=private_key,
408
+ transaction_type="governance_vote"
409
+ )
410
+ # Add governance-specific info
411
+ transaction.update({
412
+ "proposal_id": proposal_id,
413
+ "vote": vote, # 'yes', 'no', 'abstain'
414
+ "voting_power": 1.0 # Could be based on stake
415
+ })
416
+ return transaction
417
+
418
+ # SYSTEM TRANSACTIONS
419
+ def create_gtx_transaction(self, bill_info: Dict) -> Dict:
420
+ """Create GTX Genesis transaction from mined bill"""
421
+ return {
422
+ "type": "gtx_genesis",
423
+ "from": "mining",
424
+ "to": bill_info.get("owner_address", "unknown"),
425
+ "amount": bill_info.get("denomination", 0),
426
+ "fee": 0.0,
427
+ "timestamp": time.time(),
428
+ "bill_serial": bill_info.get("serial", ""),
429
+ "mining_difficulty": bill_info.get("difficulty", 0),
430
+ "hash": f"gtx_{hashlib.sha256(json.dumps(bill_info).encode()).hexdigest()[:16]}",
431
+ "public_key": "system",
432
+ "signature": "system"
433
+ }
434
+
435
+ def create_reward_transaction(self, to_address: str, amount: float,
436
+ block_height: int, reward_type: str = "block") -> Dict:
437
+ """Create reward transaction"""
438
+ transaction = {
439
+ "type": "reward",
440
+ "from": "network",
441
+ "to": to_address,
442
+ "amount": float(amount),
443
+ "fee": 0.0,
444
+ "block_height": block_height,
445
+ "reward_type": reward_type, # block, fee, staking
446
+ "timestamp": time.time(),
447
+ "hash": self._generate_reward_hash(to_address, amount, block_height, reward_type),
448
+ "public_key": "system",
449
+ "signature": "system"
450
+ }
451
+ return transaction
452
+
453
+ def create_fee_distribution(self, to_address: str, amount: float,
454
+ distribution_cycle: int, stake_share: float) -> Dict:
455
+ """Create fee distribution transaction"""
456
+ return {
457
+ "type": "fee_distribution",
458
+ "from": self.fee_pool_manager.fee_pool_address,
459
+ "to": to_address,
460
+ "amount": float(amount),
461
+ "fee": 0.0,
462
+ "distribution_cycle": distribution_cycle,
463
+ "stake_share": stake_share,
464
+ "timestamp": time.time(),
465
+ "hash": self.fee_pool_manager._generate_distribution_hash(to_address, amount, distribution_cycle),
466
+ "public_key": "system",
467
+ "signature": "system"
468
+ }
469
+
470
+ # FEE DISTRIBUTION
471
+ def distribute_fees(self, current_block_height: int, stakers: List[Dict],
472
+ total_stake: float) -> List[Dict]:
473
+ """Distribute collected fees to stakers"""
474
+ return self.fee_pool_manager.create_distribution_transactions(
475
+ current_block_height, stakers, total_stake
476
+ )
477
+
478
+ # VALIDATION METHODS
479
+ def validate_transaction(self, transaction: Dict) -> Tuple[bool, str]:
480
+ """Validate transaction using security module"""
481
+ return self.security.validate_transaction(transaction)
482
+
483
+ def validate_transaction_security(self, transaction: Dict) -> Tuple[bool, str]:
484
+ """Validate transaction security"""
485
+ return self.security.validate_transaction_security(transaction)
486
+
487
+ def assess_transaction_risk(self, transaction: Dict) -> Tuple[str, str]:
488
+ """Assess transaction risk level"""
489
+ return self.security.assess_risk(transaction)
490
+
491
+ def verify_transaction_signature(self, transaction: Dict) -> bool:
492
+ """Verify transaction signature"""
493
+ try:
494
+ sign_data = self._get_signing_data(transaction)
495
+ signature = transaction.get("signature", "")
496
+ public_key = transaction.get("public_key", "")
497
+ return self.key_manager.verify_signature(sign_data, signature, public_key)
498
+ except:
499
+ return False
500
+
501
+ # MEMPOOL MANAGEMENT
502
+ def get_pending_transactions(self, address: str = None) -> List[Dict]:
503
+ """Get pending transactions from mempool"""
504
+ return self.mempool_manager.get_pending_transactions(address)
505
+
506
+ def is_transaction_pending(self, tx_hash: str) -> bool:
507
+ """Check if transaction is pending in mempool"""
508
+ return self.mempool_manager.is_transaction_pending(tx_hash)
509
+
510
+ def is_transaction_confirmed(self, tx_hash: str) -> bool:
511
+ """Check if transaction has been confirmed"""
512
+ return self.mempool_manager.is_transaction_confirmed(tx_hash)
513
+
514
+ # FEE MANAGEMENT
515
+ def set_transaction_fee(self, transaction_type: str, fee_amount: float):
516
+ """Set custom fee for transaction type"""
517
+ self.fee_calculator.set_fee(transaction_type, fee_amount)
518
+
519
+ def calculate_network_fee(self, transaction_size: int, priority: str = 'normal') -> float:
520
+ """Calculate network fee based on size and priority"""
521
+ return self.fee_calculator.calculate_network_fee(transaction_size, priority)
522
+
523
+ def get_fee_pool_balance(self) -> float:
524
+ """Get current fee pool balance"""
525
+ return self.fee_pool_manager.pending_fees
526
+
527
+ def get_fee_pool_address(self) -> str:
528
+ """Get fee pool address"""
529
+ return self.fee_pool_manager.fee_pool_address
530
+
531
+ def get_fee_statistics(self) -> Dict:
532
+ """Get fee pool statistics"""
533
+ return self.fee_pool_manager.get_fee_statistics()
534
+
535
+ # UTILITY METHODS
536
+ def _get_signing_data(self, transaction: Dict) -> str:
537
+ """Create data string for signing"""
538
+ parts = [
539
+ transaction["type"],
540
+ transaction["from"],
541
+ transaction["to"],
542
+ str(transaction["amount"]),
543
+ str(transaction.get("nonce", 0)),
544
+ str(transaction["timestamp"]),
545
+ transaction.get("memo", ""),
546
+ str(transaction.get("fee", 0)),
547
+ transaction.get("version", "1.0")
548
+ ]
549
+ return "|".join(parts)
550
+
551
+ def _calculate_transaction_hash(self, transaction: Dict) -> str:
552
+ """Calculate transaction hash"""
553
+ # Create a copy without signature for consistent hashing
554
+ tx_copy = transaction.copy()
555
+ tx_copy.pop("signature", None)
556
+ tx_copy.pop("hash", None)
557
+ data_string = json.dumps(tx_copy, sort_keys=True)
558
+ return hashlib.sha256(data_string.encode()).hexdigest()
559
+
560
+ def _generate_reward_hash(self, to_address: str, amount: float,
561
+ block_height: int, reward_type: str) -> str:
562
+ """Generate unique hash for reward transaction"""
563
+ data = f"reward_{reward_type}_{to_address}_{amount}_{block_height}_{time.time_ns()}"
564
+ return hashlib.sha256(data.encode()).hexdigest()
565
+
566
+ def stop(self):
567
+ """Stop the transaction manager"""
568
+ self.mempool_manager.stop()
569
+
570
+ # Additional validator class for backward compatibility
571
+ class TransactionValidator:
572
+ """Transaction validator for risk assessment and validation"""
573
+
574
+ def __init__(self):
575
+ self.security = TransactionSecurity()
576
+
577
+ def assess_risk(self, transaction: Dict) -> Tuple[str, str]:
578
+ """Assess transaction risk level"""
579
+ return self.security.assess_risk(transaction)
580
+
581
+ def validate(self, transaction: Dict) -> Tuple[bool, str]:
582
+ """Validate transaction"""
583
+ return self.security.validate_transaction(transaction)
@@ -0,0 +1,71 @@
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:])