| # Validator β Trainer Communication Map |
|
|
| Every channel between the subnet's roles, in one place: who writes, who reads, |
| what carries integrity, and what happens when several validators run at once. |
| `docs/ARCHITECTURE.md` explains *why* the round works this way; this page is |
| the wire-level *how*. |
|
|
| Terminology worth pinning down first: the **trainer** publishes the round's |
| **manifest** (signed training receipts); each **validator** publishes a round |
| **receipt** (signed scoring/weights record). Validators never post manifests β |
| they gate, score, set weights, and publish receipts. |
|
|
| ## The picture |
|
|
| ``` |
| Bittensor chain |
| commitments β² β commitments, β² weights |
| (gen refs) β β incentive, blocks β (per validator, |
| β βΌ β independent) |
| ββββββββββ βββββββββββββββββββββββ ββββββββββββββββ |
| β miners β β trainer β β validators β Γ N |
| ββββββββββ β (owner GPU boundary)β ββββββββββββββββ |
| β βββββββββββββββββββββββ β² β² β² β |
| β generator β checkpoints β manifest β β β β receipts (signed, |
| β repos βΌ βΌ β β β βΌ per-validator prefix) |
| βΌ βββββββββββββ βββββββββββββββββββββββββββββββββββ |
| βββββββββββββ β Hippius β β manifest bucket (Hippius S3) β |
| β Hippius β β Hub (OCI) β β manifests/β¦ logs/β¦ β |
| β Hub (OCI) β βββββββββββββ β receipts/<hotkey>/β¦ index.htmlβ |
| βββββββββββββ βββββββββββββββββββββββββββββββββββ |
| β² |
| βββββββββββββ pool bucket β snapshots (tar+sha256, |
| TSBench-Forge ββΊ β owner poolβ ββββββββββββββββ selected by |
| (private raw β builder β effective_block) |
| data bucket) βββββββββββββ |
| ``` |
|
|
| ## Channels |
|
|
| | # | Channel | Writer β Reader | Medium / key | Integrity | Multi-validator behaviour | |
| |---|---------|-----------------|--------------|-----------|---------------------------| |
| | 1 | Generator commitments | miner β trainer, validators | chain reveal commitments, `metro-v1:gen:hippius:<repo>@<digest>` | on-chain, digest-pinned | read-only; identical view per block | |
| | 2 | Round seed | chain β everyone | epoch-start block hash β `seed_from_block_hash` | consensus | deterministic, shared | |
| | 3 | Training manifest | trainer β validators | `manifests/round-<id>.json` + `manifests/latest.json` (manifest bucket) | signed by `[manifest] trainer_hotkey`; gated by `check_manifest` | read-only; single writer (the trainer) | |
| | 4 | Checkpoints / generators | trainer, miners β validators | Hippius Hub OCI, `repo@sha256:β¦` | content-addressed digest self-verifies | read-only | |
| | 5 | Eval pool | owner pool builder β validators | `pool/snapshots/block-<N>.tar` + `pool/index.json` (pool bucket) | sha256 pinned in the **signed manifest** (`eval_pool_key`/`eval_pool_sha256`, gated by `check_pool_pin`); index sha256 as legacy fallback for unpinned manifests | read-only; all validators resolve the same snapshot for a round and verify it against the pin | |
| | 6 | Weights | each validator β chain | `set_weights` | on-chain, per-hotkey | independent by construction β no shared state | |
| | 7 | Round receipts | each validator β auditors, dashboard | `receipts/<hotkey>/round-<id>.json` + `receipts/<hotkey>/latest.json`, shared `receipts/latest.json` pointer | signed per validator hotkey; public-read | **single-writer prefixes** β validators cannot clobber each other; only the convenience pointer is last-writer-wins | |
| | 8 | Receipts index | each validator β dashboard | `receipts/index.json`, entries keyed `(round_id, validator_hotkey)` | unsigned, presentational only | merge-keyed read-modify-write; a simultaneous write can drop one entry until that validator's next round β never audit- or weight-bearing | |
| | 8b | Live chain status | validator (or `scripts/publish_chain_status.py`) β dashboard | `status/chain.json`: block anchor, epoch grid, stage windows, revealed submissions (see `cascade.shared.chain_status`) | unsigned, presentational only | last-writer-wins whole-object overwrite β honest publishers write near-identical chain state; never audit- or weight-bearing | |
| | 9 | Training logs | trainer β observers | `logs/round-<id>/<role>.jsonl` (+ optional wandb) | none (observability) | read-only | |
| | 10 | Trainer β GPU pods | trainer orchestrator β rented pods | SSH, receipt-sentinel stdout | wallet never leaves the orchestrator | n/a | |
| | 11 | Validator β eval pod | validator β its own GPU pod | SSH+scp (`--eval-hosts`) | only public checkpoint + report cross | per-validator, private | |
|
|
| The channels a verdict depends on (1β6) are all either on-chain, signed, or |
| content-addressed *and* deterministic per round β N validators reach the same |
| verdict independently, which is why weights need no coordination. Channels |
| 7β9 are evidence and observability, never inputs to consensus. |
|
|
| Because storage keys aren't prefix-scoped, anyone holding a bucket's write |
| credentials can overwrite *any* object in it. The design assumes that and |
| anchors integrity above the storage layer: manifests fail the trainer-hotkey |
| signature gate if touched, checkpoints are digest-pinned, and the eval pool is |
| pinned inside the signed manifest. What write access *does* buy an attacker is |
| vandalism β deleted receipts, a defaced dashboard, stalled rounds β which is |
| detectable (signatures, the R2 mirror) but not preventable; the mitigation is |
| key hygiene: one pair per bucket, pool keys separate from manifest keys, forge |
| keys never shared beyond the owner. |
|
|
| ## What a validator needs access to β and only this |
|
|
| | Resource | Access | Credential | |
| |----------|--------|------------| |
| | Bittensor chain | read + `set_weights` | hotkey wallet | |
| | Manifest bucket | read `manifests/β¦`, write `receipts/<own hotkey>/β¦` + index | `HIPPIUS_S3_*` | |
| | Pool bucket | read-only snapshots | `POOL_S3_*` β issue a pair separate from the manifest-bucket keys (S3 keys aren't prefix-scoped; a shared pair could write the pool) | |
| | Hippius Hub | read (pull checkpoints/generators) | `HIPPIUS_HUB_TOKEN` | |
| | HF benchmark datasets + bench sidecar (opt-in only, see below) | public read | `HF_TOKEN` if gated | |
|
|
| The benchmark sidecar (`benchmarks/`, or an SSH eval pod via `--eval-hosts`) is |
| **not** part of a stock validator. All three of its call sites default off: |
| `[eval] run_benchmarks` (log-only numbers on a dethrone), `[scoring] |
| gift_gate_mode` (the gift-eval gate β the only mode in which the sidecar is |
| load-bearing, since `enforce` turns a sidecar failure into an inconclusive |
| round), and `[scoring] cascade_enabled` (warm-start promotion, which prefers |
| the trainer-signed `bench_scores` on the manifest and touches the sidecar only |
| as a non-consensus-safe fallback for manifests that carry none). |
|
|
| Deliberately **not** on the list: the TSBench-Forge raw-data bucket. Validators |
| consume forge data only through the built pool snapshots (channel 5). The raw |
| catalog + parquet relay (`tsbench-forge-sources` on Hippius β see |
| `docs/EVAL_POOL.md`) is an owner-orchestrator-side secret; keeping it private |
| is the anti-gaming lever that stops miners from fitting generators to the |
| held-out pool. |
|
|
| ## TSBench-Forge β validator data path |
|
|
| ``` |
| forge repo cron (scrape-data.yml) |
| ββ sync_storage.py ββΊ s3://tsbench-forge-sources [private, owner-only] |
| owner orchestrator |
| ββ aws s3 sync β¦ ./tsforge |
| cascade-pool publish --sources tsbench_forge ββΊ pool bucket snapshots |
| validators |
| ββ select snapshot by effective_block, verify sha256, rotate windows by round seed |
| ``` |
|
|
| One bucket contract end to end: `sources.yaml` + `data/<source_id>/<date>.parquet` |
| at the relay, deterministic tar + `pool/index.json` at the pool. The forge cron |
| and the pool-publish cron are decoupled; the staleness guard |
| (`max_stale_days`, fail-loud when every feed is stale) lives in the pool |
| builder so a dead scraper can't silently erode freshness. |
|
|