Files
aitbc/home/test_ollama_blockchain.py

260 lines
8.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Ollama GPU Provider Test with Blockchain Verification using Home Directory Users
Tests the complete flow: Client -> Coordinator -> GPU Miner -> Receipt -> Blockchain
"""
import os
import sys
import subprocess
import time
import json
from typing import Optional
import httpx
# Add parent directories to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'cli'))
# Configuration
DEFAULT_COORDINATOR = "http://127.0.0.1:18000"
DEFAULT_BLOCKCHAIN = "http://aitbc.keisanki.net/rpc"
DEFAULT_PROMPT = "What is the capital of France?"
DEFAULT_MODEL = "llama3.2:latest"
DEFAULT_TIMEOUT = 180
POLL_INTERVAL = 3
def get_wallet_balance(wallet_dir: str) -> float:
"""Get wallet balance from home directory wallet"""
result = subprocess.run(
f'cd {wallet_dir} && python3 wallet.py balance',
shell=True,
capture_output=True,
text=True
)
if result.returncode == 0:
for line in result.stdout.split('\n'):
if 'Balance:' in line:
# Extract the value after "Balance:"
balance_part = line.split('Balance:')[1].strip()
balance_value = balance_part.split()[0] # Get the numeric part before "AITBC"
try:
return float(balance_value)
except ValueError:
continue
return 0.0
def get_wallet_address(wallet_dir: str) -> Optional[str]:
"""Get wallet address from home directory wallet"""
result = subprocess.run(
f'cd {wallet_dir} && python3 wallet.py address',
shell=True,
capture_output=True,
text=True
)
if result.returncode == 0:
for line in result.stdout.split('\n'):
if 'Address:' in line:
return line.split()[-1]
return None
def submit_job_via_client(prompt: str, model: str) -> Optional[str]:
"""Submit job using the CLI client"""
cmd = f'cd ../cli && python3 client.py submit inference --prompt "{prompt}" --model {model}'
result = subprocess.run(
cmd,
shell=True,
capture_output=True,
text=True
)
if result.returncode != 0:
print(f"❌ Job submission failed: {result.stderr}")
return None
# Extract job ID
for line in result.stdout.split('\n'):
if "Job ID:" in line:
return line.split()[-1]
return None
def get_job_status(job_id: str) -> Optional[str]:
"""Get job status using CLI client"""
result = subprocess.run(
f'cd ../cli && python3 client.py status {job_id}',
shell=True,
capture_output=True,
text=True
)
if result.returncode != 0:
return None
# Extract state
for line in result.stdout.split('\n'):
if "State:" in line:
return line.split()[-1]
return None
def get_job_result(job_id: str) -> Optional[dict]:
"""Get job result via API"""
with httpx.Client() as client:
response = client.get(
f"{DEFAULT_COORDINATOR}/v1/jobs/{job_id}/result",
headers={"X-Api-Key": "${CLIENT_API_KEY}"},
timeout=10,
)
if response.status_code == 200:
return response.json()
return None
def check_blockchain_transaction(receipt_id: str) -> Optional[dict]:
"""Check if receipt is recorded on blockchain"""
try:
with httpx.Client() as client:
# Try to get recent transactions
response = client.get(
f"{DEFAULT_BLOCKCHAIN}/transactions",
timeout=10,
)
if response.status_code == 200:
data = response.json()
transactions = data.get("transactions", data.get("items", []))
# Look for matching receipt
for tx in transactions:
payload = tx.get("payload", {})
if payload.get("receipt_id") == receipt_id:
return tx
return None
except httpx.ConnectError:
print(f"⚠️ Blockchain node not available at {DEFAULT_BLOCKCHAIN}")
return None
except Exception as e:
print(f"⚠️ Error checking blockchain: {e}")
return None
def main():
print("🚀 Ollama GPU Provider Test with Home Directory Users")
print("=" * 60)
# Get initial balances
print("\n💰 Initial Wallet Balances:")
print("-" * 40)
client_balance = get_wallet_balance("client")
miner_balance = get_wallet_balance("miner")
print(f" Client: {client_balance} AITBC")
print(f" Miner: {miner_balance} AITBC")
# Submit job
print(f"\n📤 Submitting Inference Job:")
print("-" * 40)
print(f" Prompt: {DEFAULT_PROMPT}")
print(f" Model: {DEFAULT_MODEL}")
job_id = submit_job_via_client(DEFAULT_PROMPT, DEFAULT_MODEL)
if not job_id:
print("❌ Failed to submit job")
return 1
print(f"✅ Job submitted: {job_id}")
# Monitor job progress
print(f"\n⏳ Monitoring Job Progress:")
print("-" * 40)
deadline = time.time() + DEFAULT_TIMEOUT
while time.time() < deadline:
state = get_job_status(job_id)
if not state:
print(" ⚠️ Could not fetch status")
time.sleep(POLL_INTERVAL)
continue
print(f" State: {state}")
if state == "COMPLETED":
break
elif state in {"FAILED", "CANCELED", "EXPIRED"}:
print(f"❌ Job ended in state: {state}")
return 1
time.sleep(POLL_INTERVAL)
if state != "COMPLETED":
print("❌ Job did not complete within timeout")
return 1
# Get job result
print(f"\n📊 Job Result:")
print("-" * 40)
result = get_job_result(job_id)
if result:
output = result.get("result", {}).get("output", "No output")
receipt = result.get("receipt")
print(f" Output: {output[:200]}{'...' if len(output) > 200 else ''}")
if receipt:
print(f"\n🧾 Receipt Information:")
print(f" Receipt ID: {receipt.get('receipt_id')}")
print(f" Provider: {receipt.get('provider')}")
print(f" Units: {receipt.get('units')} {receipt.get('unit_type', 'seconds')}")
print(f" Unit Price: {receipt.get('unit_price')} AITBC")
print(f" Total Price: {receipt.get('price')} AITBC")
# Check blockchain
print(f"\n⛓️ Checking Blockchain:")
print("-" * 40)
tx = check_blockchain_transaction(receipt.get('receipt_id'))
if tx:
print(f"✅ Transaction found on blockchain!")
print(f" TX Hash: {tx.get('tx_hash')}")
print(f" Block: {tx.get('block_height')}")
print(f" From: {tx.get('sender')}")
print(f" To: {tx.get('recipient')}")
print(f" Amount: {tx.get('amount')} AITBC")
else:
print(f"⚠️ Transaction not yet found on blockchain")
print(f" (May take a few moments to be mined)")
else:
print(f"⚠️ No receipt generated")
else:
print(" Could not fetch result")
# Show final balances
print(f"\n💰 Final Wallet Balances:")
print("-" * 40)
client_balance = get_wallet_balance("client")
miner_balance = get_wallet_balance("miner")
print(f" Client: {client_balance} AITBC")
print(f" Miner: {miner_balance} AITBC")
# Calculate difference
client_diff = client_balance - get_wallet_balance("client")
print(f"\n📈 Transaction Summary:")
print("-" * 40)
print(f" Client spent: {abs(client_diff):.4f} AITBC")
print(f" Miner earned: {abs(client_diff):.4f} AITBC")
print(f"\n✅ Test completed successfully!")
return 0
if __name__ == "__main__":
sys.exit(main())