Remove outdated GPU marketplace endpoint and fix staking service logic
- Remove duplicate `/marketplace/gpu/{gpu_id}` endpoint from marketplace_gpu.py
- Remove marketplace_gpu router inclusion from main.py (already included elsewhere)
- Fix staking service staker_count logic to check existing stakes before increment/decrement
- Add minimum stake amount validation (100 AITBC)
- Add proper error handling for stake not found cases
- Fix staking pool update to commit and refresh after modifications
- Update CLI send_transaction to use chain
This commit is contained in:
426
scripts/testing/generate_staking_test_data.py
Executable file
426
scripts/testing/generate_staking_test_data.py
Executable file
@@ -0,0 +1,426 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Staking Test Data Generator
|
||||
Generates realistic test data scenarios for staking tests
|
||||
"""
|
||||
|
||||
import json
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Any
|
||||
|
||||
# Performance tiers and their properties
|
||||
PERFORMANCE_TIERS = {
|
||||
"BRONZE": {
|
||||
"multiplier": 1.0,
|
||||
"min_accuracy": 70.0,
|
||||
"max_accuracy": 79.9,
|
||||
"min_submissions": 5,
|
||||
"success_rate_range": (0.70, 0.80)
|
||||
},
|
||||
"SILVER": {
|
||||
"multiplier": 1.25,
|
||||
"min_accuracy": 80.0,
|
||||
"max_accuracy": 89.9,
|
||||
"min_submissions": 10,
|
||||
"success_rate_range": (0.80, 0.90)
|
||||
},
|
||||
"GOLD": {
|
||||
"multiplier": 1.5,
|
||||
"min_accuracy": 90.0,
|
||||
"max_accuracy": 94.9,
|
||||
"min_submissions": 20,
|
||||
"success_rate_range": (0.90, 0.95)
|
||||
},
|
||||
"PLATINUM": {
|
||||
"multiplier": 2.0,
|
||||
"min_accuracy": 95.0,
|
||||
"max_accuracy": 97.9,
|
||||
"min_submissions": 50,
|
||||
"success_rate_range": (0.95, 0.98)
|
||||
},
|
||||
"DIAMOND": {
|
||||
"multiplier": 3.0,
|
||||
"min_accuracy": 98.0,
|
||||
"max_accuracy": 100.0,
|
||||
"min_submissions": 100,
|
||||
"success_rate_range": (0.98, 1.00)
|
||||
}
|
||||
}
|
||||
|
||||
# Lock period multipliers
|
||||
LOCK_PERIOD_MULTIPLIERS = {
|
||||
"short": {"days": 7, "multiplier": 1.0},
|
||||
"medium": {"days": 30, "multiplier": 1.1},
|
||||
"long": {"days": 90, "multiplier": 1.5},
|
||||
"extended": {"days": 365, "multiplier": 2.0}
|
||||
}
|
||||
|
||||
# Stake amount ranges
|
||||
STAKE_AMOUNTS = {
|
||||
"minimum": 100.0,
|
||||
"small": 1000.0,
|
||||
"medium": 10000.0,
|
||||
"large": 50000.0,
|
||||
"maximum": 100000.0
|
||||
}
|
||||
|
||||
|
||||
def generate_agent_wallet() -> str:
|
||||
"""Generate a random agent wallet address"""
|
||||
return f"0x{''.join(random.choices('0123456789abcdef', k=40))}"
|
||||
|
||||
|
||||
def generate_staker_address() -> str:
|
||||
"""Generate a random staker address"""
|
||||
return f"ait1{''.join(random.choices('0123456789abcdef', k=40))}"
|
||||
|
||||
|
||||
def generate_agent_metrics(tier: str = "GOLD") -> Dict[str, Any]:
|
||||
"""Generate realistic agent metrics for a given tier"""
|
||||
tier_config = PERFORMANCE_TIERS[tier]
|
||||
|
||||
total_submissions = random.randint(tier_config["min_submissions"], tier_config["min_submissions"] * 3)
|
||||
success_rate = random.uniform(*tier_config["success_rate_range"])
|
||||
successful_submissions = int(total_submissions * success_rate)
|
||||
|
||||
return {
|
||||
"agent_wallet": generate_agent_wallet(),
|
||||
"total_submissions": total_submissions,
|
||||
"successful_submissions": successful_submissions,
|
||||
"average_accuracy": random.uniform(tier_config["min_accuracy"], tier_config["max_accuracy"]),
|
||||
"current_tier": tier,
|
||||
"tier_score": random.uniform(60.0, 95.0),
|
||||
"total_staked": 0.0,
|
||||
"staker_count": 0,
|
||||
"total_rewards_distributed": 0.0,
|
||||
"last_update_time": datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
|
||||
def calculate_expected_apy(tier: str, lock_period_days: int, base_apy: float = 5.0) -> float:
|
||||
"""Calculate expected APY based on tier and lock period"""
|
||||
tier_multiplier = PERFORMANCE_TIERS[tier]["multiplier"]
|
||||
|
||||
if lock_period_days >= 365:
|
||||
lock_multiplier = 2.0
|
||||
elif lock_period_days >= 90:
|
||||
lock_multiplier = 1.5
|
||||
elif lock_period_days >= 30:
|
||||
lock_multiplier = 1.1
|
||||
else:
|
||||
lock_multiplier = 1.0
|
||||
|
||||
apy = base_apy * tier_multiplier * lock_multiplier
|
||||
return min(apy, 20.0) # Cap at 20%
|
||||
|
||||
|
||||
def generate_stake_data(
|
||||
agent_wallet: str,
|
||||
staker_address: str,
|
||||
tier: str = "GOLD",
|
||||
amount_category: str = "medium",
|
||||
lock_period_category: str = "medium",
|
||||
auto_compound: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
"""Generate realistic stake data"""
|
||||
amount = STAKE_AMOUNTS[amount_category]
|
||||
lock_period_days = LOCK_PERIOD_MULTIPLIERS[lock_period_category]["days"]
|
||||
expected_apy = calculate_expected_apy(tier, lock_period_days)
|
||||
|
||||
start_time = datetime.utcnow()
|
||||
end_time = start_time + timedelta(days=lock_period_days)
|
||||
|
||||
return {
|
||||
"stake_id": f"stake_{random.randint(100000, 999999)}",
|
||||
"staker_address": staker_address,
|
||||
"agent_wallet": agent_wallet,
|
||||
"amount": amount,
|
||||
"lock_period": lock_period_days,
|
||||
"start_time": start_time.isoformat(),
|
||||
"end_time": end_time.isoformat(),
|
||||
"status": "ACTIVE",
|
||||
"accumulated_rewards": 0.0,
|
||||
"last_reward_time": start_time.isoformat(),
|
||||
"current_apy": expected_apy,
|
||||
"agent_tier": tier,
|
||||
"performance_multiplier": PERFORMANCE_TIERS[tier]["multiplier"],
|
||||
"auto_compound": auto_compound
|
||||
}
|
||||
|
||||
|
||||
def generate_staking_pool(agent_wallet: str, total_staked: float) -> Dict[str, Any]:
|
||||
"""Generate staking pool data"""
|
||||
return {
|
||||
"agent_wallet": agent_wallet,
|
||||
"total_staked": total_staked,
|
||||
"total_rewards": 0.0,
|
||||
"pool_apy": 5.0,
|
||||
"staker_count": 0,
|
||||
"active_stakers": [],
|
||||
"last_distribution_time": datetime.utcnow().isoformat(),
|
||||
"distribution_frequency": 1
|
||||
}
|
||||
|
||||
|
||||
def generate_test_scenario(num_agents: int = 5, num_stakes_per_agent: int = 3) -> Dict[str, Any]:
|
||||
"""Generate a complete test scenario with multiple agents and stakes"""
|
||||
scenario = {
|
||||
"scenario_id": f"scenario_{random.randint(1000, 9999)}",
|
||||
"generated_at": datetime.utcnow().isoformat(),
|
||||
"agents": [],
|
||||
"stakes": [],
|
||||
"pools": []
|
||||
}
|
||||
|
||||
# Generate agents with different tiers
|
||||
tier_distribution = ["BRONZE", "SILVER", "GOLD", "GOLD", "PLATINUM"]
|
||||
for i in range(num_agents):
|
||||
tier = tier_distribution[i % len(tier_distribution)]
|
||||
agent_metrics = generate_agent_metrics(tier)
|
||||
scenario["agents"].append(agent_metrics)
|
||||
|
||||
# Generate staking pool
|
||||
pool = generate_staking_pool(agent_metrics["agent_wallet"], 0.0)
|
||||
scenario["pools"].append(pool)
|
||||
|
||||
# Generate stakes for this agent
|
||||
for j in range(num_stakes_per_agent):
|
||||
staker_address = generate_staker_address()
|
||||
amount_category = random.choice(["small", "medium", "large"])
|
||||
lock_period_category = random.choice(["short", "medium", "long", "extended"])
|
||||
auto_compound = random.choice([True, False])
|
||||
|
||||
stake = generate_stake_data(
|
||||
agent_wallet=agent_metrics["agent_wallet"],
|
||||
staker_address=staker_address,
|
||||
tier=tier,
|
||||
amount_category=amount_category,
|
||||
lock_period_category=lock_period_category,
|
||||
auto_compound=auto_compound
|
||||
)
|
||||
scenario["stakes"].append(stake)
|
||||
|
||||
# Update pool totals
|
||||
pool["total_staked"] += stake["amount"]
|
||||
pool["staker_count"] += 1
|
||||
if staker_address not in pool["active_stakers"]:
|
||||
pool["active_stakers"].append(staker_address)
|
||||
|
||||
return scenario
|
||||
|
||||
|
||||
def generate_edge_case_scenarios() -> List[Dict[str, Any]]:
|
||||
"""Generate edge case test scenarios"""
|
||||
scenarios = []
|
||||
|
||||
# Scenario 1: Minimum stake amount
|
||||
scenarios.append({
|
||||
"name": "Minimum Stake Amount",
|
||||
"description": "Test with minimum valid stake amount (100 AIT)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
amount_category="minimum",
|
||||
lock_period_category="medium"
|
||||
)
|
||||
})
|
||||
|
||||
# Scenario 2: Maximum stake amount
|
||||
scenarios.append({
|
||||
"name": "Maximum Stake Amount",
|
||||
"description": "Test with maximum valid stake amount (100,000 AIT)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
amount_category="maximum",
|
||||
lock_period_category="medium"
|
||||
)
|
||||
})
|
||||
|
||||
# Scenario 3: Short lock period
|
||||
scenarios.append({
|
||||
"name": "Short Lock Period",
|
||||
"description": "Test with minimum lock period (7 days)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="short"
|
||||
)
|
||||
})
|
||||
|
||||
# Scenario 4: Extended lock period
|
||||
scenarios.append({
|
||||
"name": "Extended Lock Period",
|
||||
"description": "Test with maximum lock period (365 days)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="extended"
|
||||
)
|
||||
})
|
||||
|
||||
# Scenario 5: Diamond tier with extended lock
|
||||
scenarios.append({
|
||||
"name": "Diamond Tier Extended Lock",
|
||||
"description": "Test maximum APY scenario (Diamond tier + 365 days)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
tier="DIAMOND",
|
||||
lock_period_category="extended"
|
||||
)
|
||||
})
|
||||
|
||||
# Scenario 6: Auto-compound enabled
|
||||
scenarios.append({
|
||||
"name": "Auto-Compound Enabled",
|
||||
"description": "Test stake with auto-compound enabled",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
auto_compound=True
|
||||
)
|
||||
})
|
||||
|
||||
return scenarios
|
||||
|
||||
|
||||
def generate_unbonding_scenarios() -> List[Dict[str, Any]]:
|
||||
"""Generate unbonding test scenarios"""
|
||||
scenarios = []
|
||||
|
||||
# Scenario 1: Unbonding before lock period (should fail)
|
||||
scenarios.append({
|
||||
"name": "Unbond Before Lock Period",
|
||||
"description": "Test unbonding before lock period ends (should fail)",
|
||||
"stake": generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="medium"
|
||||
),
|
||||
"action": "unbond",
|
||||
"expected_result": "failure",
|
||||
"expected_error": "Lock period has not ended"
|
||||
})
|
||||
|
||||
# Scenario 2: Unbonding after lock period (should succeed)
|
||||
stake = generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="medium"
|
||||
)
|
||||
stake["end_time"] = (datetime.utcnow() - timedelta(days=1)).isoformat()
|
||||
scenarios.append({
|
||||
"name": "Unbond After Lock Period",
|
||||
"description": "Test unbonding after lock period ends (should succeed)",
|
||||
"stake": stake,
|
||||
"action": "unbond",
|
||||
"expected_result": "success",
|
||||
"expected_status": "UNBONDING"
|
||||
})
|
||||
|
||||
# Scenario 3: Complete unbonding with penalty
|
||||
stake = generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="medium"
|
||||
)
|
||||
stake["end_time"] = (datetime.utcnow() - timedelta(days=1)).isoformat()
|
||||
stake["status"] = "UNBONDING"
|
||||
stake["unbonding_time"] = (datetime.utcnow() - timedelta(days=10)).isoformat()
|
||||
scenarios.append({
|
||||
"name": "Complete Unbonding With Penalty",
|
||||
"description": "Test completing unbonding within 30 days (10% penalty)",
|
||||
"stake": stake,
|
||||
"action": "complete_unbonding",
|
||||
"expected_result": "success",
|
||||
"expected_penalty": 0.10
|
||||
})
|
||||
|
||||
# Scenario 4: Complete unbonding without penalty
|
||||
stake = generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category="medium"
|
||||
)
|
||||
stake["end_time"] = (datetime.utcnow() - timedelta(days=1)).isoformat()
|
||||
stake["status"] = "UNBONDING"
|
||||
stake["unbonding_time"] = (datetime.utcnow() - timedelta(days=35)).isoformat()
|
||||
scenarios.append({
|
||||
"name": "Complete Unbonding No Penalty",
|
||||
"description": "Test completing unbonding after 30 days (no penalty)",
|
||||
"stake": stake,
|
||||
"action": "complete_unbonding",
|
||||
"expected_result": "success",
|
||||
"expected_penalty": 0.0
|
||||
})
|
||||
|
||||
return scenarios
|
||||
|
||||
|
||||
def save_test_data(data: Dict[str, Any], output_file: str):
|
||||
"""Save test data to JSON file"""
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(data, f, indent=2, default=str)
|
||||
print(f"Test data saved to: {output_file}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to generate test data"""
|
||||
print("🔧 Generating Staking Test Data")
|
||||
print("=" * 50)
|
||||
|
||||
# Generate comprehensive test scenario
|
||||
print("\nGenerating comprehensive test scenario...")
|
||||
scenario = generate_test_scenario(num_agents=5, num_stakes_per_agent=3)
|
||||
save_test_data(scenario, "/var/lib/aitbc/data/test_staking_scenario.json")
|
||||
|
||||
# Generate edge case scenarios
|
||||
print("\nGenerating edge case scenarios...")
|
||||
edge_cases = generate_edge_case_scenarios()
|
||||
save_test_data(edge_cases, "/var/lib/aitbc/data/test_staking_edge_cases.json")
|
||||
|
||||
# Generate unbonding scenarios
|
||||
print("\nGenerating unbonding scenarios...")
|
||||
unbonding_scenarios = generate_unbonding_scenarios()
|
||||
save_test_data(unbonding_scenarios, "/var/lib/aitbc/data/test_staking_unbonding.json")
|
||||
|
||||
# Generate individual test data files
|
||||
print("\nGenerating individual test data files...")
|
||||
|
||||
# Agent metrics for each tier
|
||||
for tier in PERFORMANCE_TIERS.keys():
|
||||
metrics = generate_agent_metrics(tier)
|
||||
save_test_data(metrics, f"/var/lib/aitbc/data/test_agent_metrics_{tier.lower()}.json")
|
||||
|
||||
# Stake data for each amount category
|
||||
for amount_cat in STAKE_AMOUNTS.keys():
|
||||
stake = generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
amount_category=amount_cat
|
||||
)
|
||||
save_test_data(stake, f"/var/lib/aitbc/data/test_stake_{amount_cat}.json")
|
||||
|
||||
# Stake data for each lock period
|
||||
for lock_cat in LOCK_PERIOD_MULTIPLIERS.keys():
|
||||
stake = generate_stake_data(
|
||||
generate_agent_wallet(),
|
||||
generate_staker_address(),
|
||||
lock_period_category=lock_cat
|
||||
)
|
||||
save_test_data(stake, f"/var/lib/aitbc/data/test_stake_lock_{lock_cat}.json")
|
||||
|
||||
print("\n✅ Test data generation complete!")
|
||||
print("\nGenerated files:")
|
||||
print(" - /var/lib/aitbc/data/test_staking_scenario.json")
|
||||
print(" - /var/lib/aitbc/data/test_staking_edge_cases.json")
|
||||
print(" - /var/lib/aitbc/data/test_staking_unbonding.json")
|
||||
print(" - Agent metrics for each tier")
|
||||
print(" - Stake data for each amount category")
|
||||
print(" - Stake data for each lock period")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user