fix: CLI bugs - island list, output signature, GPU credentials, mining subcommand
Some checks failed
CLI Tests / test-cli (push) Failing after 3s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Deploy to Testnet / deploy-testnet (push) Successful in 1m18s
Multi-Node Stress Testing / stress-test (push) Successful in 2s
Security Scanning / security-scan (push) Successful in 31s

- S05 Islands: edge.py list_islands now has name='list' for 'aitbc edge island list'
- S06 Market: output() now handles structured data (dict/list) by JSON-encoding
- S09 GPU: added safe_load_credentials() to gpu_marketplace.py and exchange_island.py
  with graceful FileNotFoundError handling and helpful error message
- S13 Mining: added 'list' subcommand to mining.py for listing active miners
This commit is contained in:
aitbc
2026-05-19 19:38:06 +02:00
parent 9804a68437
commit 27a078a279
5 changed files with 88 additions and 19 deletions

View File

@@ -80,7 +80,7 @@ def leave(island_id: str):
error(f"Error leaving island: {str(e)}")
@island.command()
@island.command(name='list')
def list_islands():
"""List all islands"""
try:

View File

@@ -24,6 +24,16 @@ from aitbc import get_logger, AITBCHTTPClient, NetworkError
logger = get_logger(__name__)
def safe_load_credentials():
"""Load island credentials with graceful error handling"""
try:
return load_island_credentials()
except FileNotFoundError as e:
error(f"Island credentials not found: {e}")
error("Run 'aitbc node island join' to join an island first")
return None
# Supported trading pairs
SUPPORTED_PAIRS = ['AIT/BTC', 'AIT/ETH']
@@ -47,7 +57,9 @@ def buy(ctx, ait_amount: float, quote_currency: str, max_price: Optional[float])
raise click.Abort()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
chain_id = get_chain_id()
island_id = get_island_id()
@@ -144,7 +156,9 @@ def sell(ctx, ait_amount: float, quote_currency: str, min_price: Optional[float]
raise click.Abort()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
chain_id = get_chain_id()
island_id = get_island_id()
@@ -232,7 +246,9 @@ def orderbook(ctx, pair: str, limit: int):
"""View the order book for a trading pair"""
try:
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
island_id = get_island_id()
@@ -320,7 +336,9 @@ def rates(ctx):
"""View current exchange rates for AIT/BTC and AIT/ETH"""
try:
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
island_id = get_island_id()
@@ -380,7 +398,9 @@ def orders(ctx, user: Optional[str], status: Optional[str], pair: Optional[str])
"""List exchange orders"""
try:
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
island_id = get_island_id()
@@ -435,7 +455,9 @@ def cancel(ctx, order_id: str):
"""Cancel an exchange order"""
try:
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
rpc_endpoint = get_rpc_endpoint()
chain_id = get_chain_id()
island_id = get_island_id()

View File

@@ -15,7 +15,7 @@ from typing import Optional, List
from ..utils import output, error, success, info, warning
from ..utils.island_credentials import (
load_island_credentials, get_rpc_endpoint, get_chain_id,
get_island_id, get_island_name
get_island_id, get_island_name, validate_credentials
)
from ..config import get_config
@@ -26,6 +26,16 @@ from aitbc import get_logger, AITBCHTTPClient, NetworkError
logger = get_logger(__name__)
def safe_load_credentials():
"""Load island credentials with graceful error handling"""
try:
return load_island_credentials()
except FileNotFoundError as e:
error(f"Island credentials not found: {e}")
error("Run 'aitbc node island join' to join an island first")
return None
@click.group()
def gpu():
"""GPU marketplace commands for bidding and offering GPU power"""
@@ -46,7 +56,9 @@ def offer(ctx, gpu_count: int, price_per_gpu: float, duration_hours: int, specs:
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
chain_id = get_chain_id()
island_id = get_island_id()
@@ -149,7 +161,9 @@ def bid(ctx, gpu_count: int, max_price: float, duration_hours: int, specs: Optio
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
chain_id = get_chain_id()
island_id = get_island_id()
@@ -250,7 +264,9 @@ def list(ctx, provider: Optional[str], status: Optional[str], type: str):
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
island_id = get_island_id()
# Query GPU service for GPU marketplace transactions
@@ -322,7 +338,9 @@ def cancel(ctx, order_id: str):
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
chain_id = get_chain_id()
island_id = get_island_id()
@@ -388,7 +406,9 @@ def accept(ctx, bid_id: str):
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
chain_id = get_chain_id()
island_id = get_island_id()
@@ -451,7 +471,9 @@ def status(ctx, order_id: str):
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
island_id = get_island_id()
# Query GPU service for the order
@@ -520,7 +542,9 @@ def match(ctx):
config = get_config()
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
island_id = get_island_id()
# Query GPU service for open offers and bids
@@ -612,7 +636,9 @@ def providers(ctx):
"""Query island members for GPU providers"""
try:
# Load island credentials
credentials = load_island_credentials()
credentials = safe_load_credentials()
if not credentials:
return
island_id = get_island_id()
# Load island members from credentials

View File

@@ -94,7 +94,7 @@ def status(rpc_url: Optional[str]):
"""Get mining status"""
if not rpc_url:
rpc_url = DEFAULT_RPC_URL
try:
http_client = AITBCHTTPClient(base_url=rpc_url, timeout=30)
result = http_client.get("/rpc/mining/status")
@@ -104,3 +104,21 @@ def status(rpc_url: Optional[str]):
error(f"Error getting mining status: {e}")
except Exception as e:
error(f"Error: {e}")
@mining.command(name='list')
@click.option('--rpc-url', help='Blockchain RPC URL')
def list_miners(rpc_url: Optional[str]):
"""List active miners"""
if not rpc_url:
rpc_url = DEFAULT_RPC_URL
try:
http_client = AITBCHTTPClient(base_url=rpc_url, timeout=30)
result = http_client.get("/rpc/mining/miners")
success("Active miners:")
click.echo(json.dumps(result, indent=2))
except NetworkError as e:
error(f"Error listing miners: {e}")
except Exception as e:
error(f"Error: {e}")

View File

@@ -16,8 +16,11 @@ from .wallet import decrypt_private_key
from .blockchain import get_chain_info, get_network_status, get_blockchain_analytics
def output(message: str, **kwargs):
"""Print a regular output message"""
def output(message, **kwargs):
"""Print a regular output message (handles strings and structured data)"""
if not isinstance(message, str):
import json
message = json.dumps(message, indent=2)
echo(message, **kwargs)