refine blockchain integration and protocols
This commit is contained in:
25
docs/issues/31-billing-ledger.md
Normal file
25
docs/issues/31-billing-ledger.md
Normal file
@@ -0,0 +1,25 @@
|
||||
Status: ready-for-agent
|
||||
|
||||
# 31 — Billing ledger: per-token pricing, 90/10 split, pending balances
|
||||
|
||||
## What to build
|
||||
|
||||
Tracker-side off-chain billing per ADR-0015. Each model preset gets a USDT `price_per_1k_tokens` in tracker config. When a request completes, the tracker debits the client's API-key ledger balance (`price × total_tokens / 1000`) and credits 90% to the serving nodes' pending balances proportional to work units (layers × tokens, reusing the existing `ComputeAttribution`), with 10% accruing to the protocol cut. API keys with insufficient balance are rejected with HTTP 402 before any routing happens — no free work.
|
||||
|
||||
The ledger persists in the existing tracker SQLite store and replicates across the tracker hive so any follower can serve balance reads.
|
||||
|
||||
This story is pure off-chain accounting — no Solana calls.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Per-model `price_per_1k_tokens` in tracker config with sane defaults
|
||||
- [ ] Completed request debits client ledger: `price × total_tokens / 1000`
|
||||
- [ ] 90% split across serving nodes by work_units; 10% accrues to `protocol_cut`
|
||||
- [ ] Insufficient balance → HTTP 402 before routing
|
||||
- [ ] Balances survive tracker restart (SQLite) and replicate to hive followers
|
||||
- [ ] Unit tests: single-node route, 3-node split, exhausted balance, restart persistence
|
||||
|
||||
## Blocked by
|
||||
|
||||
- `23-heartbeat-stats.md`
|
||||
- `25-rolling-rpm-stats.md`
|
||||
28
docs/issues/32-devnet-treasury-deposits.md
Normal file
28
docs/issues/32-devnet-treasury-deposits.md
Normal file
@@ -0,0 +1,28 @@
|
||||
Status: ready-for-agent
|
||||
|
||||
# 32 — Devnet custodial treasury: mock-USDT mint + deposit watcher
|
||||
|
||||
## What to build
|
||||
|
||||
The real Solana adapter behind the `packages/contracts` boundary, custodial model per ADR-0015. All on-chain surface is plain SPL transfers — no Anchor programs.
|
||||
|
||||
**Setup script** (`scripts/devnet_setup.py`): creates the mock-USDT SPL mint (6 decimals, matching real USDT) and the treasury token account on devnet, airdropping SOL for fees, and prints the `.env.devnet` values (mint address, RPC URL, treasury keypair path).
|
||||
|
||||
**Wallet binding**: `POST /v1/wallet/register` binds a client wallet pubkey to an API key.
|
||||
|
||||
**Deposit watcher**: polls the treasury token account for confirmed incoming USDT transfers and credits the sending wallet's bound API-key ledger balance. Transaction signatures are deduplicated so replayed/re-observed transfers credit exactly once.
|
||||
|
||||
Note: this supersedes the "testnet, never devnet" note in issue 06 (see ADR-0015) — devnet is the ecosystem standard for app development and real USDT exists on neither cluster.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `scripts/devnet_setup.py` creates mint + treasury ATA and prints `.env.devnet` values
|
||||
- [ ] `POST /v1/wallet/register` binds client wallet pubkey to API key
|
||||
- [ ] Deposit watcher credits ledger within one poll interval of a confirmed transfer
|
||||
- [ ] Duplicate/replayed transactions credit exactly once (signature dedupe)
|
||||
- [ ] Local `solana-test-validator` integration test covers mint → deposit → credit
|
||||
- [ ] Deterministic local adapter still works for CI without any validator
|
||||
|
||||
## Blocked by
|
||||
|
||||
- `31-billing-ledger.md`
|
||||
27
docs/issues/33-settlement-loop.md
Normal file
27
docs/issues/33-settlement-loop.md
Normal file
@@ -0,0 +1,27 @@
|
||||
Status: ready-for-agent
|
||||
|
||||
# 33 — Settlement loop: leader-only batched USDT payouts
|
||||
|
||||
## What to build
|
||||
|
||||
The on-chain settlement loop per ADR-0015, following the mining-pool standard: pay a node when `pending ≥ payout_threshold` OR `time_since_last_payout ≥ max_period`, whichever fires first, with a dust floor so no payout is smaller than it is worth.
|
||||
|
||||
Only the current Raft leader runs the loop; followers replicate the ledger but never sign. The treasury keypair is loaded only on settlement-capable trackers. Payouts are batched SPL transfers treasury → node wallets on devnet.
|
||||
|
||||
Config (all dynamic, so the period can grow with volume): dev defaults `period=60s, threshold≈0` so every run is verifiable on-chain; prod defaults `period=24h, threshold=a few USDT`.
|
||||
|
||||
Settlement history (settlement id, tx signature, node wallet, amount, timestamp) persists in SQLite, replicates across the hive, and is queryable over HTTP. Retries are idempotent by settlement id — a failed or timed-out transaction never double-pays.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Only the Raft leader settles; followers never sign (asserted in a 3-tracker test)
|
||||
- [ ] Trigger: `pending ≥ threshold` OR `elapsed ≥ max_period`; dust floor respected
|
||||
- [ ] Batched SPL transfers land on devnet; pending balances zeroed atomically with recorded tx signature
|
||||
- [ ] Failed/timeout transactions retry without double-pay (idempotent by settlement id)
|
||||
- [ ] Settlement history queryable via tracker HTTP endpoint
|
||||
- [ ] End-to-end devnet test: fund client → run inference → node wallet USDT balance increases
|
||||
|
||||
## Blocked by
|
||||
|
||||
- `19-binary-data-plane-and-peer-weight-transfer.md`
|
||||
- `32-devnet-treasury-deposits.md`
|
||||
28
docs/issues/34-forfeiture-penalty.md
Normal file
28
docs/issues/34-forfeiture-penalty.md
Normal file
@@ -0,0 +1,28 @@
|
||||
Status: ready-for-agent
|
||||
|
||||
# 34 — Hardened proof-of-work: pending-balance forfeiture penalty
|
||||
|
||||
## What to build
|
||||
|
||||
Wire the validator's ~5% sampling (issue 07) to the new penalty per ADR-0015. On confirmed output divergence:
|
||||
|
||||
1. The node's **entire pending balance is forfeited** to the protocol cut, in the same ledger transaction as the strike (no window where a payout can race the penalty).
|
||||
2. A **strike** is recorded; the third strike **bans** the wallet — registration rejected, excluded from all routes, and any unpaid pending balance is never paid out.
|
||||
|
||||
The probationary period (first N jobs unpaid, default 50) is retained as the anti-sybil re-entry cost, and the node CLI shows remaining probation jobs.
|
||||
|
||||
Why this deters cheating: settlement is periodic, so the pending balance itself is the collateral — no upfront stake deposit, zero onboarding friction. At a 5% check rate a cheater is caught once per ~20 fraudulent jobs, so the penalty must exceed ~20× the per-job gain; with daily settlement, pending ≈ a full day's earnings, well above that bar. Document this math in the validator README.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Divergence → pending balance forfeited to `protocol_cut` atomically with the strike
|
||||
- [ ] 3rd strike bans wallet: registration rejected, excluded from all routes
|
||||
- [ ] Banned wallet's unpaid pending balance is not paid at next settlement
|
||||
- [ ] Probation: first N jobs (default 50) accrue no pending balance; node CLI shows remaining
|
||||
- [ ] Integration test: deliberately-bad node loses pending, accrues strikes, banned within 60 requests
|
||||
- [ ] Forfeiture events visible in tracker logs and settlement history
|
||||
|
||||
## Blocked by
|
||||
|
||||
- `07-fraud-detection-slash.md`
|
||||
- `31-billing-ledger.md`
|
||||
34
docs/issues/35-tracker-web-dashboard.md
Normal file
34
docs/issues/35-tracker-web-dashboard.md
Normal file
@@ -0,0 +1,34 @@
|
||||
Status: ready-for-agent
|
||||
|
||||
# 35 — Tracker web dashboard
|
||||
|
||||
## What to build
|
||||
|
||||
A read-only web dashboard served by the tracker itself at `GET /dashboard` — single page, plain HTML/JS polling the tracker's HTTP endpoints, static assets embedded in the tracker package. No new build toolchain.
|
||||
|
||||
Because the tracker hive replicates ledger and registry state, **any tracker in the mesh — leader or follower — can serve the dashboard** from its own state.
|
||||
|
||||
Panels:
|
||||
|
||||
- Hive membership and current Raft leader
|
||||
- Node registry: health, scores, coverage map per model
|
||||
- Client ledger balances
|
||||
- Node pending balances and next-payout ETA
|
||||
- Settlement history with devnet explorer links (tx signatures)
|
||||
- Strikes / bans / forfeiture events
|
||||
- Rolling RPM stats per model
|
||||
|
||||
Write operations (editing prices, manual settlement trigger) are deferred to a later story.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] `GET /dashboard` serves the UI from any tracker (leader or follower)
|
||||
- [ ] All seven panels render with live data
|
||||
- [ ] Auto-refresh ≤5s without page reload
|
||||
- [ ] No new build toolchain — static assets embedded in the tracker package
|
||||
- [ ] Works against a 3-tracker hive in the two-machine LAN test setup
|
||||
|
||||
## Blocked by
|
||||
|
||||
- `31-billing-ledger.md`
|
||||
- `33-settlement-loop.md`
|
||||
Reference in New Issue
Block a user