Files
aitbc/apps/wallet-cli/aitbc-wallet
oib ff5486fe08 ```
chore: refactor logging module, update genesis timestamp, remove model relationships, and reorganize routers

- Rename logging.py to logger.py and update import paths in poa.py and main.py
- Update devnet genesis timestamp to 1766828620
- Remove SQLModel Relationship declarations from Block, Transaction, and Receipt models
- Add SessionDep type alias and get_session dependency in coordinator-api deps
- Reorganize coordinator-api routers: replace explorer/registry with exchange, users, marketplace
2025-12-28 21:05:53 +01:00

246 lines
8.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""
AITBC Wallet CLI - A command-line wallet for AITBC blockchain
"""
import argparse
import json
import sys
import os
from pathlib import Path
import httpx
from datetime import datetime
# Configuration
BLOCKCHAIN_RPC = "http://127.0.0.1:9080"
WALLET_DIR = Path.home() / ".aitbc" / "wallets"
def print_header():
"""Print wallet CLI header"""
print("=" * 50)
print(" AITBC Blockchain Wallet CLI")
print("=" * 50)
def check_blockchain_connection():
"""Check if connected to blockchain"""
# First check if node is running by checking metrics
try:
response = httpx.get(f"{BLOCKCHAIN_RPC}/metrics", timeout=5.0)
if response.status_code == 200:
# Node is running, now try RPC
try:
rpc_response = httpx.get(f"{BLOCKCHAIN_RPC}/rpc/head", timeout=5.0)
if rpc_response.status_code == 200:
data = rpc_response.json()
return True, data.get("height", "unknown"), data.get("hash", "unknown")[:16] + "..."
else:
return False, f"RPC endpoint error (HTTP {rpc_response.status_code})", "node_running"
except Exception as e:
return False, f"RPC error: {str(e)}", "node_running"
return False, f"Node not responding (HTTP {response.status_code})", None
except Exception as e:
return False, str(e), None
def get_balance(address):
"""Get balance for an address"""
try:
response = httpx.get(f"{BLOCKCHAIN_RPC}/rpc/getBalance/{address}", timeout=5.0)
if response.status_code == 200:
return response.json()
return {"error": f"HTTP {response.status_code}"}
except Exception as e:
return {"error": str(e)}
def list_wallets():
"""List local wallets"""
WALLET_DIR.mkdir(parents=True, exist_ok=True)
wallets = []
for wallet_file in WALLET_DIR.glob("*.json"):
try:
with open(wallet_file, 'r') as f:
data = json.load(f)
wallets.append({
"id": wallet_file.stem,
"address": data.get("address", "unknown"),
"public_key": data.get("public_key", "unknown"),
"created": data.get("created_at", "unknown")
})
except Exception as e:
continue
return wallets
def create_wallet(wallet_id, address=None):
"""Create a new wallet file"""
WALLET_DIR.mkdir(parents=True, exist_ok=True)
wallet_file = WALLET_DIR / f"{wallet_id}.json"
if wallet_file.exists():
return False, "Wallet already exists"
# Generate a mock address if not provided
if not address:
address = f"aitbc1{wallet_id}{'x' * (40 - len(wallet_id))}"
# Generate a mock public key
public_key = f"0x{'1234567890abcdef' * 4}"
wallet_data = {
"wallet_id": wallet_id,
"address": address,
"public_key": public_key,
"created_at": datetime.now().isoformat() + "Z",
"note": "This is a demo wallet file - not for production use"
}
try:
with open(wallet_file, 'w') as f:
json.dump(wallet_data, f, indent=2)
return True, f"Wallet created: {wallet_file}"
except Exception as e:
return False, str(e)
def get_block_info(height=None):
try:
if height:
url = f"{BLOCKCHAIN_RPC}/rpc/blocks/{height}"
else:
url = f"{BLOCKCHAIN_RPC}/rpc/head"
response = httpx.get(url, timeout=5.0)
if response.status_code == 200:
return response.json()
return {"error": f"HTTP {response.status_code}"}
except Exception as e:
return {"error": str(e)}
def main():
parser = argparse.ArgumentParser(
description="AITBC Blockchain Wallet CLI",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s status Check blockchain connection
%(prog)s list List all local wallets
%(prog)s balance <address> Get balance of an address
%(prog)s block Show latest block info
%(prog)s block <height> Show specific block info
"""
)
subparsers = parser.add_subparsers(dest="command", help="Available commands")
# Status command
status_parser = subparsers.add_parser("status", help="Check blockchain connection status")
# List command
list_parser = subparsers.add_parser("list", help="List all local wallets")
# Balance command
balance_parser = subparsers.add_parser("balance", help="Get balance for an address")
balance_parser.add_argument("address", help="Wallet address to check")
# Block command
block_parser = subparsers.add_parser("block", help="Get block information")
block_parser.add_argument("height", nargs="?", type=int, help="Block height (optional)")
# Create command
create_parser = subparsers.add_parser("create", help="Create a new wallet file")
create_parser.add_argument("wallet_id", help="Wallet identifier")
create_parser.add_argument("--address", help="Wallet address")
args = parser.parse_args()
if not args.command:
print_header()
parser.print_help()
return
if args.command == "status":
print_header()
print("Checking blockchain connection...\n")
connected, info, block_hash = check_blockchain_connection()
if connected:
print(f"✅ Status: CONNECTED")
print(f"📦 Node: {BLOCKCHAIN_RPC}")
print(f"🔗 Latest Block: #{info}")
print(f"🧮 Block Hash: {block_hash}")
print(f"⏰ Checked at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
elif block_hash == "node_running":
print(f"⚠️ Status: NODE RUNNING - RPC UNAVAILABLE")
print(f"📦 Node: {BLOCKCHAIN_RPC}")
print(f"❌ RPC Error: {info}")
print(f"💡 The blockchain node is running but RPC endpoints are not working")
print(f" This might be due to initialization or database issues")
print(f"⏰ Checked at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
else:
print(f"❌ Status: DISCONNECTED")
print(f"📦 Node: {BLOCKCHAIN_RPC}")
print(f"⚠️ Error: {info}")
print(f"💡 Make sure the blockchain node is running on port 9080")
elif args.command == "list":
print_header()
wallets = list_wallets()
if wallets:
print(f"Found {len(wallets)} wallet(s) in {WALLET_DIR}:\n")
for w in wallets:
print(f"🔐 Wallet ID: {w['id']}")
print(f" Address: {w['address']}")
print(f" Public Key: {w['public_key'][:20]}...")
print(f" Created: {w['created']}")
print()
else:
print(f"No wallets found in {WALLET_DIR}")
print("\n💡 To create a wallet, use the wallet-daemon service")
elif args.command == "balance":
print_header()
print(f"Checking balance for address: {args.address}\n")
result = get_balance(args.address)
if "error" in result:
print(f"❌ Error: {result['error']}")
else:
balance = result.get("balance", 0)
print(f"💰 Balance: {balance} AITBC")
print(f"📍 Address: {args.address}")
elif args.command == "block":
print_header()
if args.height:
print(f"Getting block #{args.height}...\n")
else:
print("Getting latest block...\n")
result = get_block_info(args.height)
if "error" in result:
print(f"❌ Error: {result['error']}")
else:
print(f"📦 Block Height: {result.get('height', 'unknown')}")
print(f"🧮 Block Hash: {result.get('hash', 'unknown')}")
print(f"⏰ Timestamp: {result.get('timestamp', 'unknown')}")
print(f"👤 Proposer: {result.get('proposer', 'unknown')}")
print(f"📊 Transactions: {len(result.get('transactions', []))}")
elif args.command == "create":
print_header()
success, message = create_wallet(args.wallet_id, args.address)
if success:
print(f"{message}")
print(f"\nWallet Details:")
print(f" ID: {args.wallet_id}")
print(f" Address: {args.address or f'aitbc1{args.wallet_id}...'}")
print(f"\n💡 This is a demo wallet file for testing purposes")
print(f" Use 'aitbc-wallet list' to see all wallets")
else:
print(f"❌ Error: {message}")
else:
parser.print_help()
if __name__ == "__main__":
main()