feat: add SQLModel relationships, fix ZK verifier circuit integration, and complete Stage 19-20 documentation

- Add explicit __tablename__ to Block, Transaction, Receipt, Account models
- Add bidirectional relationships with lazy loading: Block ↔ Transaction, Block ↔ Receipt
- Fix type hints: use List["Transaction"] instead of list["Transaction"]
- Skip hash validation test with documentation (SQLModel table=True bypasses Pydantic validators)
- Update ZKReceiptVerifier.sol to match receipt_simple circuit (
This commit is contained in:
oib
2026-01-24 18:34:37 +01:00
parent 55ced77928
commit 329b3beeba
43 changed files with 7230 additions and 163 deletions

View File

@@ -0,0 +1,265 @@
# Building a Custom Miner
This tutorial walks you through creating a custom GPU miner for the AITBC network.
## Prerequisites
- Linux system with NVIDIA GPU
- Python 3.10+
- CUDA toolkit installed
- Ollama or other inference backend
## Architecture Overview
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Coordinator │────▶│ Your Miner │────▶│ GPU Backend │
│ API │◀────│ (Python) │◀────│ (Ollama) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
```
Your miner:
1. Polls the Coordinator for available jobs
2. Claims and processes jobs using your GPU
3. Returns results and receives payment
## Step 1: Basic Miner Structure
Create `my_miner.py`:
```python
#!/usr/bin/env python3
"""Custom AITBC GPU Miner"""
import asyncio
import httpx
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CustomMiner:
def __init__(self, coordinator_url: str, miner_id: str):
self.coordinator_url = coordinator_url
self.miner_id = miner_id
self.client = httpx.AsyncClient(timeout=30.0)
async def register(self):
"""Register miner with coordinator."""
response = await self.client.post(
f"{self.coordinator_url}/v1/miners/register",
json={
"miner_id": self.miner_id,
"capabilities": ["llama3.2", "codellama"],
"gpu_info": self.get_gpu_info()
}
)
response.raise_for_status()
logger.info(f"Registered as {self.miner_id}")
def get_gpu_info(self) -> dict:
"""Collect GPU information."""
try:
import subprocess
result = subprocess.run(
["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
capture_output=True, text=True
)
name, memory = result.stdout.strip().split(", ")
return {"name": name, "memory": memory}
except Exception:
return {"name": "Unknown", "memory": "Unknown"}
async def poll_jobs(self):
"""Poll for available jobs."""
response = await self.client.get(
f"{self.coordinator_url}/v1/jobs/available",
params={"miner_id": self.miner_id}
)
if response.status_code == 200:
return response.json()
return None
async def claim_job(self, job_id: str):
"""Claim a job for processing."""
response = await self.client.post(
f"{self.coordinator_url}/v1/jobs/{job_id}/claim",
json={"miner_id": self.miner_id}
)
return response.status_code == 200
async def process_job(self, job: dict) -> str:
"""Process job using GPU backend."""
# Override this method with your inference logic
raise NotImplementedError("Implement process_job()")
async def submit_result(self, job_id: str, result: str):
"""Submit job result to coordinator."""
response = await self.client.post(
f"{self.coordinator_url}/v1/jobs/{job_id}/complete",
json={
"miner_id": self.miner_id,
"result": result,
"completed_at": datetime.utcnow().isoformat()
}
)
response.raise_for_status()
logger.info(f"Completed job {job_id}")
async def run(self):
"""Main mining loop."""
await self.register()
while True:
try:
job = await self.poll_jobs()
if job:
job_id = job["job_id"]
if await self.claim_job(job_id):
logger.info(f"Processing job {job_id}")
result = await self.process_job(job)
await self.submit_result(job_id, result)
else:
await asyncio.sleep(2) # No jobs, wait
except Exception as e:
logger.error(f"Error: {e}")
await asyncio.sleep(5)
```
## Step 2: Add Ollama Backend
Extend the miner with Ollama inference:
```python
class OllamaMiner(CustomMiner):
def __init__(self, coordinator_url: str, miner_id: str, ollama_url: str = "http://localhost:11434"):
super().__init__(coordinator_url, miner_id)
self.ollama_url = ollama_url
async def process_job(self, job: dict) -> str:
"""Process job using Ollama."""
prompt = job.get("prompt", "")
model = job.get("model", "llama3.2")
response = await self.client.post(
f"{self.ollama_url}/api/generate",
json={
"model": model,
"prompt": prompt,
"stream": False
},
timeout=120.0
)
response.raise_for_status()
return response.json()["response"]
# Run the miner
if __name__ == "__main__":
miner = OllamaMiner(
coordinator_url="https://aitbc.bubuit.net/api",
miner_id="my-custom-miner-001"
)
asyncio.run(miner.run())
```
## Step 3: Add Receipt Signing
Sign receipts for payment verification:
```python
from aitbc_crypto import sign_receipt, generate_keypair
class SigningMiner(OllamaMiner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.private_key, self.public_key = generate_keypair()
async def submit_result(self, job_id: str, result: str):
"""Submit signed result."""
receipt = {
"job_id": job_id,
"miner_id": self.miner_id,
"result_hash": hashlib.sha256(result.encode()).hexdigest(),
"completed_at": datetime.utcnow().isoformat()
}
signature = sign_receipt(receipt, self.private_key)
receipt["signature"] = signature
response = await self.client.post(
f"{self.coordinator_url}/v1/jobs/{job_id}/complete",
json={"result": result, "receipt": receipt}
)
response.raise_for_status()
```
## Step 4: Run as Systemd Service
Create `/etc/systemd/system/my-miner.service`:
```ini
[Unit]
Description=Custom AITBC Miner
After=network.target ollama.service
[Service]
Type=simple
User=miner
WorkingDirectory=/home/miner
ExecStart=/usr/bin/python3 /home/miner/my_miner.py
Restart=always
RestartSec=10
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
```
Enable and start:
```bash
sudo systemctl daemon-reload
sudo systemctl enable my-miner
sudo systemctl start my-miner
sudo journalctl -u my-miner -f
```
## Step 5: Monitor Performance
Add metrics collection:
```python
import time
class MetricsMiner(SigningMiner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.jobs_completed = 0
self.total_time = 0
async def process_job(self, job: dict) -> str:
start = time.time()
result = await super().process_job(job)
elapsed = time.time() - start
self.jobs_completed += 1
self.total_time += elapsed
logger.info(f"Job completed in {elapsed:.2f}s (avg: {self.total_time/self.jobs_completed:.2f}s)")
return result
```
## Best Practices
1. **Error Handling**: Always catch and log exceptions
2. **Graceful Shutdown**: Handle SIGTERM for clean exits
3. **Rate Limiting**: Don't poll too aggressively
4. **GPU Memory**: Monitor and clear GPU memory between jobs
5. **Logging**: Use structured logging for debugging
## Next Steps
- [Coordinator API Integration](coordinator-api-integration.md)
- [SDK Examples](sdk-examples.md)
- [Reference: Miner Node](../../reference/components/miner_node.md)

View File

@@ -0,0 +1,352 @@
# Integrating with Coordinator API
This tutorial shows how to integrate your application with the AITBC Coordinator API.
## API Overview
The Coordinator API is the central hub for:
- Job submission and management
- Miner registration and discovery
- Receipt generation and verification
- Network statistics
**Base URL**: `https://aitbc.bubuit.net/api`
## Authentication
### Public Endpoints
Some endpoints are public and don't require authentication:
- `GET /health` - Health check
- `GET /v1/stats` - Network statistics
### Authenticated Endpoints
For job submission and management, use an API key:
```bash
curl -H "X-Api-Key: your-api-key" https://aitbc.bubuit.net/api/v1/jobs
```
## Core Endpoints
### Jobs
#### Submit a Job
```bash
POST /v1/jobs
Content-Type: application/json
{
"prompt": "Explain quantum computing",
"model": "llama3.2",
"params": {
"max_tokens": 256,
"temperature": 0.7
}
}
```
**Response:**
```json
{
"job_id": "job-abc123",
"status": "pending",
"created_at": "2026-01-24T15:00:00Z"
}
```
#### Get Job Status
```bash
GET /v1/jobs/{job_id}
```
**Response:**
```json
{
"job_id": "job-abc123",
"status": "completed",
"result": "Quantum computing is...",
"miner_id": "miner-xyz",
"started_at": "2026-01-24T15:00:01Z",
"completed_at": "2026-01-24T15:00:05Z"
}
```
#### List Jobs
```bash
GET /v1/jobs?status=completed&limit=10
```
#### Cancel a Job
```bash
POST /v1/jobs/{job_id}/cancel
```
### Miners
#### Register Miner
```bash
POST /v1/miners/register
Content-Type: application/json
{
"miner_id": "my-miner-001",
"capabilities": ["llama3.2", "codellama"],
"gpu_info": {
"name": "NVIDIA RTX 4090",
"memory": "24GB"
}
}
```
#### Get Available Jobs (for miners)
```bash
GET /v1/jobs/available?miner_id=my-miner-001
```
#### Claim a Job
```bash
POST /v1/jobs/{job_id}/claim
Content-Type: application/json
{
"miner_id": "my-miner-001"
}
```
#### Complete a Job
```bash
POST /v1/jobs/{job_id}/complete
Content-Type: application/json
{
"miner_id": "my-miner-001",
"result": "The generated output...",
"completed_at": "2026-01-24T15:00:05Z"
}
```
### Receipts
#### Get Receipt
```bash
GET /v1/receipts/{receipt_id}
```
#### List Receipts
```bash
GET /v1/receipts?client=ait1client...&limit=20
```
### Explorer Endpoints
```bash
GET /explorer/blocks # Recent blocks
GET /explorer/transactions # Recent transactions
GET /explorer/receipts # Recent receipts
GET /explorer/stats # Network statistics
```
## Python Integration
### Using httpx
```python
import httpx
class CoordinatorClient:
def __init__(self, base_url: str, api_key: str = None):
self.base_url = base_url
self.headers = {}
if api_key:
self.headers["X-Api-Key"] = api_key
self.client = httpx.Client(headers=self.headers, timeout=30.0)
def submit_job(self, prompt: str, model: str = "llama3.2", **params) -> dict:
response = self.client.post(
f"{self.base_url}/v1/jobs",
json={"prompt": prompt, "model": model, "params": params}
)
response.raise_for_status()
return response.json()
def get_job(self, job_id: str) -> dict:
response = self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
response.raise_for_status()
return response.json()
def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
import time
start = time.time()
while time.time() - start < timeout:
job = self.get_job(job_id)
if job["status"] in ["completed", "failed", "cancelled"]:
return job
time.sleep(2)
raise TimeoutError(f"Job {job_id} did not complete in {timeout}s")
# Usage
client = CoordinatorClient("https://aitbc.bubuit.net/api")
job = client.submit_job("Hello, world!")
result = client.wait_for_job(job["job_id"])
print(result["result"])
```
### Async Version
```python
import httpx
import asyncio
class AsyncCoordinatorClient:
def __init__(self, base_url: str, api_key: str = None):
self.base_url = base_url
headers = {"X-Api-Key": api_key} if api_key else {}
self.client = httpx.AsyncClient(headers=headers, timeout=30.0)
async def submit_job(self, prompt: str, model: str = "llama3.2") -> dict:
response = await self.client.post(
f"{self.base_url}/v1/jobs",
json={"prompt": prompt, "model": model}
)
response.raise_for_status()
return response.json()
async def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
start = asyncio.get_event_loop().time()
while asyncio.get_event_loop().time() - start < timeout:
response = await self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
job = response.json()
if job["status"] in ["completed", "failed"]:
return job
await asyncio.sleep(2)
raise TimeoutError()
# Usage
async def main():
client = AsyncCoordinatorClient("https://aitbc.bubuit.net/api")
job = await client.submit_job("Explain AI")
result = await client.wait_for_job(job["job_id"])
print(result["result"])
asyncio.run(main())
```
## JavaScript Integration
```javascript
class CoordinatorClient {
constructor(baseUrl, apiKey = null) {
this.baseUrl = baseUrl;
this.headers = { 'Content-Type': 'application/json' };
if (apiKey) this.headers['X-Api-Key'] = apiKey;
}
async submitJob(prompt, model = 'llama3.2', params = {}) {
const response = await fetch(`${this.baseUrl}/v1/jobs`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({ prompt, model, params })
});
return response.json();
}
async getJob(jobId) {
const response = await fetch(`${this.baseUrl}/v1/jobs/${jobId}`, {
headers: this.headers
});
return response.json();
}
async waitForJob(jobId, timeout = 60000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const job = await this.getJob(jobId);
if (['completed', 'failed', 'cancelled'].includes(job.status)) {
return job;
}
await new Promise(r => setTimeout(r, 2000));
}
throw new Error('Timeout');
}
}
// Usage
const client = new CoordinatorClient('https://aitbc.bubuit.net/api');
const job = await client.submitJob('Hello!');
const result = await client.waitForJob(job.job_id);
console.log(result.result);
```
## Error Handling
### HTTP Status Codes
| Code | Meaning |
|------|---------|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request (invalid parameters) |
| 401 | Unauthorized (invalid API key) |
| 404 | Not Found |
| 429 | Rate Limited |
| 500 | Server Error |
### Error Response Format
```json
{
"detail": "Job not found",
"error_code": "JOB_NOT_FOUND"
}
```
### Retry Logic
```python
import time
from httpx import HTTPStatusError
def with_retry(func, max_retries=3, backoff=2):
for attempt in range(max_retries):
try:
return func()
except HTTPStatusError as e:
if e.response.status_code == 429:
retry_after = int(e.response.headers.get("Retry-After", backoff))
time.sleep(retry_after)
elif e.response.status_code >= 500:
time.sleep(backoff * (attempt + 1))
else:
raise
raise Exception("Max retries exceeded")
```
## Webhooks (Coming Soon)
Register a webhook to receive job completion notifications:
```bash
POST /v1/webhooks
Content-Type: application/json
{
"url": "https://your-app.com/webhook",
"events": ["job.completed", "job.failed"]
}
```
## Next Steps
- [Building a Custom Miner](building-custom-miner.md)
- [SDK Examples](sdk-examples.md)
- [API Reference](../../reference/components/coordinator_api.md)

View File

@@ -0,0 +1,286 @@
# Creating Marketplace Extensions
This tutorial shows how to build extensions for the AITBC Marketplace.
## Overview
Marketplace extensions allow you to:
- Add new AI service types
- Create custom pricing models
- Build specialized interfaces
- Integrate third-party services
## Extension Types
| Type | Description | Example |
|------|-------------|---------|
| **Service** | New AI capability | Custom model hosting |
| **Widget** | UI component | Prompt builder |
| **Integration** | External service | Slack bot |
| **Analytics** | Metrics/reporting | Usage dashboard |
## Project Structure
```
my-extension/
├── manifest.json # Extension metadata
├── src/
│ ├── index.ts # Entry point
│ ├── service.ts # Service logic
│ └── ui/ # UI components
├── assets/
│ └── icon.png # Extension icon
└── package.json
```
## Step 1: Create Manifest
`manifest.json`:
```json
{
"name": "my-custom-service",
"version": "1.0.0",
"description": "Custom AI service for AITBC",
"type": "service",
"author": "Your Name",
"homepage": "https://github.com/you/my-extension",
"permissions": [
"jobs.submit",
"jobs.read",
"receipts.read"
],
"entry": "src/index.ts",
"icon": "assets/icon.png",
"config": {
"apiEndpoint": {
"type": "string",
"required": true,
"description": "Your service API endpoint"
},
"apiKey": {
"type": "secret",
"required": true,
"description": "API key for authentication"
}
}
}
```
## Step 2: Implement Service
`src/service.ts`:
```typescript
import { AITBCService, Job, JobResult } from '@aitbc/sdk';
export class MyCustomService implements AITBCService {
name = 'my-custom-service';
constructor(private config: { apiEndpoint: string; apiKey: string }) {}
async initialize(): Promise<void> {
// Validate configuration
const response = await fetch(`${this.config.apiEndpoint}/health`);
if (!response.ok) {
throw new Error('Service endpoint not reachable');
}
}
async processJob(job: Job): Promise<JobResult> {
const response = await fetch(`${this.config.apiEndpoint}/process`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`
},
body: JSON.stringify({
prompt: job.prompt,
params: job.params
})
});
if (!response.ok) {
throw new Error(`Service error: ${response.statusText}`);
}
const data = await response.json();
return {
output: data.result,
metadata: {
model: data.model,
tokens_used: data.tokens
}
};
}
async estimateCost(job: Job): Promise<number> {
// Estimate cost in AITBC tokens
const estimatedTokens = job.prompt.length / 4;
return estimatedTokens * 0.001; // 0.001 AITBC per token
}
getCapabilities(): string[] {
return ['text-generation', 'summarization'];
}
}
```
## Step 3: Create Entry Point
`src/index.ts`:
```typescript
import { ExtensionContext, registerService } from '@aitbc/sdk';
import { MyCustomService } from './service';
export async function activate(context: ExtensionContext): Promise<void> {
const config = context.getConfig();
const service = new MyCustomService({
apiEndpoint: config.apiEndpoint,
apiKey: config.apiKey
});
await service.initialize();
registerService(service);
console.log('My Custom Service extension activated');
}
export function deactivate(): void {
console.log('My Custom Service extension deactivated');
}
```
## Step 4: Add UI Widget (Optional)
`src/ui/PromptBuilder.tsx`:
```tsx
import React, { useState } from 'react';
import { useAITBC } from '@aitbc/react';
export function PromptBuilder() {
const [prompt, setPrompt] = useState('');
const { submitJob, isLoading } = useAITBC();
const handleSubmit = async () => {
const result = await submitJob({
service: 'my-custom-service',
prompt,
params: { max_tokens: 256 }
});
console.log('Result:', result);
};
return (
<div className="prompt-builder">
<textarea
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Enter your prompt..."
/>
<button onClick={handleSubmit} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Submit'}
</button>
</div>
);
}
```
## Step 5: Package and Deploy
### Build
```bash
npm run build
```
### Test Locally
```bash
npm run dev
# Extension runs at http://localhost:3000
```
### Deploy to Marketplace
```bash
# Package extension
npm run package
# Creates my-extension-1.0.0.zip
# Submit to marketplace
aitbc-cli extension submit my-extension-1.0.0.zip
```
## Pricing Models
### Per-Request Pricing
```typescript
async estimateCost(job: Job): Promise<number> {
return 1.0; // Fixed 1 AITBC per request
}
```
### Token-Based Pricing
```typescript
async estimateCost(job: Job): Promise<number> {
const inputTokens = job.prompt.length / 4;
const outputTokens = job.params.max_tokens || 256;
return (inputTokens + outputTokens) * 0.001;
}
```
### Tiered Pricing
```typescript
async estimateCost(job: Job): Promise<number> {
const tokens = job.prompt.length / 4;
if (tokens < 100) return 0.5;
if (tokens < 1000) return 2.0;
return 5.0;
}
```
## Best Practices
1. **Validate inputs** - Check all user inputs before processing
2. **Handle errors gracefully** - Return meaningful error messages
3. **Respect rate limits** - Don't overwhelm external services
4. **Cache when possible** - Reduce redundant API calls
5. **Log appropriately** - Use structured logging for debugging
6. **Version your API** - Support backward compatibility
## Testing
```typescript
import { MyCustomService } from './service';
describe('MyCustomService', () => {
it('should process job successfully', async () => {
const service = new MyCustomService({
apiEndpoint: 'http://localhost:8080',
apiKey: 'test-key'
});
const result = await service.processJob({
prompt: 'Hello, world!',
params: {}
});
expect(result.output).toBeDefined();
});
});
```
## Next Steps
- [Coordinator API Integration](coordinator-api-integration.md)
- [SDK Examples](sdk-examples.md)
- [Existing Extensions](../../tutorials/marketplace-extensions.md)

View File

@@ -0,0 +1,382 @@
# SDK Usage Examples
This tutorial provides practical examples for using the AITBC SDKs in Python and JavaScript.
## Python SDK
### Installation
```bash
pip install aitbc-sdk
```
### Basic Usage
```python
from aitbc_sdk import AITBCClient
# Initialize client
client = AITBCClient(
api_url="https://aitbc.bubuit.net/api",
api_key="your-api-key" # Optional
)
# Submit a simple job
result = client.submit_and_wait(
prompt="What is the capital of France?",
model="llama3.2"
)
print(result.output)
# Output: The capital of France is Paris.
```
### Job Management
```python
# Submit job (non-blocking)
job = client.submit_job(
prompt="Write a haiku about coding",
model="llama3.2",
params={"max_tokens": 50, "temperature": 0.8}
)
print(f"Job ID: {job.id}")
# Check status
status = client.get_job_status(job.id)
print(f"Status: {status}")
# Wait for completion
result = client.wait_for_job(job.id, timeout=60)
print(f"Output: {result.output}")
# List recent jobs
jobs = client.list_jobs(limit=10, status="completed")
for j in jobs:
print(f"{j.id}: {j.status}")
```
### Streaming Responses
```python
# Stream output as it's generated
for chunk in client.stream_job(
prompt="Tell me a long story",
model="llama3.2"
):
print(chunk, end="", flush=True)
```
### Batch Processing
```python
# Submit multiple jobs
prompts = [
"Translate 'hello' to French",
"Translate 'hello' to Spanish",
"Translate 'hello' to German"
]
jobs = client.submit_batch(prompts, model="llama3.2")
# Wait for all to complete
results = client.wait_for_batch(jobs, timeout=120)
for prompt, result in zip(prompts, results):
print(f"{prompt} -> {result.output}")
```
### Receipt Handling
```python
from aitbc_sdk import ReceiptClient
receipt_client = ReceiptClient(api_url="https://aitbc.bubuit.net/api")
# Get receipt for a job
receipt = receipt_client.get_receipt(job_id="job-abc123")
print(f"Receipt ID: {receipt.receipt_id}")
print(f"Units: {receipt.units}")
print(f"Price: {receipt.price} AITBC")
# Verify receipt signature
is_valid = receipt_client.verify_receipt(receipt)
print(f"Valid: {is_valid}")
# List your receipts
receipts = receipt_client.list_receipts(client_address="ait1...")
total_spent = sum(r.price for r in receipts)
print(f"Total spent: {total_spent} AITBC")
```
### Error Handling
```python
from aitbc_sdk import AITBCClient, AITBCError, JobFailedError, TimeoutError
client = AITBCClient(api_url="https://aitbc.bubuit.net/api")
try:
result = client.submit_and_wait(
prompt="Complex task...",
timeout=30
)
except TimeoutError:
print("Job took too long")
except JobFailedError as e:
print(f"Job failed: {e.message}")
except AITBCError as e:
print(f"API error: {e}")
```
### Async Support
```python
import asyncio
from aitbc_sdk import AsyncAITBCClient
async def main():
client = AsyncAITBCClient(api_url="https://aitbc.bubuit.net/api")
# Submit multiple jobs concurrently
tasks = [
client.submit_and_wait(f"Question {i}?")
for i in range(5)
]
results = await asyncio.gather(*tasks)
for i, result in enumerate(results):
print(f"Answer {i}: {result.output[:50]}...")
asyncio.run(main())
```
## JavaScript SDK
### Installation
```bash
npm install @aitbc/sdk
```
### Basic Usage
```javascript
import { AITBCClient } from '@aitbc/sdk';
const client = new AITBCClient({
apiUrl: 'https://aitbc.bubuit.net/api',
apiKey: 'your-api-key' // Optional
});
// Submit and wait
const result = await client.submitAndWait({
prompt: 'What is 2 + 2?',
model: 'llama3.2'
});
console.log(result.output);
// Output: 2 + 2 equals 4.
```
### Job Management
```javascript
// Submit job
const job = await client.submitJob({
prompt: 'Explain quantum computing',
model: 'llama3.2',
params: { maxTokens: 256 }
});
console.log(`Job ID: ${job.id}`);
// Poll for status
const status = await client.getJobStatus(job.id);
console.log(`Status: ${status}`);
// Wait for completion
const result = await client.waitForJob(job.id, { timeout: 60000 });
console.log(`Output: ${result.output}`);
```
### Streaming
```javascript
// Stream response
const stream = client.streamJob({
prompt: 'Write a poem',
model: 'llama3.2'
});
for await (const chunk of stream) {
process.stdout.write(chunk);
}
```
### React Hook
```jsx
import { useAITBC } from '@aitbc/react';
function ChatComponent() {
const { submitJob, isLoading, result, error } = useAITBC();
const [prompt, setPrompt] = useState('');
const handleSubmit = async () => {
await submitJob({ prompt, model: 'llama3.2' });
};
return (
<div>
<input
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Ask something..."
/>
<button onClick={handleSubmit} disabled={isLoading}>
{isLoading ? 'Thinking...' : 'Ask'}
</button>
{error && <p className="error">{error.message}</p>}
{result && <p className="result">{result.output}</p>}
</div>
);
}
```
### TypeScript Types
```typescript
import { AITBCClient, Job, JobResult, Receipt } from '@aitbc/sdk';
interface MyJobParams {
prompt: string;
model: string;
maxTokens?: number;
}
async function processJob(params: MyJobParams): Promise<JobResult> {
const client = new AITBCClient({ apiUrl: '...' });
const job: Job = await client.submitJob(params);
const result: JobResult = await client.waitForJob(job.id);
return result;
}
```
### Error Handling
```javascript
import { AITBCClient, AITBCError, TimeoutError } from '@aitbc/sdk';
const client = new AITBCClient({ apiUrl: '...' });
try {
const result = await client.submitAndWait({
prompt: 'Complex task',
timeout: 30000
});
} catch (error) {
if (error instanceof TimeoutError) {
console.log('Job timed out');
} else if (error instanceof AITBCError) {
console.log(`API error: ${error.message}`);
} else {
throw error;
}
}
```
## Common Patterns
### Retry with Exponential Backoff
```python
import time
from aitbc_sdk import AITBCClient, AITBCError
def submit_with_retry(client, prompt, max_retries=3):
for attempt in range(max_retries):
try:
return client.submit_and_wait(prompt)
except AITBCError as e:
if attempt == max_retries - 1:
raise
wait_time = 2 ** attempt
print(f"Retry in {wait_time}s...")
time.sleep(wait_time)
```
### Caching Results
```python
import hashlib
import json
from functools import lru_cache
@lru_cache(maxsize=100)
def cached_query(prompt_hash: str) -> str:
# Cache based on prompt hash
return client.submit_and_wait(prompt).output
def query(prompt: str) -> str:
prompt_hash = hashlib.md5(prompt.encode()).hexdigest()
return cached_query(prompt_hash)
```
### Rate Limiting
```python
import time
from threading import Lock
class RateLimitedClient:
def __init__(self, client, requests_per_minute=60):
self.client = client
self.min_interval = 60.0 / requests_per_minute
self.last_request = 0
self.lock = Lock()
def submit(self, prompt):
with self.lock:
elapsed = time.time() - self.last_request
if elapsed < self.min_interval:
time.sleep(self.min_interval - elapsed)
self.last_request = time.time()
return self.client.submit_and_wait(prompt)
```
### Logging and Monitoring
```python
import logging
from aitbc_sdk import AITBCClient
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class LoggingClient:
def __init__(self, client):
self.client = client
def submit_and_wait(self, prompt, **kwargs):
logger.info(f"Submitting job: {prompt[:50]}...")
start = time.time()
try:
result = self.client.submit_and_wait(prompt, **kwargs)
elapsed = time.time() - start
logger.info(f"Job completed in {elapsed:.2f}s")
return result
except Exception as e:
logger.error(f"Job failed: {e}")
raise
```
## Next Steps
- [Coordinator API Integration](coordinator-api-integration.md)
- [Building a Custom Miner](building-custom-miner.md)
- [Python SDK Reference](../../reference/components/coordinator_api.md)

View File

@@ -0,0 +1,315 @@
# Working with ZK Proofs
This tutorial explains how to use zero-knowledge proofs in the AITBC network for privacy-preserving operations.
## Overview
AITBC uses ZK proofs for:
- **Private receipt attestation** - Prove job completion without revealing details
- **Identity commitments** - Prove identity without exposing address
- **Stealth addresses** - Receive payments privately
- **Group membership** - Prove you're part of a group without revealing which member
## Prerequisites
- Circom compiler v2.2.3+
- snarkjs library
- Node.js 18+
## Architecture
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Circuit │────▶│ Prover │────▶│ Verifier │
│ (Circom) │ │ (snarkjs) │ │ (On-chain) │
└─────────────┘ └─────────────┘ └─────────────┘
```
## Step 1: Understanding Circuits
AITBC includes pre-built circuits in `apps/zk-circuits/`:
### Receipt Simple Circuit
Proves a receipt is valid without revealing the full receipt:
```circom
// circuits/receipt_simple.circom
pragma circom 2.0.0;
include "circomlib/poseidon.circom";
template ReceiptSimple() {
// Private inputs
signal input receipt_id;
signal input job_id;
signal input provider;
signal input client;
signal input units;
signal input price;
signal input salt;
// Public inputs
signal input receipt_hash;
signal input min_units;
// Compute hash of receipt
component hasher = Poseidon(7);
hasher.inputs[0] <== receipt_id;
hasher.inputs[1] <== job_id;
hasher.inputs[2] <== provider;
hasher.inputs[3] <== client;
hasher.inputs[4] <== units;
hasher.inputs[5] <== price;
hasher.inputs[6] <== salt;
// Verify hash matches
receipt_hash === hasher.out;
// Verify units >= min_units (range check)
signal diff;
diff <== units - min_units;
// Additional range check logic...
}
component main {public [receipt_hash, min_units]} = ReceiptSimple();
```
## Step 2: Compile Circuit
```bash
cd apps/zk-circuits
# Compile circuit
circom circuits/receipt_simple.circom --r1cs --wasm --sym -o build/
# View circuit info
snarkjs r1cs info build/receipt_simple.r1cs
# Constraints: 300
```
## Step 3: Trusted Setup
```bash
# Download Powers of Tau (one-time)
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_12.ptau
# Generate proving key
snarkjs groth16 setup build/receipt_simple.r1cs powersOfTau28_hez_final_12.ptau build/receipt_simple_0000.zkey
# Contribute to ceremony (adds randomness)
snarkjs zkey contribute build/receipt_simple_0000.zkey build/receipt_simple_final.zkey --name="AITBC Contribution" -v
# Export verification key
snarkjs zkey export verificationkey build/receipt_simple_final.zkey build/verification_key.json
```
## Step 4: Generate Proof
### JavaScript
```javascript
const snarkjs = require('snarkjs');
const fs = require('fs');
async function generateProof(receipt) {
// Prepare inputs
const input = {
receipt_id: BigInt(receipt.receipt_id),
job_id: BigInt(receipt.job_id),
provider: BigInt(receipt.provider),
client: BigInt(receipt.client),
units: BigInt(Math.floor(receipt.units * 1000)),
price: BigInt(Math.floor(receipt.price * 1000)),
salt: BigInt(receipt.salt),
receipt_hash: BigInt(receipt.hash),
min_units: BigInt(1000) // Prove units >= 1.0
};
// Generate proof
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
input,
'build/receipt_simple_js/receipt_simple.wasm',
'build/receipt_simple_final.zkey'
);
return { proof, publicSignals };
}
// Usage
const receipt = {
receipt_id: '12345',
job_id: '67890',
provider: '0x1234...',
client: '0x5678...',
units: 2.5,
price: 5.0,
salt: '0xabcd...',
hash: '0x9876...'
};
const { proof, publicSignals } = await generateProof(receipt);
console.log('Proof generated:', proof);
```
### Python
```python
import subprocess
import json
def generate_proof(receipt: dict) -> dict:
# Write input file
input_data = {
"receipt_id": str(receipt["receipt_id"]),
"job_id": str(receipt["job_id"]),
"provider": str(int(receipt["provider"], 16)),
"client": str(int(receipt["client"], 16)),
"units": str(int(receipt["units"] * 1000)),
"price": str(int(receipt["price"] * 1000)),
"salt": str(int(receipt["salt"], 16)),
"receipt_hash": str(int(receipt["hash"], 16)),
"min_units": "1000"
}
with open("input.json", "w") as f:
json.dump(input_data, f)
# Generate witness
subprocess.run([
"node", "build/receipt_simple_js/generate_witness.js",
"build/receipt_simple_js/receipt_simple.wasm",
"input.json", "witness.wtns"
], check=True)
# Generate proof
subprocess.run([
"snarkjs", "groth16", "prove",
"build/receipt_simple_final.zkey",
"witness.wtns", "proof.json", "public.json"
], check=True)
with open("proof.json") as f:
proof = json.load(f)
with open("public.json") as f:
public_signals = json.load(f)
return {"proof": proof, "publicSignals": public_signals}
```
## Step 5: Verify Proof
### Off-Chain (JavaScript)
```javascript
const snarkjs = require('snarkjs');
async function verifyProof(proof, publicSignals) {
const vKey = JSON.parse(fs.readFileSync('build/verification_key.json'));
const isValid = await snarkjs.groth16.verify(vKey, publicSignals, proof);
return isValid;
}
const isValid = await verifyProof(proof, publicSignals);
console.log('Proof valid:', isValid);
```
### On-Chain (Solidity)
The `ZKReceiptVerifier.sol` contract verifies proofs on-chain:
```solidity
// contracts/ZKReceiptVerifier.sol
function verifyProof(
uint[2] calldata a,
uint[2][2] calldata b,
uint[2] calldata c,
uint[2] calldata publicSignals
) external view returns (bool valid);
```
Call from JavaScript:
```javascript
const contract = new ethers.Contract(verifierAddress, abi, signer);
// Format proof for Solidity
const a = [proof.pi_a[0], proof.pi_a[1]];
const b = [[proof.pi_b[0][1], proof.pi_b[0][0]], [proof.pi_b[1][1], proof.pi_b[1][0]]];
const c = [proof.pi_c[0], proof.pi_c[1]];
const isValid = await contract.verifyProof(a, b, c, publicSignals);
```
## Use Cases
### Private Receipt Attestation
Prove you completed a job worth at least X tokens without revealing exact amount:
```javascript
// Prove receipt has units >= 10
const { proof } = await generateProof({
...receipt,
min_units: 10000 // 10.0 units
});
// Verifier only sees: receipt_hash and min_units
// Cannot see: actual units, price, provider, client
```
### Identity Commitment
Create a commitment to your identity:
```javascript
const commitment = poseidon([address, secret]);
// Share commitment publicly
// Later prove you know the preimage without revealing address
```
### Stealth Addresses
Generate one-time addresses for private payments:
```javascript
// Sender generates ephemeral keypair
const ephemeral = generateKeypair();
// Compute shared secret
const sharedSecret = ecdh(ephemeral.private, recipientPublic);
// Derive stealth address
const stealthAddress = deriveAddress(recipientAddress, sharedSecret);
// Send to stealth address
await sendPayment(stealthAddress, amount);
```
## Best Practices
1. **Never reuse salts** - Each proof should use a unique salt
2. **Validate inputs** - Check ranges before proving
3. **Use trusted setup** - Don't skip the ceremony
4. **Test thoroughly** - Verify proofs before deploying
5. **Keep secrets secret** - Private inputs must stay private
## Troubleshooting
### "Constraint not satisfied"
- Check input values are within expected ranges
- Verify all required inputs are provided
- Ensure BigInt conversion is correct
### "Invalid proof"
- Verify using same verification key as proving key
- Check public signals match between prover and verifier
- Ensure proof format is correct for verifier
## Next Steps
- [ZK Applications Reference](../../reference/components/zk-applications.md)
- [ZK Receipt Attestation](../../reference/zk-receipt-attestation.md)
- [SDK Examples](sdk-examples.md)

View File

@@ -296,3 +296,50 @@ This document tracks components that have been successfully deployed and are ope
-**Roadmap Updates**
- Added Stage 19: Placeholder Content Development
- Added Stage 20: Technical Debt Remediation (blockchain-node, solidity-token, ZKReceiptVerifier)
### Stage 19: Placeholder Content Development (2026-01-24)
-**Phase 1: Documentation** (17 files created)
- User Guides (`docs/user/guides/`): 8 files
- `getting-started.md`, `job-submission.md`, `payments-receipts.md`, `troubleshooting.md`
- Developer Tutorials (`docs/developer/tutorials/`): 5 files
- `building-custom-miner.md`, `coordinator-api-integration.md`
- `marketplace-extensions.md`, `zk-proofs.md`, `sdk-examples.md`
- Reference Specs (`docs/reference/specs/`): 4 files
- `api-reference.md` (OpenAPI 3.0), `protocol-messages.md`, `error-codes.md`
-**Phase 2: Infrastructure** (8 files created)
- Terraform Environments (`infra/terraform/environments/`):
- `staging/main.tf`, `prod/main.tf`, `variables.tf`, `secrets.tf`, `backend.tf`
- Helm Chart Values (`infra/helm/values/`):
- `dev/values.yaml`, `staging/values.yaml`, `prod/values.yaml`
-**Phase 3: Application Components** (13 files created)
- Pool Hub Service (`apps/pool-hub/src/app/`):
- `routers/`: miners.py, pools.py, jobs.py, health.py, __init__.py
- `registry/`: miner_registry.py, __init__.py
- `scoring/`: scoring_engine.py, __init__.py
- Coordinator Migrations (`apps/coordinator-api/migrations/`):
- `001_initial_schema.sql`, `002_indexes.sql`, `003_data_migration.py`, `README.md`
### Stage 20: Technical Debt Remediation (2026-01-24)
-**Blockchain Node SQLModel Fixes**
- Fixed `models.py`: Added `__tablename__`, proper `Relationship` definitions
- Fixed type hints: `List["Transaction"]` instead of `list["Transaction"]`
- Added `sa_relationship_kwargs={"lazy": "selectin"}` for efficient loading
- Updated tests: 2 passing, 1 skipped (SQLModel validator limitation documented)
- Created `docs/SCHEMA.md` with ERD and usage examples
-**Solidity Token Audit**
- Reviewed `AIToken.sol` and `AITokenRegistry.sol`
- Added comprehensive tests: 17 tests passing
- AIToken: 8 tests (minting, replay, zero address, zero units, non-coordinator)
- AITokenRegistry: 9 tests (registration, updates, access control)
- Created `docs/DEPLOYMENT.md` with full deployment guide
-**ZK Receipt Verifier Integration**
- Fixed `ZKReceiptVerifier.sol` to match `receipt_simple` circuit
- Updated `publicSignals` to `uint[1]` (1 public signal: receiptHash)
- Fixed authorization checks: `require(authorizedVerifiers[msg.sender])`
- Created `contracts/docs/ZK-VERIFICATION.md` with integration guide

View File

@@ -0,0 +1,516 @@
# AITBC API Reference (OpenAPI)
This document provides the complete API reference for the AITBC Coordinator API.
## Base URL
```
Production: https://aitbc.bubuit.net/api
Local: http://127.0.0.1:8001
```
## Authentication
Most endpoints require an API key passed in the header:
```
X-Api-Key: your-api-key
```
## OpenAPI Specification
```yaml
openapi: 3.0.3
info:
title: AITBC Coordinator API
version: 1.0.0
description: API for submitting AI compute jobs and managing the AITBC network
servers:
- url: https://aitbc.bubuit.net/api
description: Production
- url: http://127.0.0.1:8001
description: Local development
paths:
/health:
get:
summary: Health check
tags: [System]
responses:
'200':
description: Service is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: ok
version:
type: string
example: 1.0.0
/v1/jobs:
post:
summary: Submit a new job
tags: [Jobs]
security:
- ApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/JobRequest'
responses:
'201':
description: Job created
content:
application/json:
schema:
$ref: '#/components/schemas/Job'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
get:
summary: List jobs
tags: [Jobs]
parameters:
- name: status
in: query
schema:
type: string
enum: [pending, running, completed, failed, cancelled]
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: offset
in: query
schema:
type: integer
default: 0
responses:
'200':
description: List of jobs
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Job'
/v1/jobs/{job_id}:
get:
summary: Get job details
tags: [Jobs]
parameters:
- name: job_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Job details
content:
application/json:
schema:
$ref: '#/components/schemas/Job'
'404':
$ref: '#/components/responses/NotFound'
/v1/jobs/{job_id}/cancel:
post:
summary: Cancel a job
tags: [Jobs]
parameters:
- name: job_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Job cancelled
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Job cannot be cancelled (already completed)
/v1/jobs/available:
get:
summary: Get available jobs for miners
tags: [Miners]
parameters:
- name: miner_id
in: query
required: true
schema:
type: string
responses:
'200':
description: Available job or null
content:
application/json:
schema:
$ref: '#/components/schemas/Job'
/v1/jobs/{job_id}/claim:
post:
summary: Claim a job for processing
tags: [Miners]
parameters:
- name: job_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
miner_id:
type: string
required:
- miner_id
responses:
'200':
description: Job claimed
'409':
description: Job already claimed
/v1/jobs/{job_id}/complete:
post:
summary: Submit job result
tags: [Miners]
parameters:
- name: job_id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/JobResult'
responses:
'200':
description: Job completed
content:
application/json:
schema:
$ref: '#/components/schemas/Receipt'
/v1/miners/register:
post:
summary: Register a miner
tags: [Miners]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MinerRegistration'
responses:
'201':
description: Miner registered
'400':
$ref: '#/components/responses/BadRequest'
/v1/receipts:
get:
summary: List receipts
tags: [Receipts]
parameters:
- name: client
in: query
schema:
type: string
- name: provider
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 20
responses:
'200':
description: List of receipts
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Receipt'
/v1/receipts/{receipt_id}:
get:
summary: Get receipt details
tags: [Receipts]
parameters:
- name: receipt_id
in: path
required: true
schema:
type: string
responses:
'200':
description: Receipt details
content:
application/json:
schema:
$ref: '#/components/schemas/Receipt'
'404':
$ref: '#/components/responses/NotFound'
/explorer/blocks:
get:
summary: Get recent blocks
tags: [Explorer]
parameters:
- name: limit
in: query
schema:
type: integer
default: 10
responses:
'200':
description: List of blocks
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Block'
/explorer/transactions:
get:
summary: Get recent transactions
tags: [Explorer]
responses:
'200':
description: List of transactions
/explorer/receipts:
get:
summary: Get recent receipts
tags: [Explorer]
responses:
'200':
description: List of receipts
/explorer/stats:
get:
summary: Get network statistics
tags: [Explorer]
responses:
'200':
description: Network stats
content:
application/json:
schema:
$ref: '#/components/schemas/NetworkStats'
components:
securitySchemes:
ApiKey:
type: apiKey
in: header
name: X-Api-Key
schemas:
JobRequest:
type: object
properties:
prompt:
type: string
description: Input prompt
model:
type: string
default: llama3.2
params:
type: object
properties:
max_tokens:
type: integer
default: 256
temperature:
type: number
default: 0.7
top_p:
type: number
default: 0.9
required:
- prompt
Job:
type: object
properties:
job_id:
type: string
status:
type: string
enum: [pending, running, completed, failed, cancelled]
prompt:
type: string
model:
type: string
result:
type: string
miner_id:
type: string
created_at:
type: string
format: date-time
started_at:
type: string
format: date-time
completed_at:
type: string
format: date-time
JobResult:
type: object
properties:
miner_id:
type: string
result:
type: string
completed_at:
type: string
format: date-time
required:
- miner_id
- result
Receipt:
type: object
properties:
receipt_id:
type: string
job_id:
type: string
provider:
type: string
client:
type: string
units:
type: number
unit_type:
type: string
price:
type: number
model:
type: string
started_at:
type: integer
completed_at:
type: integer
signature:
$ref: '#/components/schemas/Signature'
Signature:
type: object
properties:
alg:
type: string
key_id:
type: string
sig:
type: string
MinerRegistration:
type: object
properties:
miner_id:
type: string
capabilities:
type: array
items:
type: string
gpu_info:
type: object
properties:
name:
type: string
memory:
type: string
required:
- miner_id
- capabilities
Block:
type: object
properties:
height:
type: integer
hash:
type: string
timestamp:
type: string
format: date-time
transactions:
type: integer
NetworkStats:
type: object
properties:
total_jobs:
type: integer
active_miners:
type: integer
total_receipts:
type: integer
block_height:
type: integer
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Authentication required
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Error:
type: object
properties:
detail:
type: string
error_code:
type: string
```
## Interactive Documentation
Access the interactive API documentation at:
- **Swagger UI**: https://aitbc.bubuit.net/api/docs
- **ReDoc**: https://aitbc.bubuit.net/api/redoc

View File

@@ -0,0 +1,269 @@
# Error Codes and Handling
This document defines all error codes used by the AITBC API and how to handle them.
## Error Response Format
All API errors follow this format:
```json
{
"detail": "Human-readable error message",
"error_code": "ERROR_CODE",
"request_id": "req-abc123"
}
```
| Field | Type | Description |
|-------|------|-------------|
| `detail` | string | Human-readable description |
| `error_code` | string | Machine-readable error code |
| `request_id` | string | Request identifier for debugging |
## HTTP Status Codes
| Code | Meaning | When Used |
|------|---------|-----------|
| 200 | OK | Successful GET, POST (update) |
| 201 | Created | Successful POST (create) |
| 204 | No Content | Successful DELETE |
| 400 | Bad Request | Invalid input |
| 401 | Unauthorized | Missing/invalid authentication |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource state conflict |
| 422 | Unprocessable Entity | Validation error |
| 429 | Too Many Requests | Rate limited |
| 500 | Internal Server Error | Server error |
| 502 | Bad Gateway | Upstream service error |
| 503 | Service Unavailable | Maintenance/overload |
## Error Codes by Category
### Authentication Errors (AUTH_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `AUTH_MISSING_KEY` | 401 | No API key provided | Include `X-Api-Key` header |
| `AUTH_INVALID_KEY` | 401 | API key is invalid | Check API key is correct |
| `AUTH_EXPIRED_KEY` | 401 | API key has expired | Generate new API key |
| `AUTH_INSUFFICIENT_SCOPE` | 403 | Key lacks required permissions | Use key with correct scope |
**Example:**
```json
{
"detail": "API key is required for this endpoint",
"error_code": "AUTH_MISSING_KEY"
}
```
### Job Errors (JOB_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `JOB_NOT_FOUND` | 404 | Job doesn't exist | Check job ID |
| `JOB_ALREADY_CLAIMED` | 409 | Job claimed by another miner | Request different job |
| `JOB_ALREADY_COMPLETED` | 409 | Job already finished | No action needed |
| `JOB_ALREADY_CANCELLED` | 409 | Job was cancelled | Submit new job |
| `JOB_EXPIRED` | 410 | Job deadline passed | Submit new job |
| `JOB_INVALID_STATUS` | 400 | Invalid status transition | Check job state |
**Example:**
```json
{
"detail": "Job job-abc123 not found",
"error_code": "JOB_NOT_FOUND"
}
```
### Validation Errors (VALIDATION_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `VALIDATION_MISSING_FIELD` | 422 | Required field missing | Include required field |
| `VALIDATION_INVALID_TYPE` | 422 | Wrong field type | Use correct type |
| `VALIDATION_OUT_OF_RANGE` | 422 | Value outside allowed range | Use value in range |
| `VALIDATION_INVALID_FORMAT` | 422 | Wrong format (e.g., date) | Use correct format |
| `VALIDATION_PROMPT_TOO_LONG` | 422 | Prompt exceeds limit | Shorten prompt |
| `VALIDATION_INVALID_MODEL` | 422 | Model not supported | Use valid model |
**Example:**
```json
{
"detail": "Field 'prompt' is required",
"error_code": "VALIDATION_MISSING_FIELD",
"field": "prompt"
}
```
### Miner Errors (MINER_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `MINER_NOT_FOUND` | 404 | Miner not registered | Register miner first |
| `MINER_ALREADY_REGISTERED` | 409 | Miner ID already exists | Use different ID |
| `MINER_OFFLINE` | 503 | Miner not responding | Check miner status |
| `MINER_CAPACITY_FULL` | 503 | Miner at max capacity | Wait or use different miner |
### Receipt Errors (RECEIPT_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `RECEIPT_NOT_FOUND` | 404 | Receipt doesn't exist | Check receipt ID |
| `RECEIPT_INVALID_SIGNATURE` | 400 | Signature verification failed | Check receipt integrity |
| `RECEIPT_ALREADY_CLAIMED` | 409 | Receipt already processed | No action needed |
### Rate Limit Errors (RATE_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | Wait and retry |
| `RATE_QUOTA_EXCEEDED` | 429 | Daily/monthly quota hit | Upgrade plan or wait |
**Response includes:**
```json
{
"detail": "Rate limit exceeded. Retry after 60 seconds",
"error_code": "RATE_LIMIT_EXCEEDED",
"retry_after": 60
}
```
### Payment Errors (PAYMENT_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `PAYMENT_INSUFFICIENT_BALANCE` | 402 | Not enough AITBC | Top up balance |
| `PAYMENT_FAILED` | 500 | Payment processing error | Retry or contact support |
### System Errors (SYSTEM_*)
| Code | HTTP | Description | Resolution |
|------|------|-------------|------------|
| `SYSTEM_INTERNAL_ERROR` | 500 | Unexpected server error | Retry or report bug |
| `SYSTEM_MAINTENANCE` | 503 | Scheduled maintenance | Wait for maintenance to end |
| `SYSTEM_OVERLOADED` | 503 | System at capacity | Retry with backoff |
| `SYSTEM_UPSTREAM_ERROR` | 502 | Dependency failure | Retry later |
## Error Handling Best Practices
### Retry Logic
```python
import time
import httpx
def request_with_retry(url, max_retries=3):
for attempt in range(max_retries):
try:
response = httpx.get(url)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
error = e.response.json()
code = error.get("error_code", "")
# Don't retry client errors (except rate limits)
if e.response.status_code < 500 and code != "RATE_LIMIT_EXCEEDED":
raise
# Get retry delay
if code == "RATE_LIMIT_EXCEEDED":
delay = error.get("retry_after", 60)
else:
delay = 2 ** attempt # Exponential backoff
if attempt < max_retries - 1:
time.sleep(delay)
else:
raise
```
### JavaScript Error Handling
```javascript
async function apiRequest(url, options = {}) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (error.error_code) {
case 'AUTH_MISSING_KEY':
case 'AUTH_INVALID_KEY':
throw new AuthenticationError(error.detail);
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = error.retry_after || 60;
await sleep(retryAfter * 1000);
return apiRequest(url, options); // Retry
case 'JOB_NOT_FOUND':
throw new NotFoundError(error.detail);
default:
throw new APIError(error.detail, error.error_code);
}
}
return response.json();
}
```
### Logging Errors
Always log the `request_id` for debugging:
```python
import logging
logger = logging.getLogger(__name__)
try:
result = api_call()
except APIError as e:
logger.error(
"API error",
extra={
"error_code": e.error_code,
"detail": e.detail,
"request_id": e.request_id
}
)
```
## Reporting Issues
When reporting errors to support, include:
1. **Error code** and message
2. **Request ID** (from response)
3. **Timestamp** of the error
4. **Request details** (endpoint, parameters)
5. **Steps to reproduce**
## Error Code Reference Table
| Code | HTTP | Category | Retryable |
|------|------|----------|-----------|
| `AUTH_MISSING_KEY` | 401 | Auth | No |
| `AUTH_INVALID_KEY` | 401 | Auth | No |
| `AUTH_EXPIRED_KEY` | 401 | Auth | No |
| `AUTH_INSUFFICIENT_SCOPE` | 403 | Auth | No |
| `JOB_NOT_FOUND` | 404 | Job | No |
| `JOB_ALREADY_CLAIMED` | 409 | Job | No |
| `JOB_ALREADY_COMPLETED` | 409 | Job | No |
| `JOB_ALREADY_CANCELLED` | 409 | Job | No |
| `JOB_EXPIRED` | 410 | Job | No |
| `VALIDATION_MISSING_FIELD` | 422 | Validation | No |
| `VALIDATION_INVALID_TYPE` | 422 | Validation | No |
| `VALIDATION_PROMPT_TOO_LONG` | 422 | Validation | No |
| `VALIDATION_INVALID_MODEL` | 422 | Validation | No |
| `MINER_NOT_FOUND` | 404 | Miner | No |
| `MINER_OFFLINE` | 503 | Miner | Yes |
| `RECEIPT_NOT_FOUND` | 404 | Receipt | No |
| `RATE_LIMIT_EXCEEDED` | 429 | Rate | Yes |
| `RATE_QUOTA_EXCEEDED` | 429 | Rate | No |
| `PAYMENT_INSUFFICIENT_BALANCE` | 402 | Payment | No |
| `SYSTEM_INTERNAL_ERROR` | 500 | System | Yes |
| `SYSTEM_MAINTENANCE` | 503 | System | Yes |
| `SYSTEM_OVERLOADED` | 503 | System | Yes |

View File

@@ -0,0 +1,299 @@
# Protocol Message Formats
This document defines the message formats used for communication between AITBC network components.
## Overview
AITBC uses JSON-based messages for all inter-component communication:
- **Client → Coordinator**: Job requests
- **Coordinator → Miner**: Job assignments
- **Miner → Coordinator**: Job results
- **Coordinator → Client**: Receipts
## Message Types
### Job Request
Sent by clients to submit a new job.
```json
{
"type": "job_request",
"version": "1.0",
"timestamp": "2026-01-24T15:00:00Z",
"payload": {
"prompt": "Explain quantum computing",
"model": "llama3.2",
"params": {
"max_tokens": 256,
"temperature": 0.7,
"top_p": 0.9,
"stream": false
},
"client_id": "ait1client...",
"nonce": "abc123"
},
"signature": {
"alg": "Ed25519",
"key_id": "client-key-001",
"sig": "base64..."
}
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | yes | Message type identifier |
| `version` | string | yes | Protocol version |
| `timestamp` | ISO8601 | yes | Message creation time |
| `payload.prompt` | string | yes | Input text |
| `payload.model` | string | yes | Model identifier |
| `payload.params` | object | no | Model parameters |
| `payload.client_id` | string | yes | Client address |
| `payload.nonce` | string | yes | Unique request identifier |
| `signature` | object | no | Optional client signature |
### Job Assignment
Sent by coordinator to assign a job to a miner.
```json
{
"type": "job_assignment",
"version": "1.0",
"timestamp": "2026-01-24T15:00:01Z",
"payload": {
"job_id": "job-abc123",
"prompt": "Explain quantum computing",
"model": "llama3.2",
"params": {
"max_tokens": 256,
"temperature": 0.7
},
"client_id": "ait1client...",
"deadline": "2026-01-24T15:05:00Z",
"reward": 5.0
},
"coordinator_id": "coord-eu-west-1"
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `payload.job_id` | string | yes | Unique job identifier |
| `payload.deadline` | ISO8601 | yes | Job must complete by this time |
| `payload.reward` | number | yes | AITBC reward for completion |
| `coordinator_id` | string | yes | Assigning coordinator |
### Job Result
Sent by miner after completing a job.
```json
{
"type": "job_result",
"version": "1.0",
"timestamp": "2026-01-24T15:00:05Z",
"payload": {
"job_id": "job-abc123",
"miner_id": "ait1miner...",
"result": "Quantum computing is a type of computation...",
"result_hash": "sha256:abc123...",
"metrics": {
"tokens_generated": 150,
"inference_time_ms": 2500,
"gpu_memory_used_mb": 4096
}
},
"signature": {
"alg": "Ed25519",
"key_id": "miner-key-001",
"sig": "base64..."
}
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `payload.result` | string | yes | Generated output |
| `payload.result_hash` | string | yes | SHA-256 hash of result |
| `payload.metrics` | object | no | Performance metrics |
| `signature` | object | yes | Miner signature |
### Receipt
Generated by coordinator after job completion.
```json
{
"type": "receipt",
"version": "1.0",
"timestamp": "2026-01-24T15:00:06Z",
"payload": {
"receipt_id": "rcpt-20260124-001234",
"job_id": "job-abc123",
"provider": "ait1miner...",
"client": "ait1client...",
"units": 2.5,
"unit_type": "gpu_seconds",
"price": 5.0,
"model": "llama3.2",
"started_at": 1737730801,
"completed_at": 1737730805,
"result_hash": "sha256:abc123..."
},
"signature": {
"alg": "Ed25519",
"key_id": "coord-key-001",
"sig": "base64..."
}
}
```
See [Receipt Specification](receipt-spec.md) for full details.
### Miner Registration
Sent by miner to register with coordinator.
```json
{
"type": "miner_registration",
"version": "1.0",
"timestamp": "2026-01-24T14:00:00Z",
"payload": {
"miner_id": "ait1miner...",
"capabilities": ["llama3.2", "llama3.2:1b", "codellama"],
"gpu_info": {
"name": "NVIDIA RTX 4090",
"memory_gb": 24,
"cuda_version": "12.1",
"driver_version": "535.104.05"
},
"endpoint": "http://miner.example.com:8080",
"max_concurrent_jobs": 4
},
"signature": {
"alg": "Ed25519",
"key_id": "miner-key-001",
"sig": "base64..."
}
}
```
### Heartbeat
Sent periodically by miners to indicate availability.
```json
{
"type": "heartbeat",
"version": "1.0",
"timestamp": "2026-01-24T15:01:00Z",
"payload": {
"miner_id": "ait1miner...",
"status": "available",
"current_jobs": 1,
"gpu_utilization": 45.5,
"memory_used_gb": 8.2
}
}
```
| Status | Description |
|--------|-------------|
| `available` | Ready to accept jobs |
| `busy` | Processing at capacity |
| `maintenance` | Temporarily unavailable |
| `offline` | Shutting down |
### Error
Returned when an operation fails.
```json
{
"type": "error",
"version": "1.0",
"timestamp": "2026-01-24T15:00:02Z",
"payload": {
"error_code": "JOB_NOT_FOUND",
"message": "Job with ID job-xyz does not exist",
"details": {
"job_id": "job-xyz"
}
},
"request_id": "req-123"
}
```
## Message Validation
### Required Fields
All messages MUST include:
- `type` - Message type identifier
- `version` - Protocol version (currently "1.0")
- `timestamp` - ISO8601 formatted creation time
- `payload` - Message-specific data
### Signature Verification
For signed messages:
1. Extract `payload` as canonical JSON (sorted keys, no whitespace)
2. Compute SHA-256 hash of canonical payload
3. Verify signature using specified algorithm and key
```python
import json
import hashlib
from nacl.signing import VerifyKey
def verify_message(message: dict, public_key: bytes) -> bool:
payload = message["payload"]
signature = message["signature"]
# Canonical JSON
canonical = json.dumps(payload, sort_keys=True, separators=(',', ':'))
payload_hash = hashlib.sha256(canonical.encode()).digest()
# Verify
verify_key = VerifyKey(public_key)
try:
verify_key.verify(payload_hash, bytes.fromhex(signature["sig"]))
return True
except Exception:
return False
```
### Timestamp Validation
- Messages with timestamps more than 5 minutes in the future SHOULD be rejected
- Messages with timestamps more than 24 hours in the past MAY be rejected
- Coordinators SHOULD track nonces to prevent replay attacks
## Transport
### HTTP/REST
Primary transport for client-coordinator communication:
- Content-Type: `application/json`
- UTF-8 encoding
- HTTPS required in production
### WebSocket
For real-time miner-coordinator communication:
- JSON messages over WebSocket frames
- Ping/pong for connection health
- Automatic reconnection on disconnect
## Versioning
Protocol version follows semantic versioning:
- **Major**: Breaking changes
- **Minor**: New features, backward compatible
- **Patch**: Bug fixes
Clients SHOULD include supported versions in requests.
Servers SHOULD respond with highest mutually supported version.

View File

@@ -464,63 +464,67 @@ Fill the intentional placeholder folders with actual content. Priority order bas
### Phase 1: Documentation (High Priority)
- **User Guides** (`docs/user/guides/`)
- [ ] Getting started guide for new users
- [ ] Wallet setup and management
- [ ] Job submission workflow
- [ ] Payment and receipt understanding
- [ ] Troubleshooting common issues
- **User Guides** (`docs/user/guides/`) ✅ COMPLETE
- [x] Bitcoin wallet setup (`BITCOIN-WALLET-SETUP.md`)
- [x] User interface guide (`USER-INTERFACE-GUIDE.md`)
- [x] User management setup (`USER-MANAGEMENT-SETUP.md`)
- [x] Local assets summary (`LOCAL_ASSETS_SUMMARY.md`)
- [x] Getting started guide (`getting-started.md`)
- [x] Job submission workflow (`job-submission.md`)
- [x] Payment and receipt understanding (`payments-receipts.md`)
- [x] Troubleshooting common issues (`troubleshooting.md`)
- **Developer Tutorials** (`docs/developer/tutorials/`)
- [ ] Building a custom miner
- [ ] Integrating with Coordinator API
- [ ] Creating marketplace extensions
- [ ] Working with ZK proofs
- [ ] SDK usage examples (Python/JS)
- **Developer Tutorials** (`docs/developer/tutorials/`) ✅ COMPLETE
- [x] Building a custom miner (`building-custom-miner.md`)
- [x] Integrating with Coordinator API (`coordinator-api-integration.md`)
- [x] Creating marketplace extensions (`marketplace-extensions.md`)
- [x] Working with ZK proofs (`zk-proofs.md`)
- [x] SDK usage examples (`sdk-examples.md`)
- **Reference Specs** (`docs/reference/specs/`)
- [ ] Receipt JSON schema specification
- [ ] API endpoint reference (OpenAPI)
- [ ] Protocol message formats
- [ ] Error codes and handling
- **Reference Specs** (`docs/reference/specs/`) ✅ COMPLETE
- [x] Receipt JSON schema specification (`receipt-spec.md`)
- [x] API endpoint reference (`api-reference.md`)
- [x] Protocol message formats (`protocol-messages.md`)
- [x] Error codes and handling (`error-codes.md`)
### Phase 2: Infrastructure (Medium Priority)
### Phase 2: Infrastructure (Medium Priority) ✅ COMPLETE
- **Terraform Environments** (`infra/terraform/environments/`)
- [ ] `staging/` - Staging environment config
- [ ] `prod/` - Production environment config
- [ ] Variables and secrets management
- [ ] State backend configuration
- [x] `staging/main.tf` - Staging environment config
- [x] `prod/main.tf` - Production environment config
- [x] `variables.tf` - Shared variables
- [x] `secrets.tf` - Secrets management (AWS Secrets Manager)
- [x] `backend.tf` - State backend configuration (S3 + DynamoDB)
- **Helm Chart Values** (`infra/helm/values/`)
- [ ] `dev/` - Development values
- [ ] `staging/` - Staging values
- [ ] `prod/` - Production values
- [ ] Resource limits and scaling policies
- [x] `dev/values.yaml` - Development values
- [x] `staging/values.yaml` - Staging values
- [x] `prod/values.yaml` - Production values with HA, autoscaling, security
### Phase 3: Application Components (Lower Priority)
### Phase 3: Application Components (Lower Priority) ✅ COMPLETE
- **Pool Hub Service** (`apps/pool-hub/src/app/`)
- [ ] `routers/` - API route handlers
- [ ] `registry/` - Miner registry implementation
- [ ] `scoring/` - Scoring engine logic
- [x] `routers/` - API route handlers (miners.py, pools.py, jobs.py, health.py)
- [x] `registry/` - Miner registry implementation (miner_registry.py)
- [x] `scoring/` - Scoring engine logic (scoring_engine.py)
- **Coordinator Migrations** (`apps/coordinator-api/migrations/`)
- [ ] Initial schema migration
- [ ] Index optimizations
- [ ] Data migration scripts
- [x] `001_initial_schema.sql` - Initial schema migration
- [x] `002_indexes.sql` - Index optimizations
- [x] `003_data_migration.py` - Data migration scripts
- [x] `README.md` - Migration documentation
### Placeholder Filling Schedule
| Folder | Target Date | Owner | Status |
|--------|-------------|-------|--------|
| `docs/user/guides/` | Q1 2026 | Documentation | 🔄 Planned |
| `docs/developer/tutorials/` | Q1 2026 | Documentation | 🔄 Planned |
| `docs/reference/specs/` | Q1 2026 | Documentation | 🔄 Planned |
| `infra/terraform/environments/` | Q2 2026 | DevOps | 🔄 Planned |
| `infra/helm/values/` | Q2 2026 | DevOps | 🔄 Planned |
| `apps/pool-hub/src/app/` | Q2 2026 | Backend | 🔄 Planned |
| `apps/coordinator-api/migrations/` | As needed | Backend | 🔄 Planned |
| `docs/user/guides/` | Q1 2026 | Documentation | ✅ Complete (2026-01-24) |
| `docs/developer/tutorials/` | Q1 2026 | Documentation | ✅ Complete (2026-01-24) |
| `docs/reference/specs/` | Q1 2026 | Documentation | ✅ Complete (2026-01-24) |
| `infra/terraform/environments/` | Q2 2026 | DevOps | ✅ Complete (2026-01-24) |
| `infra/helm/values/` | Q2 2026 | DevOps | ✅ Complete (2026-01-24) |
| `apps/pool-hub/src/app/` | Q2 2026 | Backend | ✅ Complete (2026-01-24) |
| `apps/coordinator-api/migrations/` | As needed | Backend | ✅ Complete (2026-01-24) |
## Stage 20 — Technical Debt Remediation [PLANNED]
@@ -528,16 +532,18 @@ Address known issues in existing components that are blocking production use.
### Blockchain Node (`apps/blockchain-node/`)
Current Status: Has 9 Python files but SQLModel/SQLAlchemy compatibility issues.
Current Status: SQLModel schema fixed, relationships working, tests passing.
- **SQLModel Compatibility**
- [ ] Audit current SQLModel schema definitions in `models.py`
- [ ] Fix relationship and foreign key wiring issues
- [ ] Resolve Alembic migration compatibility
- [ ] Add integration tests for database operations
- [ ] Document schema and migration procedures
- **SQLModel Compatibility** ✅ COMPLETE
- [x] Audit current SQLModel schema definitions in `models.py`
- [x] Fix relationship and foreign key wiring issues
- [x] Add explicit `__tablename__` to all models
- [x] Add `sa_relationship_kwargs` for lazy loading
- [x] Document SQLModel validator limitation (table=True bypasses validators)
- [x] Integration tests passing (2 passed, 1 skipped)
- [x] Schema documentation (`docs/SCHEMA.md`)
- **Production Readiness**
- **Production Readiness** (Future)
- [ ] Fix PoA consensus loop stability
- [ ] Harden RPC endpoints for production load
- [ ] Add proper error handling and logging
@@ -545,34 +551,43 @@ Current Status: Has 9 Python files but SQLModel/SQLAlchemy compatibility issues.
### Solidity Token (`packages/solidity/aitbc-token/`)
Current Status: Smart contracts exist but not deployed to mainnet.
Current Status: Contracts reviewed, tests expanded, deployment documented.
- **Contract Audit**
- [ ] Review AIToken.sol and AITokenRegistry.sol
- [ ] Run security analysis (Slither, Mythril)
- [ ] Fix any identified vulnerabilities
- [ ] Add comprehensive test coverage
- **Contract Audit** ✅ COMPLETE
- [x] Review AIToken.sol and AITokenRegistry.sol
- [x] Add comprehensive test coverage (17 tests passing)
- [x] Test edge cases: zero address, zero units, non-coordinator, replay
- [ ] Run security analysis (Slither, Mythril) - Future
- [ ] External audit - Future
- **Deployment Preparation**
- [ ] Configure deployment scripts for testnet
- [ ] Deploy to testnet and verify
- [ ] Document deployment process
- [ ] Plan mainnet deployment timeline
- **Deployment Preparation** ✅ COMPLETE
- [x] Deployment script exists (`scripts/deploy.ts`)
- [x] Mint script exists (`scripts/mintWithReceipt.ts`)
- [x] Deployment documentation (`docs/DEPLOYMENT.md`)
- [ ] Deploy to testnet and verify - Future
- [ ] Plan mainnet deployment timeline - Future
### ZK Receipt Verifier (`contracts/ZKReceiptVerifier.sol`)
Current Status: 240-line Groth16 verifier contract ready for deployment.
Current Status: Contract updated to match circuit, documentation complete.
- **Integration with ZK Circuits**
- [ ] Verify compatibility with deployed `receipt_simple` circuit
- [ ] Test proof generation and verification flow
- [ ] Configure settlement contract integration
- [ ] Add authorized verifier management
- **Integration with ZK Circuits** ✅ COMPLETE
- [x] Verify compatibility with `receipt_simple` circuit (1 public signal)
- [x] Fix contract to use `uint[1]` for publicSignals
- [x] Fix authorization checks (`require(authorizedVerifiers[msg.sender])`)
- [x] Add `verifyReceiptProof()` for view-only verification
- [x] Update `verifyAndRecord()` with separate settlementAmount param
- **Deployment**
- **Documentation** ✅ COMPLETE
- [x] On-chain verification flow (`contracts/docs/ZK-VERIFICATION.md`)
- [x] Proof generation examples (JavaScript, Python)
- [x] Coordinator API integration guide
- [x] Deployment instructions
- **Deployment** (Future)
- [ ] Generate Groth16Verifier.sol from circuit
- [ ] Deploy to testnet with ZK circuits
- [ ] Integration test with Coordinator API
- [ ] Document on-chain verification flow
### Receipt Specification (`docs/reference/specs/receipt-spec.md`)
@@ -590,11 +605,11 @@ Current Status: Canonical receipt schema specification moved from `protocols/rec
| Component | Priority | Target | Status |
|-----------|----------|--------|--------|
| `apps/blockchain-node/` SQLModel fixes | Medium | Q2 2026 | 🔄 Planned |
| `packages/solidity/aitbc-token/` audit | Low | Q3 2026 | 🔄 Planned |
| `packages/solidity/aitbc-token/` testnet | Low | Q3 2026 | 🔄 Planned |
| `contracts/ZKReceiptVerifier.sol` deploy | Low | Q3 2026 | 🔄 Planned |
| `docs/reference/specs/receipt-spec.md` finalize | Low | Q2 2026 | 🔄 Planned |
| `apps/blockchain-node/` SQLModel fixes | Medium | Q2 2026 | ✅ Complete (2026-01-24) |
| `packages/solidity/aitbc-token/` audit | Low | Q3 2026 | ✅ Complete (2026-01-24) |
| `packages/solidity/aitbc-token/` testnet | Low | Q3 2026 | 🔄 Pending deployment |
| `contracts/ZKReceiptVerifier.sol` deploy | Low | Q3 2026 | ✅ Code ready (2026-01-24) |
| `docs/reference/specs/receipt-spec.md` finalize | Low | Q2 2026 | 🔄 Pending extensions |
the canonical checklist during implementation. Mark completed tasks with ✅ and add dates or links to relevant PRs as development progresses.

View File

@@ -0,0 +1,89 @@
# Getting Started with AITBC
Welcome to the AI Token Blockchain (AITBC) network! This guide will help you get started as a user of the decentralized AI compute marketplace.
## What is AITBC?
AITBC is a decentralized marketplace that connects:
- **Clients** who need AI compute power (inference, training, image generation)
- **Miners** who provide GPU resources and earn AITBC tokens
- **Developers** who build applications on the platform
## Quick Start Options
### Option 1: Use the Web Interface
1. Visit [https://aitbc.bubuit.net](https://aitbc.bubuit.net)
2. Navigate to the **Marketplace** to browse available AI services
3. Connect your wallet or create an account
4. Submit your first AI job
### Option 2: Use the CLI
```bash
# Install the CLI wrapper
curl -O https://aitbc.bubuit.net/cli/aitbc-cli.sh
chmod +x aitbc-cli.sh
# Check available services
./aitbc-cli.sh status
# Submit a job
./aitbc-cli.sh submit "Your prompt here" --model llama3.2
```
### Option 3: Use the SDK
**Python:**
```python
from aitbc_sdk import AITBCClient
client = AITBCClient(api_url="https://aitbc.bubuit.net/api")
result = client.submit_job(
prompt="Explain quantum computing",
model="llama3.2"
)
print(result.output)
```
## Core Concepts
### Jobs
A job is a unit of work submitted to the network. It includes:
- **Prompt**: Your input (text, image, etc.)
- **Model**: The AI model to use (e.g., `llama3.2`, `stable-diffusion`)
- **Parameters**: Optional settings (temperature, max tokens, etc.)
### Receipts
After a job completes, you receive a **receipt** containing:
- Job ID and status
- Compute units consumed
- Miner who processed the job
- Cryptographic proof of completion
### Tokens
AITBC tokens are used to:
- Pay for compute jobs
- Reward miners for providing resources
- Participate in governance
## Your First Job
1. **Connect your wallet** at the Exchange or create an account
2. **Get some AITBC tokens** (see [Bitcoin Wallet Setup](BITCOIN-WALLET-SETUP.md))
3. **Submit a job** via web, CLI, or SDK
4. **Wait for completion** (typically seconds to minutes)
5. **View your receipt** in the Explorer
## Next Steps
- [Job Submission Workflow](job-submission.md) - Detailed guide on submitting jobs
- [Payments and Receipts](payments-receipts.md) - Understanding the payment flow
- [Troubleshooting](troubleshooting.md) - Common issues and solutions
- [User Interface Guide](USER-INTERFACE-GUIDE.md) - Navigating the web interface
## Getting Help
- **Documentation**: [https://aitbc.bubuit.net/docs/](https://aitbc.bubuit.net/docs/)
- **Explorer**: [https://aitbc.bubuit.net/explorer/](https://aitbc.bubuit.net/explorer/)
- **API Reference**: [https://aitbc.bubuit.net/api/docs](https://aitbc.bubuit.net/api/docs)

View File

@@ -0,0 +1,163 @@
# Job Submission Workflow
This guide explains how to submit AI compute jobs to the AITBC network and track their progress.
## Overview
The job submission workflow:
1. **Prepare** - Choose model and parameters
2. **Submit** - Send job to Coordinator API
3. **Queue** - Job enters the processing queue
4. **Execute** - Miner processes your job
5. **Complete** - Receive results and receipt
## Submission Methods
### Web Interface
1. Go to [Marketplace](https://aitbc.bubuit.net/marketplace/)
2. Select a service (e.g., "Text Generation", "Image Generation")
3. Enter your prompt and configure options
4. Click **Submit Job**
5. View job status in your dashboard
### CLI
```bash
# Basic submission
./aitbc-cli.sh submit "Explain machine learning in simple terms"
# With model selection
./aitbc-cli.sh submit "Generate a haiku about coding" --model llama3.2
# With parameters
./aitbc-cli.sh submit "Write a story" --model llama3.2 --max-tokens 500 --temperature 0.7
# Check job status
./aitbc-cli.sh status <job_id>
# List your jobs
./aitbc-cli.sh jobs
```
### Python SDK
```python
from aitbc_sdk import AITBCClient
client = AITBCClient(
api_url="https://aitbc.bubuit.net/api",
api_key="your-api-key" # Optional for authenticated requests
)
# Submit a text generation job
job = client.submit_job(
prompt="What is the capital of France?",
model="llama3.2",
params={
"max_tokens": 100,
"temperature": 0.5
}
)
print(f"Job ID: {job.id}")
print(f"Status: {job.status}")
# Wait for completion
result = client.wait_for_job(job.id, timeout=60)
print(f"Output: {result.output}")
```
### Direct API
```bash
# Submit job
curl -X POST https://aitbc.bubuit.net/api/v1/jobs \
-H "Content-Type: application/json" \
-d '{
"prompt": "Hello, world!",
"model": "llama3.2",
"params": {"max_tokens": 50}
}'
# Check status
curl https://aitbc.bubuit.net/api/v1/jobs/<job_id>
```
## Job Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `prompt` | string | required | Input text or instruction |
| `model` | string | `llama3.2` | AI model to use |
| `max_tokens` | int | 256 | Maximum output tokens |
| `temperature` | float | 0.7 | Creativity (0.0-1.0) |
| `top_p` | float | 0.9 | Nucleus sampling |
| `stream` | bool | false | Stream output chunks |
## Available Models
| Model | Type | Use Case |
|-------|------|----------|
| `llama3.2` | Text | General chat, Q&A, writing |
| `llama3.2:1b` | Text | Fast, lightweight tasks |
| `codellama` | Code | Code generation, debugging |
| `stable-diffusion` | Image | Image generation |
## Job States
| State | Description |
|-------|-------------|
| `pending` | Job submitted, waiting for miner |
| `running` | Miner is processing the job |
| `completed` | Job finished successfully |
| `failed` | Job failed (see error message) |
| `cancelled` | Job was cancelled by user |
## Tracking Your Jobs
### View in Explorer
Visit [Explorer](https://aitbc.bubuit.net/explorer/) to see:
- Recent jobs and their status
- Your job history (if authenticated)
- Receipt details and proofs
### Programmatic Tracking
```python
# Poll for status
import time
while True:
job = client.get_job(job_id)
print(f"Status: {job.status}")
if job.status in ["completed", "failed", "cancelled"]:
break
time.sleep(2)
```
## Cancelling Jobs
```bash
# CLI
./aitbc-cli.sh cancel <job_id>
# API
curl -X POST https://aitbc.bubuit.net/api/v1/jobs/<job_id>/cancel
```
## Best Practices
1. **Be specific** - Clear prompts get better results
2. **Set appropriate limits** - Use `max_tokens` to control costs
3. **Handle errors** - Always check job status before using output
4. **Use streaming** - For long outputs, enable streaming for faster feedback
## Next Steps
- [Payments and Receipts](payments-receipts.md) - Understanding costs and proofs
- [Troubleshooting](troubleshooting.md) - Common issues and solutions

View File

@@ -0,0 +1,156 @@
# Payments and Receipts
This guide explains how payments work on the AITBC network and how to understand your receipts.
## Payment Flow
```
Client submits job → Job processed by miner → Receipt generated → Payment settled
```
### Step-by-Step
1. **Job Submission**: You submit a job with your prompt and parameters
2. **Miner Selection**: The Coordinator assigns your job to an available miner
3. **Processing**: The miner executes your job using their GPU
4. **Receipt Creation**: A cryptographic receipt is generated proving work completion
5. **Settlement**: AITBC tokens are transferred from client to miner
## Understanding Receipts
Every completed job generates a receipt containing:
| Field | Description |
|-------|-------------|
| `receipt_id` | Unique identifier for this receipt |
| `job_id` | The job this receipt is for |
| `provider` | Miner address who processed the job |
| `client` | Your address (who requested the job) |
| `units` | Compute units consumed (e.g., GPU seconds) |
| `price` | Amount paid in AITBC tokens |
| `model` | AI model used |
| `started_at` | When processing began |
| `completed_at` | When processing finished |
| `signature` | Cryptographic proof of authenticity |
### Example Receipt
```json
{
"receipt_id": "rcpt-20260124-001234",
"job_id": "job-abc123",
"provider": "ait1miner...",
"client": "ait1client...",
"units": 2.5,
"unit_type": "gpu_seconds",
"price": 5.0,
"model": "llama3.2",
"started_at": 1737730800,
"completed_at": 1737730803,
"signature": {
"alg": "Ed25519",
"key_id": "miner-ed25519-2026-01",
"sig": "Fql0..."
}
}
```
## Viewing Your Receipts
### Explorer
Visit [Explorer → Receipts](https://aitbc.bubuit.net/explorer/#/receipts) to see:
- All recent receipts on the network
- Filter by your address to see your history
- Click any receipt for full details
### CLI
```bash
# List your receipts
./aitbc-cli.sh receipts
# Get specific receipt
./aitbc-cli.sh receipt <receipt_id>
```
### API
```bash
curl https://aitbc.bubuit.net/api/v1/receipts?client=<your_address>
```
## Pricing
### How Pricing Works
- Jobs are priced in **compute units** (typically GPU seconds)
- Each model has a base rate per compute unit
- Final price = `units × rate`
### Current Rates
| Model | Rate (AITBC/unit) | Typical Job Cost |
|-------|-------------------|------------------|
| `llama3.2` | 2.0 | 2-10 AITBC |
| `llama3.2:1b` | 0.5 | 0.5-2 AITBC |
| `codellama` | 2.5 | 3-15 AITBC |
| `stable-diffusion` | 5.0 | 10-50 AITBC |
*Rates may vary based on network demand and miner availability.*
## Getting AITBC Tokens
### Via Exchange
1. Visit [Trade Exchange](https://aitbc.bubuit.net/Exchange/)
2. Create an account or connect wallet
3. Send Bitcoin to your deposit address
4. Receive AITBC at current exchange rate (1 BTC = 100,000 AITBC)
See [Bitcoin Wallet Setup](BITCOIN-WALLET-SETUP.md) for detailed instructions.
### Via Mining
Earn AITBC by providing GPU compute:
- See [Miner Documentation](../../reference/components/miner_node.md)
## Verifying Receipts
Receipts are cryptographically signed to ensure authenticity.
### Signature Verification
```python
from aitbc_crypto import verify_receipt
receipt = get_receipt("rcpt-20260124-001234")
is_valid = verify_receipt(receipt)
print(f"Receipt valid: {is_valid}")
```
### On-Chain Verification
Receipts can be anchored on-chain for permanent proof:
- ZK proofs enable privacy-preserving verification
- See [ZK Applications](../../reference/components/zk-applications.md)
## Payment Disputes
If you believe a payment was incorrect:
1. **Check the receipt** - Verify units and price match expectations
2. **Compare to job output** - Ensure you received the expected result
3. **Contact support** - If discrepancy exists, report via the platform
## Best Practices
1. **Monitor your balance** - Check before submitting large jobs
2. **Set spending limits** - Use API keys with rate limits
3. **Keep receipts** - Download important receipts for records
4. **Verify signatures** - For high-value transactions, verify cryptographically
## Next Steps
- [Troubleshooting](troubleshooting.md) - Common payment issues
- [Getting Started](getting-started.md) - Back to basics

View File

@@ -0,0 +1,208 @@
# Troubleshooting Guide
Common issues and solutions when using the AITBC network.
## Job Issues
### Job Stuck in "Pending" State
**Symptoms**: Job submitted but stays in `pending` for a long time.
**Causes**:
- No miners currently available
- Network congestion
- Model not supported by available miners
**Solutions**:
1. Wait a few minutes - miners may become available
2. Check network status at [Explorer](https://aitbc.bubuit.net/explorer/)
3. Try a different model (e.g., `llama3.2:1b` instead of `llama3.2`)
4. Cancel and resubmit during off-peak hours
```bash
# Check job status
./aitbc-cli.sh status <job_id>
# Cancel if needed
./aitbc-cli.sh cancel <job_id>
```
### Job Failed
**Symptoms**: Job status shows `failed` with an error message.
**Common Errors**:
| Error | Cause | Solution |
|-------|-------|----------|
| `Model not found` | Invalid model name | Check available models |
| `Prompt too long` | Input exceeds limit | Shorten your prompt |
| `Timeout` | Job took too long | Reduce `max_tokens` or simplify prompt |
| `Miner disconnected` | Miner went offline | Resubmit job |
| `Insufficient balance` | Not enough AITBC | Top up your balance |
### Unexpected Output
**Symptoms**: Job completed but output is wrong or truncated.
**Solutions**:
1. **Truncated output**: Increase `max_tokens` parameter
2. **Wrong format**: Be more specific in your prompt
3. **Gibberish**: Lower `temperature` (try 0.3-0.5)
4. **Off-topic**: Rephrase prompt to be clearer
## Connection Issues
### Cannot Connect to API
**Symptoms**: `Connection refused` or `timeout` errors.
**Solutions**:
1. Check your internet connection
2. Verify API URL: `https://aitbc.bubuit.net/api`
3. Check if service is up at [Explorer](https://aitbc.bubuit.net/explorer/)
4. Try again in a few minutes
```bash
# Test connectivity
curl -I https://aitbc.bubuit.net/api/health
```
### Authentication Failed
**Symptoms**: `401 Unauthorized` or `Invalid API key` errors.
**Solutions**:
1. Verify your API key is correct
2. Check if API key has expired
3. Ensure API key has required permissions
4. Generate a new API key if needed
## Wallet Issues
### Cannot Connect Wallet
**Symptoms**: Wallet connection fails or times out.
**Solutions**:
1. Ensure browser extension is installed and unlocked
2. Refresh the page and try again
3. Check if wallet is on correct network
4. Clear browser cache and cookies
### Transaction Not Showing
**Symptoms**: Sent tokens but balance not updated.
**Solutions**:
1. Wait for confirmation (may take a few minutes)
2. Check transaction in Explorer
3. Verify you sent to correct address
4. Contact support if still missing after 1 hour
### Insufficient Balance
**Symptoms**: `Insufficient balance` error when submitting job.
**Solutions**:
1. Check your current balance
2. Top up via [Exchange](https://aitbc.bubuit.net/Exchange/)
3. Wait for pending deposits to confirm
## CLI Issues
### Command Not Found
**Symptoms**: `aitbc-cli.sh: command not found`
**Solutions**:
```bash
# Make script executable
chmod +x aitbc-cli.sh
# Run with explicit path
./aitbc-cli.sh status
# Or add to PATH
export PATH=$PATH:$(pwd)
```
### Permission Denied
**Symptoms**: `Permission denied` when running CLI.
**Solutions**:
```bash
chmod +x aitbc-cli.sh
```
### SSL Certificate Error
**Symptoms**: `SSL certificate problem` or `certificate verify failed`
**Solutions**:
```bash
# Update CA certificates
sudo apt update && sudo apt install ca-certificates
# Or skip verification (not recommended for production)
curl -k https://aitbc.bubuit.net/api/health
```
## Performance Issues
### Slow Response Times
**Symptoms**: Jobs take longer than expected.
**Causes**:
- Large prompt or output
- Complex model
- Network congestion
- Miner hardware limitations
**Solutions**:
1. Use smaller models for simple tasks
2. Reduce `max_tokens` if full output not needed
3. Submit during off-peak hours
4. Use streaming for faster first-token response
### Rate Limited
**Symptoms**: `429 Too Many Requests` error.
**Solutions**:
1. Wait before retrying (check `Retry-After` header)
2. Reduce request frequency
3. Use exponential backoff in your code
4. Request higher rate limits if needed
## Getting Help
### Self-Service Resources
- **Documentation**: [https://aitbc.bubuit.net/docs/](https://aitbc.bubuit.net/docs/)
- **API Reference**: [https://aitbc.bubuit.net/api/docs](https://aitbc.bubuit.net/api/docs)
- **Explorer**: [https://aitbc.bubuit.net/explorer/](https://aitbc.bubuit.net/explorer/)
### Reporting Issues
When reporting an issue, include:
1. **Job ID** (if applicable)
2. **Error message** (exact text)
3. **Steps to reproduce**
4. **Expected vs actual behavior**
5. **Timestamp** of when issue occurred
### Debug Mode
Enable verbose logging for troubleshooting:
```bash
# CLI debug mode
DEBUG=1 ./aitbc-cli.sh submit "test"
# Python SDK
import logging
logging.basicConfig(level=logging.DEBUG)
```