- Update key capabilities to include GPU marketplace, payments, billing, and governance - Expand CLI section from basic examples to 12 command groups with 90+ subcommands - Add detailed test results table showing 208 passing tests across 6 test suites - Update documentation links to reference new CLI reference and coordinator API docs - Revise test commands to reflect actual test structure (
334 lines
12 KiB
Markdown
334 lines
12 KiB
Markdown
# AITBC Receipt Specification (Draft)
|
|
|
|
## Overview
|
|
|
|
This document defines the canonical schema and serialization rules for receipts generated by the AITBC network after miners complete compute jobs. Receipts serve as tamper-evident evidence tying compute usage to token minting events.
|
|
|
|
## Receipt Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `version` | string | yes | Receipt schema version (e.g., `"1.0"`). |
|
|
| `receipt_id` | string | yes | Unique identifier for this receipt. SHOULD be globally unique (UUID or hash). |
|
|
| `job_id` | string | yes | Identifier of the coordinator job this receipt references. |
|
|
| `provider` | string | yes | Miner address/account that executed the job. |
|
|
| `client` | string | yes | Client address/account that requested the job. |
|
|
| `units` | number | yes | Compute units earned by the miner (token minting basis). |
|
|
| `unit_type` | string | yes | Unit denomination (e.g., `"gpu_seconds"`, `"token_ops"`). |
|
|
| `price` | number | optional | Price paid by the client for the job (same unit as `units` if applicable). |
|
|
| `model` | string | optional | Model or workload identifier (e.g., `"runwayml/stable-diffusion-v1-5"`). |
|
|
| `prompt_hash` | string | optional | Hash of user prompt or workload input to preserve privacy. |
|
|
| `started_at` | integer | yes | Unix timestamp (seconds) when the job started. |
|
|
| `completed_at` | integer | yes | Unix timestamp when the job completed. |
|
|
| `duration_ms` | integer | optional | Milliseconds elapsed during execution. |
|
|
| `artifact_hash` | string | optional | SHA-256 hash of the result artifact(s). |
|
|
| `coordinator_id` | string | optional | Coordinator identifier if multiple coordinators exist. |
|
|
| `nonce` | string | optional | Unique nonce to prevent replay/double minting. |
|
|
| `chain_id` | integer | optional | Target chain/network identifier. |
|
|
| `metadata` | object | optional | Arbitrary key/value pairs for future extensions. |
|
|
| `signature` | object | conditional | Signature object (see below). |
|
|
|
|
### Signature Object
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `alg` | string | yes | Signature algorithm (e.g., `"Ed25519"`, `"secp256k1"`). |
|
|
| `key_id` | string | yes | Identifier of signing key (e.g., `"miner-ed25519-2025-09"`). |
|
|
| `sig` | string | yes | Base64url-encoded signature over the canonical receipt bytes. |
|
|
|
|
Receipts SHOULD be signed by either the miner, coordinator attester, or both depending on trust model. Multiple signatures can be supported by storing them in `metadata.signatures` array.
|
|
|
|
## Canonical Serialization
|
|
|
|
1. Construct a JSON object containing all fields except `signature`.
|
|
2. Remove any fields with null/undefined values.
|
|
3. Sort keys lexicographically at each object level.
|
|
4. Serialize using UTF-8 without whitespace (RFC 8785 style).
|
|
5. Compute hash as `sha256(serialized_json)` for Ed25519 signing.
|
|
6. Attach `signature` object containing algorithm, key ID, and base64url signature over the hash.
|
|
|
|
## Validation Rules
|
|
|
|
- `completed_at >= started_at`.
|
|
- `units >= 0` and `price >= 0` when present.
|
|
- `signature.alg` MUST be one of the network approved algorithms (initially `Ed25519`).
|
|
- `chain_id` SHOULD match the target blockchain network when provided.
|
|
- Reject receipts older than network-defined retention period.
|
|
|
|
## Example Receipt (unsigned)
|
|
|
|
```json
|
|
{
|
|
"version": "1.0",
|
|
"receipt_id": "rcpt-20250926-000123",
|
|
"job_id": "job-abc123",
|
|
"provider": "ait1minerxyz...",
|
|
"client": "ait1clientabc...",
|
|
"units": 1.9,
|
|
"unit_type": "gpu_seconds",
|
|
"price": 4.2,
|
|
"model": "runwayml/stable-diffusion-v1-5",
|
|
"prompt_hash": "sha256:cf1f...",
|
|
"started_at": 1695720000,
|
|
"completed_at": 1695720002,
|
|
"artifact_hash": "sha256:deadbeef...",
|
|
"coordinator_id": "coord-eu-west-1",
|
|
"nonce": "b7f3d10b",
|
|
"chain_id": 12345
|
|
}
|
|
```
|
|
|
|
Signed form includes:
|
|
|
|
```json
|
|
"signature": {
|
|
"alg": "Ed25519",
|
|
"key_id": "miner-ed25519-2025-09",
|
|
"sig": "Fql0..."
|
|
}
|
|
```
|
|
|
|
## Multi-Signature Receipt Format
|
|
|
|
Receipts requiring attestation from multiple parties (e.g., miner + coordinator) use a `signatures` array instead of a single `signature` object.
|
|
|
|
### Schema
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `signatures` | array | conditional | Array of signature objects when multi-sig is used. |
|
|
| `threshold` | integer | optional | Minimum signatures required for validity (default: all). |
|
|
| `quorum_policy` | string | optional | Policy name: `"all"`, `"majority"`, `"threshold"`. |
|
|
|
|
### Signature Entry
|
|
|
|
Each entry in the `signatures` array:
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `alg` | string | yes | Signature algorithm (`"Ed25519"`, `"secp256k1"`). |
|
|
| `key_id` | string | yes | Signing key identifier. |
|
|
| `signer_role` | string | yes | Role of signer: `"miner"`, `"coordinator"`, `"auditor"`. |
|
|
| `signer_id` | string | yes | Address or account of the signer. |
|
|
| `sig` | string | yes | Base64url-encoded signature over canonical receipt bytes. |
|
|
| `signed_at` | integer | yes | Unix timestamp when signature was created. |
|
|
|
|
### Validation Rules
|
|
|
|
- When `signatures` is present, `signature` (singular) MUST be absent.
|
|
- Each signature is computed over the same canonical serialization (excluding all signature fields).
|
|
- `threshold` defaults to `len(signatures)` (all required) when omitted.
|
|
- Signers MUST NOT appear more than once in the array.
|
|
- At least one signer with `signer_role: "miner"` is required.
|
|
|
|
### Example
|
|
|
|
```json
|
|
{
|
|
"version": "1.1",
|
|
"receipt_id": "rcpt-20260212-ms001",
|
|
"job_id": "job-xyz789",
|
|
"provider": "ait1minerabc...",
|
|
"client": "ait1clientdef...",
|
|
"units": 3.5,
|
|
"unit_type": "gpu_seconds",
|
|
"started_at": 1739376000,
|
|
"completed_at": 1739376004,
|
|
"threshold": 2,
|
|
"quorum_policy": "all",
|
|
"signatures": [
|
|
{
|
|
"alg": "Ed25519",
|
|
"key_id": "miner-ed25519-2026-02",
|
|
"signer_role": "miner",
|
|
"signer_id": "ait1minerabc...",
|
|
"sig": "Xk9f...",
|
|
"signed_at": 1739376005
|
|
},
|
|
{
|
|
"alg": "Ed25519",
|
|
"key_id": "coord-ed25519-2026-01",
|
|
"signer_role": "coordinator",
|
|
"signer_id": "coord-eu-west-1",
|
|
"sig": "Lm3a...",
|
|
"signed_at": 1739376006
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ZK-Proof Metadata Extension
|
|
|
|
Receipts can carry zero-knowledge proof metadata in the `metadata.zk_proof` field, enabling privacy-preserving verification without revealing sensitive job details.
|
|
|
|
### Schema (`metadata.zk_proof`)
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `circuit_id` | string | yes | Identifier of the ZK circuit used (e.g., `"SimpleReceipt_v1"`). |
|
|
| `circuit_version` | integer | yes | Circuit version number. |
|
|
| `proof_system` | string | yes | Proof system: `"groth16"`, `"plonk"`, `"stark"`. |
|
|
| `proof` | object | yes | Proof data (system-specific). |
|
|
| `public_signals` | array | yes | Public inputs to the circuit. |
|
|
| `verifier_contract` | string | optional | On-chain verifier contract address. |
|
|
| `verification_key_hash` | string | optional | SHA-256 hash of the verification key. |
|
|
| `generated_at` | integer | yes | Unix timestamp of proof generation. |
|
|
|
|
### Groth16 Proof Object
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `a` | array[2] | G1 point (π_A). |
|
|
| `b` | array[2][2] | G2 point (π_B). |
|
|
| `c` | array[2] | G1 point (π_C). |
|
|
|
|
### Public Signals
|
|
|
|
For the `SimpleReceipt` circuit, `public_signals` contains:
|
|
- `[0]`: `receiptHash` — Poseidon hash of private receipt data.
|
|
|
|
For the full `ReceiptAttestation` circuit:
|
|
- `[0]`: `receiptHash`
|
|
- `[1]`: `settlementAmount`
|
|
- `[2]`: `timestamp`
|
|
|
|
### Validation Rules
|
|
|
|
- `circuit_id` MUST match a known registered circuit.
|
|
- `public_signals[0]` (receiptHash) MUST NOT be zero.
|
|
- If `verifier_contract` is provided, on-chain verification SHOULD be performed.
|
|
- Proof MUST be verified before the receipt is accepted for settlement.
|
|
|
|
### Example
|
|
|
|
```json
|
|
{
|
|
"version": "1.1",
|
|
"receipt_id": "rcpt-20260212-zk001",
|
|
"job_id": "job-priv001",
|
|
"provider": "ait1minerxyz...",
|
|
"client": "ait1clientabc...",
|
|
"units": 2.0,
|
|
"unit_type": "gpu_seconds",
|
|
"started_at": 1739376000,
|
|
"completed_at": 1739376003,
|
|
"metadata": {
|
|
"zk_proof": {
|
|
"circuit_id": "SimpleReceipt_v1",
|
|
"circuit_version": 1,
|
|
"proof_system": "groth16",
|
|
"proof": {
|
|
"a": ["0x1a2b...", "0x3c4d..."],
|
|
"b": [["0x5e6f...", "0x7a8b..."], ["0x9c0d...", "0xef12..."]],
|
|
"c": ["0x3456...", "0x7890..."]
|
|
},
|
|
"public_signals": ["0x48fa91c3..."],
|
|
"verifier_contract": "0xAbCdEf0123456789...",
|
|
"verification_key_hash": "sha256:a1b2c3d4...",
|
|
"generated_at": 1739376004
|
|
}
|
|
},
|
|
"signature": {
|
|
"alg": "Ed25519",
|
|
"key_id": "miner-ed25519-2026-02",
|
|
"sig": "Qr7x..."
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Merkle Proof Anchoring Specification
|
|
|
|
Receipts can be anchored on-chain using Merkle trees, allowing efficient batch verification and compact inclusion proofs.
|
|
|
|
### Anchoring Process
|
|
|
|
1. **Batch collection**: Coordinator collects N receipts within a time window.
|
|
2. **Leaf computation**: Each leaf = `sha256(canonical_receipt_bytes)`.
|
|
3. **Tree construction**: Binary Merkle tree with leaves sorted by `receipt_id`.
|
|
4. **Root submission**: Merkle root is submitted on-chain in a single transaction.
|
|
5. **Proof distribution**: Each receipt owner receives their inclusion proof.
|
|
|
|
### Schema (`metadata.merkle_anchor`)
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `root` | string | yes | Hex-encoded Merkle root (`0x...`). |
|
|
| `leaf` | string | yes | Hex-encoded leaf hash of this receipt. |
|
|
| `proof` | array | yes | Array of sibling hashes from leaf to root. |
|
|
| `index` | integer | yes | Leaf index in the tree (0-based). |
|
|
| `tree_size` | integer | yes | Total number of leaves in the tree. |
|
|
| `block_height` | integer | optional | Blockchain block height where root was anchored. |
|
|
| `tx_hash` | string | optional | Transaction hash of the anchoring transaction. |
|
|
| `anchored_at` | integer | yes | Unix timestamp of anchoring. |
|
|
|
|
### Verification Algorithm
|
|
|
|
```
|
|
1. leaf_hash = sha256(canonical_receipt_bytes)
|
|
2. assert leaf_hash == anchor.leaf
|
|
3. current = leaf_hash
|
|
4. for i, sibling in enumerate(anchor.proof):
|
|
5. if bit(anchor.index, i) == 0:
|
|
6. current = sha256(current || sibling)
|
|
7. else:
|
|
8. current = sha256(sibling || current)
|
|
9. assert current == anchor.root
|
|
```
|
|
|
|
### Validation Rules
|
|
|
|
- `leaf` MUST equal `sha256(canonical_receipt_bytes)` of the receipt.
|
|
- `proof` length MUST equal `ceil(log2(tree_size))`.
|
|
- `index` MUST be in range `[0, tree_size)`.
|
|
- If `tx_hash` is provided, the root MUST match the on-chain value.
|
|
- Merkle roots MUST be submitted within the network retention window.
|
|
|
|
### Example
|
|
|
|
```json
|
|
{
|
|
"version": "1.1",
|
|
"receipt_id": "rcpt-20260212-mk001",
|
|
"job_id": "job-batch42",
|
|
"provider": "ait1minerxyz...",
|
|
"client": "ait1clientabc...",
|
|
"units": 1.0,
|
|
"unit_type": "gpu_seconds",
|
|
"started_at": 1739376000,
|
|
"completed_at": 1739376001,
|
|
"metadata": {
|
|
"merkle_anchor": {
|
|
"root": "0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069",
|
|
"leaf": "0x3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d",
|
|
"proof": [
|
|
"0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
|
"0x486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7"
|
|
],
|
|
"index": 2,
|
|
"tree_size": 4,
|
|
"block_height": 15234,
|
|
"tx_hash": "0xabc123def456...",
|
|
"anchored_at": 1739376060
|
|
}
|
|
},
|
|
"signature": {
|
|
"alg": "Ed25519",
|
|
"key_id": "coord-ed25519-2026-01",
|
|
"sig": "Yz4w..."
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Version History
|
|
|
|
| Version | Date | Changes |
|
|
|---------|------|---------|
|
|
| 1.0 | 2025-09 | Initial receipt schema, Ed25519 signatures, canonical serialization. |
|
|
| 1.1 | 2026-02 | Multi-signature format, ZK-proof metadata extension, Merkle proof anchoring. |
|