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:
aitbc
2026-04-13 22:07:51 +02:00
parent da630386cf
commit 7c51f3490b
140 changed files with 42080 additions and 267 deletions

View File

@@ -0,0 +1,337 @@
"""
Staking Lifecycle Integration Tests
Test 3.1.1: Complete staking lifecycle integration test
"""
import pytest
import asyncio
import sys
from datetime import datetime, timedelta
sys.path.insert(0, "/opt/aitbc/apps/coordinator-api/src")
sys.path.insert(0, "/opt/aitbc/contracts")
# Import after path setup
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from sqlmodel import SQLModel
from app.domain.bounty import AgentStake, AgentMetrics, StakingPool, StakeStatus, PerformanceTier
from app.services.staking_service import StakingService
@pytest.fixture
def db_session():
"""Create SQLite in-memory database for testing"""
engine = create_engine("sqlite:///:memory:", echo=False)
SQLModel.metadata.create_all(engine)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = SessionLocal()
yield session
session.close()
@pytest.fixture
def staking_service(db_session):
"""Create staking service instance"""
return StakingService(db_session)
@pytest.fixture
def agent_wallet():
"""Test agent wallet address"""
return "0x1234567890123456789012345678901234567890"
@pytest.fixture
def staker_address():
"""Test staker address"""
return "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
@pytest.fixture
def agent_metrics(db_session, agent_wallet):
"""Create test agent metrics"""
metrics = AgentMetrics(
agent_wallet=agent_wallet,
total_staked=0.0,
staker_count=0,
total_rewards_distributed=0.0,
average_accuracy=95.0,
total_submissions=10,
successful_submissions=9,
success_rate=90.0,
current_tier=PerformanceTier.GOLD,
tier_score=80.0
)
db_session.add(metrics)
db_session.commit()
db_session.refresh(metrics)
return metrics
class TestStakingLifecycle:
"""Test 3.1.1: Complete staking lifecycle integration test"""
async def test_complete_staking_lifecycle(
self,
staking_service,
agent_metrics,
staker_address,
agent_wallet
):
"""Test complete staking lifecycle: create stake → unbond → complete"""
# Step 1: Create stake
print("\n=== Step 1: Creating stake ===")
stake = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=agent_wallet,
amount=1000.0,
lock_period=30,
auto_compound=False
)
assert stake is not None
assert stake.status == StakeStatus.ACTIVE
assert stake.amount == 1000.0
print(f"✓ Stake created: {stake.stake_id}")
# Verify agent metrics updated
updated_metrics = await staking_service.get_agent_metrics(agent_wallet)
assert updated_metrics.total_staked == 1000.0
assert updated_metrics.staker_count == 1
print(f"✓ Agent metrics updated: total_staked={updated_metrics.total_staked}")
# Verify staking pool updated
updated_pool = await staking_service.get_staking_pool(agent_wallet)
assert updated_pool.total_staked == 1000.0
print(f"✓ Staking pool updated: total_staked={updated_pool.total_staked}")
# Step 2: Calculate rewards
print("\n=== Step 2: Calculating rewards ===")
rewards = await staking_service.calculate_rewards(stake.stake_id)
print(f"✓ Rewards calculated: {rewards}")
# Step 3: Simulate time passing (lock period elapsed)
print("\n=== Step 3: Simulating lock period ===")
# In a real scenario, this would be actual time passing
# For testing, we'll just verify the logic works
stake.end_time = datetime.utcnow() - timedelta(days=1) # Lock period ended
staking_service.session.commit()
print(f"✓ Lock period simulated as ended")
# Step 4: Initiate unbonding
print("\n=== Step 4: Initiating unbonding ===")
unbonded_stake = await staking_service.unbond_stake(stake.stake_id)
assert unbonded_stake.status == StakeStatus.UNBONDING
print(f"✓ Unbonding initiated: status={unbonded_stake.status}")
# Step 5: Simulate unbonding period
print("\n=== Step 5: Simulating unbonding period ===")
unbonded_stake.unbonding_time = datetime.utcnow() - timedelta(days=8) # 8 days ago
staking_service.session.commit()
print(f"✓ Unbonding period simulated as ended")
# Step 6: Complete unbonding
print("\n=== Step 6: Completing unbonding ===")
result = await staking_service.complete_unbonding(stake.stake_id)
assert result is not None
assert "total_amount" in result
assert "total_rewards" in result
assert "penalty" in result
print(f"✓ Unbonding completed:")
print(f" - Total amount: {result['total_amount']}")
print(f" - Total rewards: {result['total_rewards']}")
print(f" - Penalty: {result['penalty']}")
# Verify stake status
completed_stake = await staking_service.get_stake(stake.stake_id)
assert completed_stake.status == StakeStatus.COMPLETED
print(f"✓ Stake status: {completed_stake.status}")
# Verify agent metrics updated
final_metrics = await staking_service.get_agent_metrics(agent_wallet)
assert final_metrics.total_staked == 0.0
assert final_metrics.staker_count == 0
print(f"✓ Agent metrics reset: total_staked={final_metrics.total_staked}")
# Verify staking pool updated
final_pool = await staking_service.get_staking_pool(agent_wallet)
assert final_pool.total_staked == 0.0
assert staker_address not in final_pool.active_stakers
print(f"✓ Staking pool reset: total_staked={final_pool.total_staked}")
print("\n=== Complete staking lifecycle test PASSED ===")
async def test_stake_accumulation_over_time(
self,
staking_service,
agent_metrics,
staker_address,
agent_wallet
):
"""Test rewards accumulation over time"""
# Create stake
stake = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=agent_wallet,
amount=1000.0,
lock_period=30,
auto_compound=False
)
# Calculate initial rewards
initial_rewards = await staking_service.calculate_rewards(stake.stake_id)
print(f"Initial rewards: {initial_rewards}")
# Simulate time passing by updating last_reward_time
stake.last_reward_time = datetime.utcnow() - timedelta(days=10)
staking_service.session.commit()
# Calculate rewards after 10 days
rewards_after_10_days = await staking_service.calculate_rewards(stake.stake_id)
print(f"Rewards after 10 days: {rewards_after_10_days}")
# Rewards should have increased
assert rewards_after_10_days >= initial_rewards
print("✓ Rewards accumulated over time")
async def test_multiple_stakes_same_agent(
self,
staking_service,
agent_metrics,
staker_address,
agent_wallet
):
"""Test multiple stakes on the same agent"""
# Create first stake
stake1 = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=agent_wallet,
amount=500.0,
lock_period=30,
auto_compound=False
)
# Create second stake
stake2 = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=agent_wallet,
amount=1500.0,
lock_period=60,
auto_compound=True
)
# Verify both stakes exist
assert stake1.stake_id != stake2.stake_id
assert stake1.amount == 500.0
assert stake2.amount == 1500.0
assert stake2.auto_compound == True
# Verify agent metrics
metrics = await staking_service.get_agent_metrics(agent_wallet)
assert metrics.total_staked == 2000.0
assert metrics.staker_count == 1 # Same staker
# Verify staking pool
pool = await staking_service.get_staking_pool(agent_wallet)
assert pool.total_staked == 2000.0
print("✓ Multiple stakes on same agent created successfully")
async def test_stake_with_different_tiers(
self,
staking_service,
db_session,
staker_address,
agent_wallet
):
"""Test stakes on agents with different performance tiers"""
# Create agents with different tiers
bronze_agent = "0x1111111111111111111111111111111111111111"
silver_agent = "0x2222222222222222222222222222222222222222"
gold_agent = agent_wallet
bronze_metrics = AgentMetrics(
agent_wallet=bronze_agent,
total_staked=0.0,
staker_count=0,
total_rewards_distributed=0.0,
average_accuracy=65.0,
total_submissions=10,
successful_submissions=7,
success_rate=70.0,
current_tier=PerformanceTier.BRONZE,
tier_score=60.0
)
silver_metrics = AgentMetrics(
agent_wallet=silver_agent,
total_staked=0.0,
staker_count=0,
total_rewards_distributed=0.0,
average_accuracy=85.0,
total_submissions=10,
successful_submissions=8,
success_rate=80.0,
current_tier=PerformanceTier.SILVER,
tier_score=70.0
)
gold_metrics = AgentMetrics(
agent_wallet=gold_agent,
total_staked=0.0,
staker_count=0,
total_rewards_distributed=0.0,
average_accuracy=95.0,
total_submissions=10,
successful_submissions=9,
success_rate=90.0,
current_tier=PerformanceTier.GOLD,
tier_score=80.0
)
db_session.add_all([bronze_metrics, silver_metrics, gold_metrics])
db_session.commit()
# Create stakes on each agent
bronze_stake = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=bronze_agent,
amount=1000.0,
lock_period=30,
auto_compound=False
)
silver_stake = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=silver_agent,
amount=1000.0,
lock_period=30,
auto_compound=False
)
gold_stake = await staking_service.create_stake(
staker_address=staker_address,
agent_wallet=gold_agent,
amount=1000.0,
lock_period=30,
auto_compound=False
)
# Verify APY increases with tier
assert bronze_stake.current_apy < silver_stake.current_apy
assert silver_stake.current_apy < gold_stake.current_apy
print(f"✓ Bronze tier APY: {bronze_stake.current_apy}%")
print(f"✓ Silver tier APY: {silver_stake.current_apy}%")
print(f"✓ Gold tier APY: {gold_stake.current_apy}%")
print("✓ APY correctly increases with performance tier")