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.
- lunalib/__init__.py +19 -0
- lunalib/cli.py +18 -0
- lunalib/core/__init__.py +0 -0
- lunalib/core/blockchain.py +451 -0
- lunalib/core/crypto.py +32 -0
- lunalib/core/mempool.py +340 -0
- lunalib/core/wallet.py +635 -0
- lunalib/gtx/__init__.py +0 -0
- lunalib/gtx/bill_registry.py +122 -0
- lunalib/gtx/digital_bill.py +273 -0
- lunalib/gtx/genesis.py +349 -0
- lunalib/luna_lib.py +77 -0
- lunalib/mining/__init__.py +0 -0
- lunalib/mining/cuda_manager.py +137 -0
- lunalib/mining/difficulty.py +106 -0
- lunalib/mining/miner.py +107 -0
- lunalib/requirements.txt +44 -0
- lunalib/storage/__init__.py +0 -0
- lunalib/storage/cache.py +148 -0
- lunalib/storage/database.py +222 -0
- lunalib/storage/encryption.py +105 -0
- lunalib/transactions/__init__.py +0 -0
- lunalib/transactions/security.py +172 -0
- lunalib/transactions/transactions.py +583 -0
- lunalib/transactions/validator.py +71 -0
- lunalib-1.1.0.dist-info/METADATA +283 -0
- lunalib-1.1.0.dist-info/RECORD +30 -0
- lunalib-1.1.0.dist-info/WHEEL +5 -0
- lunalib-1.1.0.dist-info/entry_points.txt +2 -0
- lunalib-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -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:])
|