refactor: organize scripts/, remove stale root dirs, clean up structure
scripts/ reorganization: - Sort 14 loose root scripts into subfolders: blockchain/ (genesis, proposer, mock chain, testnet BTC) dev/ (CLI wrapper, dev services, OpenAPI gen, systemd setup, domain proxy) ops/ (coordinator proxy, remote tunnel) gpu/ (miner workflow) - Merge scripts/testing/ into scripts/test/ (eliminate duplicate folder) - Create scripts/examples/ for usage demos and simulations Root-level cleanup: - Move home/ (12 simulation scripts) → scripts/examples/ - Move dev-utils/ (2 files) → scripts/dev/ - Move protocols/receipts/sample → tests/fixtures/ - Delete stale src/ (duplicate of apps/blockchain-node/src/) - Remove empty home/, dev-utils/, protocols/ directories Documentation updates: - Update docs/6_architecture/8_codebase-structure.md tree and table - Update root README.md tree to reflect new structure
This commit is contained in:
17
scripts/dev/aitbc-pythonpath.pth
Normal file
17
scripts/dev/aitbc-pythonpath.pth
Normal file
@@ -0,0 +1,17 @@
|
||||
# Add project paths to Python path for imports
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Get the directory where this .pth file is located
|
||||
project_root = Path(__file__).parent
|
||||
|
||||
# Add package source directories
|
||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-core" / "src"))
|
||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-crypto" / "src"))
|
||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-p2p" / "src"))
|
||||
sys.path.insert(0, str(project_root / "packages" / "py" / "aitbc-sdk" / "src"))
|
||||
|
||||
# Add app source directories
|
||||
sys.path.insert(0, str(project_root / "apps" / "coordinator-api" / "src"))
|
||||
sys.path.insert(0, str(project_root / "apps" / "wallet-daemon" / "src"))
|
||||
sys.path.insert(0, str(project_root / "apps" / "blockchain-node" / "src"))
|
||||
11
scripts/dev/dev-utils-README.md
Normal file
11
scripts/dev/dev-utils-README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Development Utilities
|
||||
|
||||
This directory contains utility files and scripts for development.
|
||||
|
||||
## Files
|
||||
|
||||
- **aitbc-pythonpath.pth** - Python path configuration for AITBC packages
|
||||
|
||||
## Usage
|
||||
|
||||
The `.pth` file is automatically used by Python to add paths to `sys.path` when the virtual environment is activated.
|
||||
131
scripts/examples/README.md
Normal file
131
scripts/examples/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# AITBC Local Simulation
|
||||
|
||||
Simulate client and GPU provider interactions with independent wallets and AITBC transactions.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
home/
|
||||
├── genesis.py # Creates genesis block and distributes initial AITBC
|
||||
├── client/ # Customer/client wallet
|
||||
│ └── wallet.py # Client wallet management
|
||||
├── miner/ # GPU provider wallet
|
||||
│ └── wallet.py # Miner wallet management
|
||||
└── simulate.py # Complete workflow simulation
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Initialize the Economy
|
||||
```bash
|
||||
cd /home/oib/windsurf/aitbc/home
|
||||
python3 genesis.py
|
||||
```
|
||||
This creates:
|
||||
- Genesis wallet: 1,000,000 AITBC
|
||||
- Client wallet: 10,000 AITBC
|
||||
- Miner wallet: 1,000 AITBC
|
||||
|
||||
### 2. Check Wallets
|
||||
```bash
|
||||
# Client wallet
|
||||
cd client && python3 wallet.py balance
|
||||
|
||||
# Miner wallet
|
||||
cd miner && python3 wallet.py balance
|
||||
```
|
||||
|
||||
### 3. Run Complete Simulation
|
||||
```bash
|
||||
cd /home/oib/windsurf/aitbc/home
|
||||
python3 simulate.py
|
||||
```
|
||||
|
||||
## Wallet Commands
|
||||
|
||||
### Client Wallet
|
||||
```bash
|
||||
cd client
|
||||
|
||||
# Check balance
|
||||
python3 wallet.py balance
|
||||
|
||||
# Show address
|
||||
python3 wallet.py address
|
||||
|
||||
# Pay for services
|
||||
python3 wallet.py send <amount> <address> <description>
|
||||
|
||||
# Transaction history
|
||||
python3 wallet.py history
|
||||
```
|
||||
|
||||
### Miner Wallet
|
||||
```bash
|
||||
cd miner
|
||||
|
||||
# Check balance with stats
|
||||
python3 wallet.py balance
|
||||
|
||||
# Add earnings from completed job
|
||||
python3 wallet.py earn <amount> --job <job_id> --desc "Service description"
|
||||
|
||||
# Withdraw earnings
|
||||
python3 wallet.py withdraw <amount> <address>
|
||||
|
||||
# Mining statistics
|
||||
python3 wallet.py stats
|
||||
```
|
||||
|
||||
## Example Workflow
|
||||
|
||||
### 1. Client Submits Job
|
||||
```bash
|
||||
cd /home/oib/windsurf/aitbc/cli
|
||||
python3 client.py submit inference --model llama-2-7b --prompt "What is AI?"
|
||||
```
|
||||
|
||||
### 2. Miner Processes Job
|
||||
```bash
|
||||
# Miner polls and gets job
|
||||
python3 miner.py poll
|
||||
|
||||
# Miner earns AITBC
|
||||
cd /home/oib/windsurf/aitbc/home/miner
|
||||
python3 wallet.py earn 50.0 --job abc123 --desc "Inference task"
|
||||
```
|
||||
|
||||
### 3. Client Pays
|
||||
```bash
|
||||
cd /home/oib/windsurf/aitbc/home/client
|
||||
|
||||
# Get miner address
|
||||
cd ../miner && python3 wallet.py address
|
||||
# Returns: aitbc1721d5bf8c0005ded6704
|
||||
|
||||
# Send payment
|
||||
cd ../client
|
||||
python3 wallet.py send 50.0 aitbc1721d5bf8c0005ded6704 "Payment for inference"
|
||||
```
|
||||
|
||||
## Wallet Files
|
||||
|
||||
- `client/client_wallet.json` - Client's wallet data
|
||||
- `miner/miner_wallet.json` - Miner's wallet data
|
||||
- `genesis_wallet.json` - Genesis wallet with remaining AITBC
|
||||
|
||||
## Integration with CLI Tools
|
||||
|
||||
The home wallets integrate with the CLI tools:
|
||||
|
||||
1. Submit jobs using `cli/client.py`
|
||||
2. Process jobs using `cli/miner.py`
|
||||
3. Track payments using `home/*/wallet.py`
|
||||
|
||||
## Tips
|
||||
|
||||
- Each wallet has a unique address
|
||||
- All transactions are recorded with timestamps
|
||||
- Genesis wallet holds the remaining AITBC supply
|
||||
- Use `simulate.py` for a complete demo
|
||||
- Check `wallet.py history` to see all transactions
|
||||
143
scripts/examples/client_get_result.py
Executable file
143
scripts/examples/client_get_result.py
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Client retrieves job result from completed GPU processing
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add paths
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'cli'))
|
||||
|
||||
def get_job_result(job_id):
|
||||
"""Get the result of a completed job"""
|
||||
|
||||
print(f"🔍 Retrieving result for job: {job_id}")
|
||||
print("=" * 60)
|
||||
|
||||
# Check job status
|
||||
print("\n1. Checking job status...")
|
||||
status_result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(status_result.stdout)
|
||||
|
||||
# Check if job is completed
|
||||
if "completed" in status_result.stdout:
|
||||
print("\n2. ✅ Job completed! Retrieving result...")
|
||||
|
||||
# Parse the status to get result details
|
||||
# In a real implementation, this would fetch from the coordinator API
|
||||
print("\n📄 Job Result:")
|
||||
print("-" * 40)
|
||||
|
||||
# Simulate getting the result from the blockchain/coordinator
|
||||
print(f"Job ID: {job_id}")
|
||||
print("Status: Completed")
|
||||
print("Miner: ollama-miner")
|
||||
print("Model: llama3.2:latest")
|
||||
print("Processing Time: 2.3 seconds")
|
||||
print("\nOutput:")
|
||||
print("Hello! I'm an AI assistant powered by AITBC network.")
|
||||
print("I'm running on GPU infrastructure provided by network miners.")
|
||||
print("\nMetadata:")
|
||||
print("- Tokens processed: 15")
|
||||
print("- GPU utilization: 45%")
|
||||
print("- Cost: 0.000025 AITBC")
|
||||
|
||||
return True
|
||||
|
||||
elif "queued" in status_result.stdout:
|
||||
print("\n⏳ Job is still queued, waiting for miner...")
|
||||
return False
|
||||
|
||||
elif "running" in status_result.stdout:
|
||||
print("\n⚙️ Job is being processed by GPU provider...")
|
||||
return False
|
||||
|
||||
elif "failed" in status_result.stdout:
|
||||
print("\n❌ Job failed!")
|
||||
return False
|
||||
|
||||
else:
|
||||
print("\n❓ Unknown job status")
|
||||
return False
|
||||
|
||||
def watch_job(job_id):
|
||||
"""Watch a job until completion"""
|
||||
|
||||
print(f"👀 Watching job: {job_id}")
|
||||
print("=" * 60)
|
||||
|
||||
import time
|
||||
|
||||
max_wait = 60 # Maximum wait time in seconds
|
||||
start_time = time.time()
|
||||
|
||||
while time.time() - start_time < max_wait:
|
||||
print(f"\n⏰ Checking... ({int(time.time() - start_time)}s elapsed)")
|
||||
|
||||
# Get status
|
||||
result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if "completed" in result.stdout:
|
||||
print("\n✅ Job completed!")
|
||||
return get_job_result(job_id)
|
||||
elif "failed" in result.stdout:
|
||||
print("\n❌ Job failed!")
|
||||
return False
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
print("\n⏰ Timeout waiting for job completion")
|
||||
return False
|
||||
|
||||
def list_recent_results():
|
||||
"""List recent completed jobs and their results"""
|
||||
|
||||
print("📋 Recent Job Results")
|
||||
print("=" * 60)
|
||||
|
||||
# Get recent blocks/jobs from explorer
|
||||
result = subprocess.run(
|
||||
'cd ../cli && python3 client.py blocks --limit 5',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
print("\n💡 To get specific result:")
|
||||
print(" python3 client_get_result.py <job_id>")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:")
|
||||
print(" python3 client_get_result.py <job_id> # Get specific job result")
|
||||
print(" python3 client_get_result.py watch <job_id> # Watch job until complete")
|
||||
print(" python3 client_get_result.py list # List recent results")
|
||||
return
|
||||
|
||||
command = sys.argv[1]
|
||||
|
||||
if command == "list":
|
||||
list_recent_results()
|
||||
elif command == "watch" and len(sys.argv) > 2:
|
||||
watch_job(sys.argv[2])
|
||||
else:
|
||||
get_job_result(command)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
126
scripts/examples/client_send_job.py
Executable file
126
scripts/examples/client_send_job.py
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Client sends a job to GPU provider and pays for it
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add paths
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'cli'))
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__)))
|
||||
|
||||
def send_job_to_gpu_provider():
|
||||
print("🚀 Client: Sending Job to GPU Provider")
|
||||
print("=" * 60)
|
||||
|
||||
# 1. Check client wallet balance
|
||||
print("\n1. Checking client wallet...")
|
||||
result = subprocess.run(
|
||||
'cd client && python3 wallet.py balance',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
print(result.stdout)
|
||||
|
||||
# 2. Submit job to coordinator
|
||||
print("\n2. Submitting 'hello' job to network...")
|
||||
job_result = subprocess.run(
|
||||
'cd ../cli && python3 client.py submit inference --prompt "hello"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(job_result.stdout)
|
||||
|
||||
# Extract job ID
|
||||
job_id = None
|
||||
if "Job ID:" in job_result.stdout:
|
||||
for line in job_result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
if not job_id:
|
||||
print("❌ Failed to submit job")
|
||||
return
|
||||
|
||||
print(f"\n✅ Job submitted: {job_id}")
|
||||
|
||||
# 3. Wait for miner to process
|
||||
print("\n3. Waiting for GPU provider to process job...")
|
||||
print(" (Make sure miner is running: python3 cli/miner.py mine)")
|
||||
|
||||
# Check job status
|
||||
max_wait = 30
|
||||
for i in range(max_wait):
|
||||
status_result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if "completed" in status_result.stdout:
|
||||
print("✅ Job completed by GPU provider!")
|
||||
print(status_result.stdout)
|
||||
break
|
||||
elif "failed" in status_result.stdout:
|
||||
print("❌ Job failed")
|
||||
print(status_result.stdout)
|
||||
break
|
||||
else:
|
||||
print(f" Waiting... ({i+1}s)")
|
||||
time.sleep(1)
|
||||
|
||||
# 4. Get cost and pay
|
||||
print("\n4. Processing payment...")
|
||||
|
||||
# For demo, assume cost is 10 AITBC
|
||||
job_cost = 10.0
|
||||
|
||||
# Get miner address
|
||||
miner_result = subprocess.run(
|
||||
'cd miner && python3 wallet.py address',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
miner_address = None
|
||||
if "Miner Address:" in miner_result.stdout:
|
||||
for line in miner_result.stdout.split('\n'):
|
||||
if "Miner Address:" in line:
|
||||
miner_address = line.split()[-1]
|
||||
break
|
||||
|
||||
if miner_address:
|
||||
print(f" Paying {job_cost} AITBC to miner...")
|
||||
|
||||
# Send payment
|
||||
pay_result = subprocess.run(
|
||||
f'cd client && python3 wallet.py send {job_cost} {miner_address} "Payment for job {job_id}"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(pay_result.stdout)
|
||||
|
||||
# 5. Show final balances
|
||||
print("\n5. Final balances:")
|
||||
print("\n Client:")
|
||||
subprocess.run('cd client && python3 wallet.py balance', shell=True)
|
||||
|
||||
print("\n Miner:")
|
||||
subprocess.run('cd miner && python3 wallet.py balance', shell=True)
|
||||
|
||||
print("\n✅ Job completed and paid for!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
send_job_to_gpu_provider()
|
||||
74
scripts/examples/client_wallet.py
Executable file
74
scripts/examples/client_wallet.py
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Client wallet for managing AITBC tokens
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# Add parent directory to path to import wallet module
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location("wallet", os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "wallet.py"))
|
||||
wallet = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(wallet)
|
||||
AITBCWallet = wallet.AITBCWallet
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Client Wallet - Manage AITBC for paying for GPU services")
|
||||
parser.add_argument("--wallet", default="client_wallet.json", help="Wallet file name")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
||||
|
||||
# Balance command
|
||||
balance_parser = subparsers.add_parser("balance", help="Show balance")
|
||||
|
||||
# Address command
|
||||
address_parser = subparsers.add_parser("address", help="Show wallet address")
|
||||
|
||||
# History command
|
||||
history_parser = subparsers.add_parser("history", help="Show transaction history")
|
||||
|
||||
# Send command (pay for services)
|
||||
send_parser = subparsers.add_parser("send", help="Send AITBC to GPU provider")
|
||||
send_parser.add_argument("amount", type=float, help="Amount to send")
|
||||
send_parser.add_argument("to", help="Recipient address")
|
||||
send_parser.add_argument("description", help="Payment description")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
# Use client-specific wallet directory
|
||||
wallet_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
wallet_path = os.path.join(wallet_dir, args.wallet)
|
||||
|
||||
wallet = AITBCWallet(wallet_path)
|
||||
|
||||
if args.command == "balance":
|
||||
print("💼 CLIENT WALLET")
|
||||
print("=" * 40)
|
||||
wallet.show_balance()
|
||||
print("\n💡 Use 'send' to pay for GPU services")
|
||||
|
||||
elif args.command == "address":
|
||||
print(f"💼 Client Address: {wallet.data['address']}")
|
||||
print(" Share this address to receive AITBC")
|
||||
|
||||
elif args.command == "history":
|
||||
print("💼 CLIENT TRANSACTION HISTORY")
|
||||
print("=" * 40)
|
||||
wallet.show_history()
|
||||
|
||||
elif args.command == "send":
|
||||
print(f"💸 Sending {args.amount} AITBC to {args.to}")
|
||||
print(f" For: {args.description}")
|
||||
wallet.spend(args.amount, args.description)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
199
scripts/examples/enhanced_client.py
Executable file
199
scripts/examples/enhanced_client.py
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Enhanced client that submits jobs and automatically retrieves results
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Add paths
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'cli'))
|
||||
|
||||
class AITBCClient:
|
||||
def __init__(self):
|
||||
self.coordinator_url = "http://localhost:8001"
|
||||
self.api_key = "${CLIENT_API_KEY}"
|
||||
|
||||
def submit_job(self, prompt, model="llama3.2:latest", wait_for_result=True):
|
||||
"""Submit a job and optionally wait for result"""
|
||||
|
||||
print(f"📤 Submitting job to AITBC network...")
|
||||
print(f" Prompt: '{prompt}'")
|
||||
print(f" Model: {model}")
|
||||
print()
|
||||
|
||||
# Submit job
|
||||
result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py submit inference --prompt "{prompt}"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Extract job ID
|
||||
job_id = None
|
||||
for line in result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
if not job_id:
|
||||
print("❌ Failed to submit job")
|
||||
return None
|
||||
|
||||
print(f"✅ Job submitted: {job_id}")
|
||||
|
||||
if wait_for_result:
|
||||
return self.wait_for_result(job_id)
|
||||
else:
|
||||
return job_id
|
||||
|
||||
def wait_for_result(self, job_id, timeout=60):
|
||||
"""Wait for job completion and return result"""
|
||||
|
||||
print(f"⏳ Waiting for GPU provider to process job...")
|
||||
print(f" Timeout: {timeout}s")
|
||||
print()
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
# Check status
|
||||
status_result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if "completed" in status_result.stdout:
|
||||
print(f"✅ Job completed by GPU provider!")
|
||||
print()
|
||||
return self.get_result(job_id)
|
||||
elif "failed" in status_result.stdout:
|
||||
print(f"❌ Job failed")
|
||||
return None
|
||||
elif "running" in status_result.stdout:
|
||||
elapsed = int(time.time() - start_time)
|
||||
print(f" ⚙️ Processing... ({elapsed}s)")
|
||||
else:
|
||||
elapsed = int(time.time() - start_time)
|
||||
print(f" ⏳ Waiting in queue... ({elapsed}s)")
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
print(f"⏰ Timeout after {timeout}s")
|
||||
return None
|
||||
|
||||
def get_result(self, job_id):
|
||||
"""Get and display job result"""
|
||||
|
||||
print(f"📄 Job Result for {job_id}")
|
||||
print("=" * 60)
|
||||
|
||||
# In a real implementation, fetch from coordinator API
|
||||
# For now, simulate the result
|
||||
|
||||
# Get job details
|
||||
status_result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print("Job Details:")
|
||||
print(status_result.stdout)
|
||||
|
||||
print("\nGenerated Output:")
|
||||
print("-" * 40)
|
||||
|
||||
# Simulate different outputs based on job
|
||||
if "hello" in job_id.lower():
|
||||
print("Hello! 👋")
|
||||
print("I'm an AI assistant running on the AITBC network.")
|
||||
print("Your request was processed by a GPU miner in the network.")
|
||||
elif "blockchain" in job_id.lower():
|
||||
print("Blockchain is a distributed ledger technology that maintains")
|
||||
print("a secure and decentralized record of transactions across multiple")
|
||||
print("computers. It's the foundation of cryptocurrencies like Bitcoin")
|
||||
print("and has many other applications beyond digital currencies.")
|
||||
else:
|
||||
print("This is a sample response from the AITBC network.")
|
||||
print("The actual output would be generated by the GPU provider")
|
||||
print("based on your specific prompt and requirements.")
|
||||
|
||||
print("\nProcessing Details:")
|
||||
print("-" * 40)
|
||||
print(f"• Miner: GPU Provider")
|
||||
print(f"• Model: llama3.2:latest")
|
||||
print(f"• Tokens: ~25")
|
||||
print(f"• Cost: 0.000025 AITBC")
|
||||
print(f"• Network: AITBC")
|
||||
|
||||
return {
|
||||
"job_id": job_id,
|
||||
"status": "completed",
|
||||
"output": "Generated response from GPU provider"
|
||||
}
|
||||
|
||||
def pay_for_job(self, job_id, amount=25.0):
|
||||
"""Pay for a completed job"""
|
||||
|
||||
print(f"\n💸 Paying for job {job_id}...")
|
||||
|
||||
# Get miner address
|
||||
miner_result = subprocess.run(
|
||||
'cd miner && python3 wallet.py address',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
miner_address = None
|
||||
for line in miner_result.stdout.split('\n'):
|
||||
if "Miner Address:" in line:
|
||||
miner_address = line.split()[-1]
|
||||
break
|
||||
|
||||
if miner_address:
|
||||
# Send payment
|
||||
pay_result = subprocess.run(
|
||||
f'cd client && python3 wallet.py send {amount} {miner_address} "Payment for job {job_id}"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(pay_result.stdout)
|
||||
return True
|
||||
else:
|
||||
print("❌ Could not get miner address")
|
||||
return False
|
||||
|
||||
def main():
|
||||
client = AITBCClient()
|
||||
|
||||
print("🚀 AITBC Enhanced Client")
|
||||
print("=" * 60)
|
||||
|
||||
# Example 1: Submit and wait for result
|
||||
print("\n📝 Example 1: Submit job and wait for result")
|
||||
print("-" * 40)
|
||||
|
||||
result = client.submit_job("hello", wait_for_result=True)
|
||||
|
||||
if result:
|
||||
# Pay for the job
|
||||
client.pay_for_job(result["job_id"])
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ Complete workflow demonstrated!")
|
||||
print("\n💡 To use with your own prompt:")
|
||||
print(" python3 enhanced_client.py")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
109
scripts/examples/example_client_remote.py
Normal file
109
scripts/examples/example_client_remote.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Example client using the remote AITBC coordinator
|
||||
"""
|
||||
|
||||
import httpx
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Configuration - using the SSH tunnel to remote server
|
||||
COORDINATOR_URL = "http://localhost:8001"
|
||||
CLIENT_API_KEY = "${CLIENT_API_KEY}"
|
||||
|
||||
def create_job():
|
||||
"""Create a job on the remote coordinator"""
|
||||
job_data = {
|
||||
"payload": {
|
||||
"type": "inference",
|
||||
"task": "text-generation",
|
||||
"model": "llama-2-7b",
|
||||
"parameters": {
|
||||
"prompt": "Hello, AITBC!",
|
||||
"max_tokens": 100
|
||||
}
|
||||
},
|
||||
"ttl_seconds": 900
|
||||
}
|
||||
|
||||
with httpx.Client() as client:
|
||||
response = client.post(
|
||||
f"{COORDINATOR_URL}/v1/jobs",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-Api-Key": CLIENT_API_KEY
|
||||
},
|
||||
json=job_data
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
job = response.json()
|
||||
print(f"✅ Job created successfully!")
|
||||
print(f" Job ID: {job['job_id']}")
|
||||
print(f" State: {job['state']}")
|
||||
print(f" Expires at: {job['expires_at']}")
|
||||
return job['job_id']
|
||||
else:
|
||||
print(f"❌ Failed to create job: {response.status_code}")
|
||||
print(f" Response: {response.text}")
|
||||
return None
|
||||
|
||||
def check_job_status(job_id):
|
||||
"""Check the status of a job"""
|
||||
with httpx.Client() as client:
|
||||
response = client.get(
|
||||
f"{COORDINATOR_URL}/v1/jobs/{job_id}",
|
||||
headers={"X-Api-Key": CLIENT_API_KEY}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
job = response.json()
|
||||
print(f"\n📊 Job Status:")
|
||||
print(f" Job ID: {job['job_id']}")
|
||||
print(f" State: {job['state']}")
|
||||
print(f" Assigned Miner: {job.get('assigned_miner_id', 'None')}")
|
||||
print(f" Created: {job['requested_at']}")
|
||||
return job
|
||||
else:
|
||||
print(f"❌ Failed to get job status: {response.status_code}")
|
||||
return None
|
||||
|
||||
def list_blocks():
|
||||
"""List blocks from the explorer"""
|
||||
with httpx.Client() as client:
|
||||
response = client.get(f"{COORDINATOR_URL}/v1/explorer/blocks")
|
||||
|
||||
if response.status_code == 200:
|
||||
blocks = response.json()
|
||||
print(f"\n📦 Recent Blocks ({len(blocks['items'])} total):")
|
||||
for block in blocks['items'][:5]: # Show last 5 blocks
|
||||
print(f" Height: {block['height']}")
|
||||
print(f" Hash: {block['hash']}")
|
||||
print(f" Time: {block['timestamp']}")
|
||||
print(f" Transactions: {block['txCount']}")
|
||||
print(f" Proposer: {block['proposer']}")
|
||||
print()
|
||||
else:
|
||||
print(f"❌ Failed to list blocks: {response.status_code}")
|
||||
|
||||
def main():
|
||||
print("🚀 AITBC Remote Client Example")
|
||||
print(f" Connecting to: {COORDINATOR_URL}")
|
||||
print()
|
||||
|
||||
# List current blocks
|
||||
list_blocks()
|
||||
|
||||
# Create a new job
|
||||
job_id = create_job()
|
||||
|
||||
if job_id:
|
||||
# Check job status
|
||||
check_job_status(job_id)
|
||||
|
||||
# List blocks again to see the new job
|
||||
print("\n🔄 Updated block list:")
|
||||
list_blocks()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
85
scripts/examples/genesis.py
Executable file
85
scripts/examples/genesis.py
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Genesis wallet - Distributes initial AITBC from genesis block
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'cli'))
|
||||
from wallet import AITBCWallet
|
||||
|
||||
def main():
|
||||
print("🌍 GENESIS BLOCK - Initial AITBC Distribution")
|
||||
print("=" * 60)
|
||||
|
||||
# Create genesis wallet with large initial balance
|
||||
genesis = AITBCWallet("genesis_wallet.json")
|
||||
genesis.data["balance"] = 1000000.0 # 1 million AITBC
|
||||
genesis.data["transactions"] = [{
|
||||
"type": "genesis",
|
||||
"amount": 1000000.0,
|
||||
"description": "Genesis block creation",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}]
|
||||
genesis.save()
|
||||
|
||||
print(f"💰 Genesis Wallet Created")
|
||||
print(f" Address: {genesis.data['address']}")
|
||||
print(f" Balance: {genesis.data['balance']} AITBC")
|
||||
print()
|
||||
|
||||
# Distribute to client and miner
|
||||
client_wallet = AITBCWallet(os.path.join("client", "client_wallet.json"))
|
||||
miner_wallet = AITBCWallet(os.path.join("miner", "miner_wallet.json"))
|
||||
|
||||
print("📤 Distributing Initial AITBC")
|
||||
print("-" * 40)
|
||||
|
||||
# Give client 10,000 AITBC to spend
|
||||
client_address = client_wallet.data["address"]
|
||||
print(f"💸 Sending 10,000 AITBC to Client ({client_address[:20]}...)")
|
||||
client_wallet.add_earnings(10000.0, "genesis_distribution", "Initial funding from genesis block")
|
||||
|
||||
# Give miner 1,000 AITBC to start
|
||||
miner_address = miner_wallet.data["address"]
|
||||
print(f"💸 Sending 1,000 AITBC to Miner ({miner_address[:20]}...)")
|
||||
miner_wallet.add_earnings(1000.0, "genesis_distribution", "Initial funding from genesis block")
|
||||
|
||||
# Update genesis wallet
|
||||
genesis.data["balance"] -= 11000.0
|
||||
genesis.data["transactions"].extend([
|
||||
{
|
||||
"type": "transfer",
|
||||
"amount": -10000.0,
|
||||
"to": client_address,
|
||||
"description": "Initial client funding",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
},
|
||||
{
|
||||
"type": "transfer",
|
||||
"amount": -1000.0,
|
||||
"to": miner_address,
|
||||
"description": "Initial miner funding",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
])
|
||||
genesis.save()
|
||||
|
||||
print()
|
||||
print("✅ Distribution Complete!")
|
||||
print("=" * 60)
|
||||
print(f"Genesis Balance: {genesis.data['balance']} AITBC")
|
||||
print(f"Client Balance: {client_wallet.data['balance']} AITBC")
|
||||
print(f"Miner Balance: {miner_wallet.data['balance']} AITBC")
|
||||
print()
|
||||
print("💡 Next Steps:")
|
||||
print(" 1. Client: Submit jobs and pay for GPU services")
|
||||
print(" 2. Miner: Process jobs and earn AITBC")
|
||||
print(" 3. Track everything with the wallet CLI tools")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
144
scripts/examples/how_customer_gets_reply.py
Executable file
144
scripts/examples/how_customer_gets_reply.py
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Demonstration: How customers get replies from GPU providers
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
def main():
|
||||
print("📨 How Customers Get Replies in AITBC")
|
||||
print("=" * 60)
|
||||
|
||||
print("\n🔄 Complete Flow:")
|
||||
print("1. Customer submits job")
|
||||
print("2. GPU provider processes job")
|
||||
print("3. Result stored on blockchain")
|
||||
print("4. Customer retrieves result")
|
||||
print("5. Customer pays for service")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("\n📝 STEP 1: Customer Submits Job")
|
||||
print("-" * 40)
|
||||
|
||||
# Submit a job
|
||||
result = subprocess.run(
|
||||
'cd ../cli && python3 client.py submit inference --prompt "What is AI?"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
# Extract job ID
|
||||
job_id = None
|
||||
for line in result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
if not job_id:
|
||||
print("❌ Failed to submit job")
|
||||
return
|
||||
|
||||
print(f"\n✅ Job submitted with ID: {job_id}")
|
||||
|
||||
print("\n⚙️ STEP 2: GPU Provider Processes Job")
|
||||
print("-" * 40)
|
||||
print(" • Miner polls for jobs")
|
||||
print(" • Job assigned to miner")
|
||||
print(" • GPU processes the request")
|
||||
print(" • Result submitted to network")
|
||||
|
||||
# Simulate processing
|
||||
print("\n 💭 Simulating GPU processing...")
|
||||
time.sleep(2)
|
||||
|
||||
print("\n📦 STEP 3: Result Stored on Blockchain")
|
||||
print("-" * 40)
|
||||
print(f" • Job {job_id} marked as completed")
|
||||
print(f" • Result stored with job metadata")
|
||||
print(f" • Block created with job details")
|
||||
|
||||
# Show block
|
||||
print("\n 📋 Blockchain Entry:")
|
||||
print(f" Block Hash: {job_id}")
|
||||
print(f" Proposer: gpu-miner")
|
||||
print(f" Status: COMPLETED")
|
||||
print(f" Result: Available for retrieval")
|
||||
|
||||
print("\n🔍 STEP 4: Customer Retrieves Result")
|
||||
print("-" * 40)
|
||||
|
||||
print(" Method 1: Check job status")
|
||||
print(f" $ python3 cli/client.py status {job_id}")
|
||||
print()
|
||||
|
||||
# Show status
|
||||
status_result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py status {job_id}',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(" Status Result:")
|
||||
for line in status_result.stdout.split('\n'):
|
||||
if line.strip():
|
||||
print(f" {line}")
|
||||
|
||||
print("\n Method 2: Get full result")
|
||||
print(f" $ python3 client_get_result.py {job_id}")
|
||||
print()
|
||||
|
||||
print(" 📄 Full Result:")
|
||||
print(" ----------")
|
||||
print(" Output: AI stands for Artificial Intelligence, which refers")
|
||||
print(" to the simulation of human intelligence in machines")
|
||||
print(" that are programmed to think and learn.")
|
||||
print(" Tokens: 28")
|
||||
print(" Cost: 0.000028 AITBC")
|
||||
print(" Miner: GPU Provider #1")
|
||||
|
||||
print("\n💸 STEP 5: Customer Pays for Service")
|
||||
print("-" * 40)
|
||||
|
||||
# Get miner address
|
||||
miner_result = subprocess.run(
|
||||
'cd miner && python3 wallet.py address',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
miner_address = None
|
||||
for line in miner_result.stdout.split('\n'):
|
||||
if "Miner Address:" in line:
|
||||
miner_address = line.split()[-1]
|
||||
break
|
||||
|
||||
if miner_address:
|
||||
print(f" Payment sent to: {miner_address}")
|
||||
print(" Amount: 25.0 AITBC")
|
||||
print(" Status: ✅ Paid")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ Customer successfully received reply!")
|
||||
|
||||
print("\n📋 Summary of Retrieval Methods:")
|
||||
print("-" * 40)
|
||||
print("1. Job Status: python3 cli/client.py status <job_id>")
|
||||
print("2. Full Result: python3 client_get_result.py <job_id>")
|
||||
print("3. Watch Job: python3 client_get_result.py watch <job_id>")
|
||||
print("4. List Recent: python3 client_get_result.py list")
|
||||
print("5. Enhanced Client: python3 enhanced_client.py")
|
||||
|
||||
print("\n💡 In production:")
|
||||
print(" • Results are stored on-chain")
|
||||
print(" • Customers can retrieve anytime")
|
||||
print(" • Results are immutable and verifiable")
|
||||
print(" • Payment is required to unlock full results")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
113
scripts/examples/miner_wallet.py
Executable file
113
scripts/examples/miner_wallet.py
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
GPU Provider wallet for managing earnings from mining
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# Add parent directory to path to import wallet module
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location("wallet", os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "wallet.py"))
|
||||
wallet = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(wallet)
|
||||
AITBCWallet = wallet.AITBCWallet
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="GPU Provider Wallet - Manage earnings from mining services")
|
||||
parser.add_argument("--wallet", default="miner_wallet.json", help="Wallet file name")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
||||
|
||||
# Balance command
|
||||
balance_parser = subparsers.add_parser("balance", help="Show balance")
|
||||
|
||||
# Address command
|
||||
address_parser = subparsers.add_parser("address", help="Show wallet address")
|
||||
|
||||
# History command
|
||||
history_parser = subparsers.add_parser("history", help="Show transaction history")
|
||||
|
||||
# Earn command (receive payment for completed jobs)
|
||||
earn_parser = subparsers.add_parser("earn", help="Add earnings from completed job")
|
||||
earn_parser.add_argument("amount", type=float, help="Amount earned")
|
||||
earn_parser.add_argument("--job", required=True, help="Job ID that was completed")
|
||||
earn_parser.add_argument("--desc", default="GPU computation", help="Service description")
|
||||
|
||||
# Withdraw command
|
||||
withdraw_parser = subparsers.add_parser("withdraw", help="Withdraw AITBC to external wallet")
|
||||
withdraw_parser.add_argument("amount", type=float, help="Amount to withdraw")
|
||||
withdraw_parser.add_argument("address", help="Destination address")
|
||||
|
||||
# Stats command
|
||||
stats_parser = subparsers.add_parser("stats", help="Show mining statistics")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
# Use miner-specific wallet directory
|
||||
wallet_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
wallet_path = os.path.join(wallet_dir, args.wallet)
|
||||
|
||||
wallet = AITBCWallet(wallet_path)
|
||||
|
||||
if args.command == "balance":
|
||||
print("⛏️ GPU PROVIDER WALLET")
|
||||
print("=" * 40)
|
||||
wallet.show_balance()
|
||||
|
||||
# Show additional stats
|
||||
earnings = sum(t['amount'] for t in wallet.data['transactions'] if t['type'] == 'earn')
|
||||
jobs_completed = sum(1 for t in wallet.data['transactions'] if t['type'] == 'earn')
|
||||
print(f"\n📊 Mining Stats:")
|
||||
print(f" Total Earned: {earnings} AITBC")
|
||||
print(f" Jobs Completed: {jobs_completed}")
|
||||
print(f" Average per Job: {earnings/jobs_completed if jobs_completed > 0 else 0} AITBC")
|
||||
|
||||
elif args.command == "address":
|
||||
print(f"⛏️ Miner Address: {wallet.data['address']}")
|
||||
print(" Share this address to receive payments")
|
||||
|
||||
elif args.command == "history":
|
||||
print("⛏️ MINER TRANSACTION HISTORY")
|
||||
print("=" * 40)
|
||||
wallet.show_history()
|
||||
|
||||
elif args.command == "earn":
|
||||
print(f"💰 Adding earnings for job {args.job}")
|
||||
wallet.add_earnings(args.amount, args.job, args.desc)
|
||||
|
||||
elif args.command == "withdraw":
|
||||
print(f"💸 Withdrawing {args.amount} AITBC to {args.address}")
|
||||
wallet.spend(args.amount, f"Withdrawal to {args.address}")
|
||||
|
||||
elif args.command == "stats":
|
||||
print("⛏️ MINING STATISTICS")
|
||||
print("=" * 40)
|
||||
|
||||
transactions = wallet.data['transactions']
|
||||
earnings = [t for t in transactions if t['type'] == 'earn']
|
||||
spends = [t for t in transactions if t['type'] == 'spend']
|
||||
|
||||
total_earned = sum(t['amount'] for t in earnings)
|
||||
total_spent = sum(t['amount'] for t in spends)
|
||||
|
||||
print(f"💰 Total Earned: {total_earned} AITBC")
|
||||
print(f"💸 Total Spent: {total_spent} AITBC")
|
||||
print(f"💳 Net Balance: {wallet.data['balance']} AITBC")
|
||||
print(f"📊 Jobs Completed: {len(earnings)}")
|
||||
|
||||
if earnings:
|
||||
print(f"\n📈 Recent Earnings:")
|
||||
for earning in earnings[-5:]:
|
||||
print(f" +{earning['amount']} AITBC | Job: {earning.get('job_id', 'N/A')}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
42
scripts/examples/quick_job.py
Executable file
42
scripts/examples/quick_job.py
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Quick job submission and payment
|
||||
Usage: python3 quick_job.py "your prompt"
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 quick_job.py \"your prompt\"")
|
||||
sys.exit(1)
|
||||
|
||||
prompt = sys.argv[1]
|
||||
|
||||
print(f"🚀 Submitting job: '{prompt}'")
|
||||
|
||||
# Submit job
|
||||
result = subprocess.run(
|
||||
f'cd ../cli && python3 client.py submit inference --prompt "{prompt}"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Extract job ID
|
||||
job_id = None
|
||||
for line in result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
if job_id:
|
||||
print(f"✅ Job submitted: {job_id}")
|
||||
print("\n💡 Next steps:")
|
||||
print(f" 1. Start miner: python3 cli/miner.py mine")
|
||||
print(f" 2. Check status: python3 cli/client.py status {job_id}")
|
||||
print(f" 3. After completion, pay with:")
|
||||
print(f" cd home/client && python3 wallet.py send 25.0 $(cd home/miner && python3 wallet.py address | grep Address | cut -d' ' -f4) 'Payment for {job_id}'")
|
||||
else:
|
||||
print("❌ Failed to submit job")
|
||||
104
scripts/examples/simple_job_flow.py
Executable file
104
scripts/examples/simple_job_flow.py
Executable file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple job flow: Client -> GPU Provider -> Payment
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
def main():
|
||||
print("📋 AITBC Job Flow: Client -> GPU Provider -> Payment")
|
||||
print("=" * 60)
|
||||
|
||||
print("\n📝 STEP 1: Client submits job 'hello'")
|
||||
print("-" * 40)
|
||||
|
||||
# Submit job
|
||||
result = subprocess.run(
|
||||
'cd ../cli && python3 client.py demo',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
print(result.stdout)
|
||||
|
||||
# Extract job ID
|
||||
job_id = None
|
||||
if "Job ID:" in result.stdout:
|
||||
for line in result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
if not job_id:
|
||||
print("❌ Failed to submit job")
|
||||
return
|
||||
|
||||
print(f"\n📮 Job submitted: {job_id}")
|
||||
|
||||
print("\n⛏️ STEP 2: GPU Provider processes job")
|
||||
print("-" * 40)
|
||||
print(" (Start miner with: python3 cli/miner.py mine)")
|
||||
print(" The miner will automatically pick up the job")
|
||||
|
||||
# Simulate miner processing
|
||||
print("\n 💭 Simulating job processing...")
|
||||
time.sleep(2)
|
||||
|
||||
# Miner earns AITBC
|
||||
print(" ✅ Job processed!")
|
||||
print(" 💰 Miner earned 25 AITBC")
|
||||
|
||||
# Add to miner wallet
|
||||
subprocess.run(
|
||||
f'cd miner && python3 wallet.py earn 25.0 --job {job_id} --desc "Processed hello job"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print("\n💸 STEP 3: Client pays for service")
|
||||
print("-" * 40)
|
||||
|
||||
# Get miner address
|
||||
miner_result = subprocess.run(
|
||||
'cd miner && python3 wallet.py address',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
miner_address = None
|
||||
if "Miner Address:" in miner_result.stdout:
|
||||
for line in miner_result.stdout.split('\n'):
|
||||
if "Miner Address:" in line:
|
||||
miner_address = line.split()[-1]
|
||||
break
|
||||
|
||||
if miner_address:
|
||||
# Client pays
|
||||
subprocess.run(
|
||||
f'cd client && python3 wallet.py send 25.0 {miner_address} "Payment for job {job_id}"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print("\n📊 STEP 4: Final balances")
|
||||
print("-" * 40)
|
||||
|
||||
print("\n Client Wallet:")
|
||||
subprocess.run('cd client && python3 wallet.py balance', shell=True)
|
||||
|
||||
print("\n Miner Wallet:")
|
||||
subprocess.run('cd miner && python3 wallet.py balance', shell=True)
|
||||
|
||||
print("\n✅ Complete workflow demonstrated!")
|
||||
print("\n💡 To run with real GPU processing:")
|
||||
print(" 1. Start miner: python3 cli/miner.py mine")
|
||||
print(" 2. Submit job: python3 cli/client.py submit inference --prompt 'hello'")
|
||||
print(" 3. Check status: python3 cli/client.py status <job_id>")
|
||||
print(" 4. Pay manually: cd home/client && python3 wallet.py send <amount> <miner_address>")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
136
scripts/examples/simulate.py
Executable file
136
scripts/examples/simulate.py
Executable file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complete simulation: Client pays for GPU services, Miner earns AITBC
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
def run_wallet_command(wallet_type, command, description):
|
||||
"""Run a wallet command and display results"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"💼 {wallet_type}: {description}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
wallet_dir = os.path.join(os.path.dirname(__file__), wallet_type.lower())
|
||||
cmd = f"cd {wallet_dir} && python3 wallet.py {command}"
|
||||
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
print(result.stdout)
|
||||
|
||||
if result.stderr:
|
||||
print(f"Error: {result.stderr}")
|
||||
|
||||
return result
|
||||
|
||||
def main():
|
||||
print("🎭 AITBC Local Simulation")
|
||||
print("=" * 60)
|
||||
print("Simulating client and GPU provider interactions")
|
||||
print()
|
||||
|
||||
# Step 1: Initialize wallets with genesis distribution
|
||||
print("📋 STEP 1: Initialize Wallets")
|
||||
os.system("cd /home/oib/windsurf/aitbc/home && python3 genesis.py")
|
||||
|
||||
input("\nPress Enter to continue...")
|
||||
|
||||
# Step 2: Check initial balances
|
||||
print("\n📋 STEP 2: Check Initial Balances")
|
||||
run_wallet_command("Client", "balance", "Initial client balance")
|
||||
run_wallet_command("Miner", "balance", "Initial miner balance")
|
||||
|
||||
input("\nPress Enter to continue...")
|
||||
|
||||
# Step 3: Client submits a job (using CLI tool)
|
||||
print("\n📋 STEP 3: Client Submits Job")
|
||||
print("-" * 40)
|
||||
|
||||
# Submit job to coordinator
|
||||
result = subprocess.run(
|
||||
"cd /home/oib/windsurf/aitbc/cli && python3 client.py submit inference --model llama-2-7b --prompt 'What is the future of AI?'",
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
# Extract job ID if successful
|
||||
job_id = None
|
||||
if "Job ID:" in result.stdout:
|
||||
for line in result.stdout.split('\n'):
|
||||
if "Job ID:" in line:
|
||||
job_id = line.split()[-1]
|
||||
break
|
||||
|
||||
input("\nPress Enter to continue...")
|
||||
|
||||
# Step 4: Miner processes the job
|
||||
print("\n📋 STEP 4: Miner Processes Job")
|
||||
print("-" * 40)
|
||||
|
||||
if job_id:
|
||||
print(f"⛏️ Miner found job: {job_id}")
|
||||
print("⚙️ Processing job...")
|
||||
time.sleep(2)
|
||||
|
||||
# Miner earns AITBC for completing the job
|
||||
run_wallet_command(
|
||||
"Miner",
|
||||
f"earn 50.0 --job {job_id} --desc 'Inference task completed'",
|
||||
"Miner earns AITBC"
|
||||
)
|
||||
|
||||
input("\nPress Enter to continue...")
|
||||
|
||||
# Step 5: Client pays for the service
|
||||
print("\n📋 STEP 5: Client Pays for Service")
|
||||
print("-" * 40)
|
||||
|
||||
if job_id:
|
||||
# Get miner address
|
||||
miner_result = subprocess.run(
|
||||
"cd /home/oib/windsurf/aitbc/home/miner && python3 wallet.py address",
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
miner_address = None
|
||||
if "Miner Address:" in miner_result.stdout:
|
||||
for line in miner_result.stdout.split('\n'):
|
||||
if "Miner Address:" in line:
|
||||
miner_address = line.split()[-1]
|
||||
break
|
||||
|
||||
if miner_address:
|
||||
run_wallet_command(
|
||||
"Client",
|
||||
f"send 50.0 {miner_address} 'Payment for inference job {job_id}'",
|
||||
"Client pays for completed job"
|
||||
)
|
||||
|
||||
input("\nPress Enter to continue...")
|
||||
|
||||
# Step 6: Check final balances
|
||||
print("\n📋 STEP 6: Final Balances")
|
||||
run_wallet_command("Client", "balance", "Final client balance")
|
||||
run_wallet_command("Miner", "balance", "Final miner balance")
|
||||
|
||||
print("\n🎉 Simulation Complete!")
|
||||
print("=" * 60)
|
||||
print("Summary:")
|
||||
print(" • Client submitted job and paid 50 AITBC")
|
||||
print(" • Miner processed job and earned 50 AITBC")
|
||||
print(" • Transaction recorded on blockchain")
|
||||
print()
|
||||
print("💡 You can:")
|
||||
print(" • Run 'cd home/client && python3 wallet.py history' to see client transactions")
|
||||
print(" • Run 'cd home/miner && python3 wallet.py stats' to see miner earnings")
|
||||
print(" • Submit more jobs with the CLI tools")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
158
scripts/examples/wallet.py
Executable file
158
scripts/examples/wallet.py
Executable file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
AITBC Wallet CLI Tool - Track earnings and manage wallet
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Dict, List
|
||||
|
||||
class AITBCWallet:
|
||||
def __init__(self, wallet_file: str = None):
|
||||
if wallet_file is None:
|
||||
wallet_file = os.path.expanduser("~/.aitbc_wallet.json")
|
||||
|
||||
self.wallet_file = wallet_file
|
||||
self.data = self._load_wallet()
|
||||
|
||||
def _load_wallet(self) -> dict:
|
||||
"""Load wallet data from file"""
|
||||
if os.path.exists(self.wallet_file):
|
||||
try:
|
||||
with open(self.wallet_file, 'r') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Create new wallet
|
||||
return {
|
||||
"address": "aitbc1" + os.urandom(10).hex(),
|
||||
"balance": 0.0,
|
||||
"transactions": [],
|
||||
"created_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
def save(self):
|
||||
"""Save wallet to file"""
|
||||
with open(self.wallet_file, 'w') as f:
|
||||
json.dump(self.data, f, indent=2)
|
||||
|
||||
def add_earnings(self, amount: float, job_id: str, description: str = ""):
|
||||
"""Add earnings from completed job"""
|
||||
transaction = {
|
||||
"type": "earn",
|
||||
"amount": amount,
|
||||
"job_id": job_id,
|
||||
"description": description or f"Job {job_id}",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
self.data["transactions"].append(transaction)
|
||||
self.data["balance"] += amount
|
||||
self.save()
|
||||
|
||||
print(f"💰 Added {amount} AITBC to wallet")
|
||||
print(f" New balance: {self.data['balance']} AITBC")
|
||||
|
||||
def spend(self, amount: float, description: str):
|
||||
"""Spend AITBC"""
|
||||
if self.data["balance"] < amount:
|
||||
print(f"❌ Insufficient balance!")
|
||||
print(f" Balance: {self.data['balance']} AITBC")
|
||||
print(f" Needed: {amount} AITBC")
|
||||
return False
|
||||
|
||||
transaction = {
|
||||
"type": "spend",
|
||||
"amount": -amount,
|
||||
"description": description,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
self.data["transactions"].append(transaction)
|
||||
self.data["balance"] -= amount
|
||||
self.save()
|
||||
|
||||
print(f"💸 Spent {amount} AITBC")
|
||||
print(f" Remaining: {self.data['balance']} AITBC")
|
||||
return True
|
||||
|
||||
def show_balance(self):
|
||||
"""Show wallet balance"""
|
||||
print(f"💳 Wallet Address: {self.data['address']}")
|
||||
print(f"💰 Balance: {self.data['balance']} AITBC")
|
||||
print(f"📊 Total Transactions: {len(self.data['transactions'])}")
|
||||
|
||||
def show_history(self, limit: int = 10):
|
||||
"""Show transaction history"""
|
||||
transactions = self.data["transactions"][-limit:]
|
||||
|
||||
if not transactions:
|
||||
print("📭 No transactions yet")
|
||||
return
|
||||
|
||||
print(f"📜 Recent Transactions (last {limit}):")
|
||||
print("-" * 60)
|
||||
|
||||
for tx in reversed(transactions):
|
||||
symbol = "💰" if tx["type"] == "earn" else "💸"
|
||||
print(f"{symbol} {tx['amount']:+8.2f} AITBC | {tx.get('description', 'N/A')}")
|
||||
print(f" 📅 {tx['timestamp']}")
|
||||
if "job_id" in tx:
|
||||
print(f" 🆔 Job: {tx['job_id']}")
|
||||
print()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="AITBC Wallet CLI")
|
||||
parser.add_argument("--wallet", help="Wallet file path")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
||||
|
||||
# Balance command
|
||||
balance_parser = subparsers.add_parser("balance", help="Show balance")
|
||||
|
||||
# History command
|
||||
history_parser = subparsers.add_parser("history", help="Show transaction history")
|
||||
history_parser.add_argument("--limit", type=int, default=10, help="Number of transactions")
|
||||
|
||||
# Earn command
|
||||
earn_parser = subparsers.add_parser("earn", help="Add earnings")
|
||||
earn_parser.add_argument("amount", type=float, help="Amount earned")
|
||||
earn_parser.add_argument("--job", help="Job ID")
|
||||
earn_parser.add_argument("--desc", help="Description")
|
||||
|
||||
# Spend command
|
||||
spend_parser = subparsers.add_parser("spend", help="Spend AITBC")
|
||||
spend_parser.add_argument("amount", type=float, help="Amount to spend")
|
||||
spend_parser.add_argument("description", help="What you're spending on")
|
||||
|
||||
# Address command
|
||||
address_parser = subparsers.add_parser("address", help="Show wallet address")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
wallet = AITBCWallet(args.wallet)
|
||||
|
||||
if args.command == "balance":
|
||||
wallet.show_balance()
|
||||
|
||||
elif args.command == "history":
|
||||
wallet.show_history(args.limit)
|
||||
|
||||
elif args.command == "earn":
|
||||
wallet.add_earnings(args.amount, args.job or "unknown", args.desc or "")
|
||||
|
||||
elif args.command == "spend":
|
||||
wallet.spend(args.amount, args.description)
|
||||
|
||||
elif args.command == "address":
|
||||
print(f"💳 Wallet Address: {wallet.data['address']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complete miner workflow - poll for jobs and assign proposer
|
||||
"""
|
||||
|
||||
import httpx
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
# Configuration
|
||||
COORDINATOR_URL = "http://localhost:8001"
|
||||
MINER_API_KEY = "${MINER_API_KEY}"
|
||||
MINER_ID = "localhost-gpu-miner"
|
||||
|
||||
def poll_and_accept_job():
|
||||
"""Poll for a job and accept it"""
|
||||
print("🔍 Polling for jobs...")
|
||||
|
||||
with httpx.Client() as client:
|
||||
# Poll for a job
|
||||
response = client.post(
|
||||
f"{COORDINATOR_URL}/v1/miners/poll",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-Api-Key": MINER_API_KEY
|
||||
},
|
||||
json={"max_wait_seconds": 5}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
job = response.json()
|
||||
print(f"✅ Received job: {job['job_id']}")
|
||||
print(f" Task: {job['payload'].get('task', 'unknown')}")
|
||||
|
||||
# Simulate processing
|
||||
print("⚙️ Processing job...")
|
||||
time.sleep(2)
|
||||
|
||||
# Submit result
|
||||
result_data = {
|
||||
"result": {
|
||||
"status": "completed",
|
||||
"output": f"Job {job['job_id']} completed successfully",
|
||||
"execution_time_ms": 2000,
|
||||
"miner_id": MINER_ID
|
||||
},
|
||||
"metrics": {
|
||||
"compute_time": 2.0,
|
||||
"energy_used": 0.1
|
||||
}
|
||||
}
|
||||
|
||||
print(f"📤 Submitting result for job {job['job_id']}...")
|
||||
result_response = client.post(
|
||||
f"{COORDINATOR_URL}/v1/miners/{job['job_id']}/result",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"X-Api-Key": MINER_API_KEY
|
||||
},
|
||||
json=result_data
|
||||
)
|
||||
|
||||
if result_response.status_code == 200:
|
||||
print("✅ Result submitted successfully!")
|
||||
return job['job_id']
|
||||
else:
|
||||
print(f"❌ Failed to submit result: {result_response.status_code}")
|
||||
print(f" Response: {result_response.text}")
|
||||
return None
|
||||
|
||||
elif response.status_code == 204:
|
||||
print("ℹ️ No jobs available")
|
||||
return None
|
||||
else:
|
||||
print(f"❌ Failed to poll: {response.status_code}")
|
||||
return None
|
||||
|
||||
def check_block_proposer(job_id):
|
||||
"""Check if the block now has a proposer"""
|
||||
print(f"\n🔍 Checking proposer for job {job_id}...")
|
||||
|
||||
with httpx.Client() as client:
|
||||
response = client.get(f"{COORDINATOR_URL}/v1/explorer/blocks")
|
||||
|
||||
if response.status_code == 200:
|
||||
blocks = response.json()
|
||||
for block in blocks['items']:
|
||||
if block['hash'] == job_id:
|
||||
print(f"📦 Block Info:")
|
||||
print(f" Height: {block['height']}")
|
||||
print(f" Hash: {block['hash']}")
|
||||
print(f" Proposer: {block['proposer']}")
|
||||
print(f" Time: {block['timestamp']}")
|
||||
return block
|
||||
return None
|
||||
|
||||
def main():
|
||||
print("⛏️ AITBC Miner Workflow Demo")
|
||||
print(f" Miner ID: {MINER_ID}")
|
||||
print(f" Coordinator: {COORDINATOR_URL}")
|
||||
print()
|
||||
|
||||
# Poll and accept a job
|
||||
job_id = poll_and_accept_job()
|
||||
|
||||
if job_id:
|
||||
# Check if the block has a proposer now
|
||||
time.sleep(1) # Give the server a moment to update
|
||||
check_block_proposer(job_id)
|
||||
else:
|
||||
print("\n💡 Tip: Create a job first using example_client_remote.py")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user