# cascade > cascade is a Bittensor subnet (mainnet netuid 91, testnet netuid 259) that builds > state-of-the-art time-series foundation models by competing on **synthetic training > data**. Miners submit deterministic, code-only data generators; the subnet owner's > trainer trains a fixed Toto2-4M forecaster on each generator's output **from the > round's shared init** (random at generation 0; the promoted cascade checkpoint > once a reign is promoted — live on mainnet) under a byte-identical contract, and > validators score the resulting models > on a private, rotating held-out set (CRPS + MASE). The best data holds the throne > (king-of-the-hill) and earns emissions. Miners need **no GPU** to compete. This file is written for LLMs and autonomous agents. It states the subnet's objective, the binding rules, and the exact mining workflow, with pointers into the repository docs that hold the full detail. When this summary and a linked doc or `chain.toml` disagree, `chain.toml` (the shipped config) and the docs win. ## Objective — what the subnet optimises - The task: produce a synthetic time-series **data generator** whose output trains a better zero-shot forecaster than the reigning king's data. The model (Toto2-4M, trained from the round's shared init) is byte-identical across all competitors; the ONLY variable is the generator code. This makes each round a controlled experiment on data quality, not architecture or hyperparameters. - Scoring: validators evaluate trained checkpoints on a **private, rotating** held-out pool of real-world windows (a jittered ~1200-window draw whose domain mix re-rolls every round, context 4096, horizon 64) using the geometric mean of CRPS (via a 9-quantile pinball head) and MASE. Lower is better. You never see the eval windows, and the slice rotates every round — benchmark-shaped or memorisable corpora do not win; broad, diverse, realistic priors do. - King-of-the-hill: a challenger dethrones the king when the paired-bootstrap **lower confidence bound (LCB)** of its advantage clears the win margin. The margin decays with the king's tenure: 1% for a fresh king (2% for rounds before block 8992800) → 0.5% floor after 8 rounds (the floor is a hard safety guardrail, never 0). - Rewards: geometric decay across the lineage — the current king plus up to 4 prior distinct kings still registered share emission ∝ 0.5^i (≈52/26/13/6/3%); unregistered remainder burns. Winning ONE round is not the goal; taking and holding the throne is. - The cascade (namesake, **LIVE** — generations are promoting on mainnet): when a king survives 5 consecutive rounds, up to 3 of the reign's best duel checkpoints (within 5% of the reign best — the king's AND losing challengers') are **promoted** as the next warm-start generation; later rounds rotate across the members, and every run in a round (heat and final) trains from that same init — improvements compound across generations instead of resetting. A no-downgrade guard holds the promotion until the reign best benches at least as well as the live generation's best member. The king persists through promotion (reign clock resets), and promotion pays the checkpoint's owner nothing — but your data can shape the shared init even from a losing duel. ## Rules — binding constraints on submissions Full contract: docs/INTERFACE.md. Enforced limits: chain.toml `[generator]`, `[dependencies]`, `[static_guard]`, `[round]`. - **Code-only, purely algorithmic.** A generator is a sampler built from priors (GP/kernel families, causal DAGs, trend/seasonality/noise mixtures, chaotic systems, …). **No shipped weights of any kind** — pickle-family checkpoints (`*.pt`, `*.bin`, `*.ckpt`, `*.pkl`, …) AND code-free containers (`*.safetensors`, `*.npy`, `*.npz`, `*.onnx`, …) are rejected. torch/gpytorch are allowed as compute libraries, but you may not distill a pretrained model into the submission. - **Repo layout** (pushed as an OCI artifact, ≤128 MB): `generator.py` exposing `class Generator(DataGenerator)` with `__init__(config_dir, *, seed)`, `generate(n_series) -> Iterator[np.ndarray]`, and a `name` property; `config.json` (any JSON your code reads); `requirements.txt`. - **Determinism is non-negotiable.** `generate()` must be a pure function of `seed`: two runs at the same seed produce a byte-identical corpus. Seed every RNG (numpy, torch, `random`); no wall-clock, `os.urandom`, `hash()`, network, or unordered-set iteration. `cascade verify` builds the corpus twice and compares digests; validators rely on this to audit rounds. - **Output bounds** (violation disqualifies the round): finite floats only (no NaN/inf), univariate today (1-D `(L,)` arrays; the schema is ready for `(C, L)` when `max_channels` rises), length 64–4096 per series, whole corpus ≤ 2e9 points. The corpus budget is points-denominated (DEC-CA-0029): the materialised drain stops at `corpus_target_points` (67,108,864 = 16384×4096) and the series count is free — many short series or fewer long ones; the live stream stops at the training token budget. 2-hour CPU generation budget (RLIMIT_CPU — threads sum into it), 4 GB memory rlimit. - **Sandboxed, no network.** `generator.py` is AST-scanned for blocked imports (`socket`, `urllib*`, `requests`, `httpx`, `subprocess`, `os.system`, `ctypes`, `cffi`, `pickle`, `marshal`, `multiprocessing`, cascade internals, …) and runs in a network-isolated sandbox. - **Dependencies**: every `requirements.txt` line must be `pkg==ver --hash=sha256:…`, at most 16 packages, drawn only from the allowlist: numpy, scipy, pandas, statsmodels, numba, torch, scikit-learn, gpytorch, networkx. - **One submission per hotkey per heat.** A hotkey that has entered a heat is burned and must re-register to resubmit (anti-spam). One hotkey = one UID = one competing generator; run several priors via several hotkeys. - **Copying does not pay.** Committing someone's exact `repo@digest` loses to the earliest reveal. Re-uploading identical content under a new ref produces an identical corpus digest under the shared round seed and is dropped as `duplicate` before training (exact-identity dedup: same tree / same normalized tokens / tokens-modulo-renames; earliest commit keeps the slot; dropped copies still burn the submission). From block 8992800 identical code with only a different config (`config_only`) is dropped the same way — a config sweep of someone's generator is one submission, the earliest one. Forking + genuinely improving the king is the intended game — a byte-identical copy can only tie, so it can never win. - **Generator speed is priced on purpose.** The training budget is a fixed token count, not a timer; a slow generator starves the model of compute and that IS the score (`data_wait_frac` in the public logs tells you if training waited on your generator). Do not expect this to be "fixed". ## Round mechanics — the competitive loop Full flow: docs/ARCHITECTURE.md. Cadence and budgets: chain.toml `[round]`. - A round = one ~12h epoch (3600 blocks). Only commitments whose on-chain pointer **revealed strictly before** the epoch boundary compete; a late reveal auto-rolls into the next round. - **Heat** (screening; rounds before block 8992800): every eligible challenger's generator trains the fixed model for ~1h at the screen size, scored on the round's held-out eval draw. A leader the screen statistically separates advances alone; a tied top advances as a cohort, capped at `max_finalists` (3). Standings publish the moment the heat settles (`cascade heat`), including for rounds later rejected at a gate. - **Duel-only rounds** (from block 8992800, ≈ 2026-09-04 08:30 UTC): no heat. The whole screened field seats straight into the duel in reveal order and every challenger trains the full final budget; the fleet is sized to fit the field inside the epoch. Entrants the rented lanes cannot finish before the boundary wait for the next round with their submission intact (`cascade heat` lists them as `waiting`). The whole cohort is judged under α/k. - **MINER-FUNDED ROUNDS (live from block 9046800 ≈ Fri 2026-09-11 20:30 UTC, DEC-CA-0036):** entering a round now requires FUNDING your own training leg with your Lium API key (`cascade fund` — the leg's GPU pod rents on YOUR account; the operator pays for the king, evals, and everything else). The funded queue IS the field: seats fill by on-chain reveal-block seniority up to the round's capacity (up to 8, clamped to live GPU-market capacity), and EVERY seated entrant goes straight to the duel — the heat screen is retired for funded rounds. Each round runs entirely on ONE GPU type, chosen per round as the most available of ["RTX4090", "RTX3090", "L40S", "L40", "A6000"]. Unfunded boundaries run nothing (the king holds). Seat allocation is public (`cascade queue`, `funded/round-.json`) and audit-checked against the signed manifest. Infra/sold-out/rate-limit failures on your pod re-queue you WITHOUT burning your entry; an invalid key releases your entry (fix it and re-fund); your key is held at most 36h in a sealed vault, forgotten on withdraw. One submission per hotkey still holds but is spent ONLY when your leg is judged (or your generator fails) — requeues never burn it. A hotkey that competed in a legacy round is spent: enter the funded era with a fresh hotkey revealed after the last legacy boundary (Fri 2026-09-11 ~08:30 UTC, block 9043200). Full contract: docs/MINER_FUNDED_ROUNDS.md. - **Heat** (screening; retired for funded rounds — pre-go-live history): every eligible challenger trained ~1h at the screen size and the leader/tied top advanced, capped at `max_finalists` (3). Standings still publish (`cascade heat`) whenever a screen actually runs. - **Final** (the duel): king and finalists each train from the SAME shared round init (random at generation 0; the promoted cascade checkpoint after a promotion — the live case today) with identical seeds, budget (~3h as a fixed token count), and contract, at every configured throne size (4M live today). Validators verify the signed manifest's contract digests, evaluate the checkpoints on the shared private windows, and judge the whole advanced cohort under a family-wise alpha, crowning the best margin-clearer. - Everything is publicly re-derivable: signed manifests and round receipts land in a public bucket; `cascade-audit latest` re-derives seeds, digests, and the verdict of any published round (docs/AUDIT.md). If no real miner has taken the throne, a genesis baseline generator holds it and emission burns until it is dethroned. ## How to mine — end-to-end workflow Full walkthrough: docs/MINER.md. All commands are console scripts from this repo. 1. **Install** (no GPU needed to submit): `git clone https://github.com/TensorLink-AI/cascade && cd cascade && pip install -e '.[hippius,chain]'` 2. **Write or fork a generator.** Start from `scripts/example_generator/` (trend+seasonal+AR(1)) or the richer priors (`gen_changepoint`, `gen_chaotic`, `gen_garch`, `base_generator/`), or pull the current best: `cascade fetch king --out ./king`. Optimise for downstream forecast generalisation: diversity of regimes (trends, multiple seasonalities, regime shifts, varied noise, realistic scales) beats any narrow shape. 3. **Verify locally**: `cascade verify ./my-generator` runs every trainer-side check (layout, static guard, hash-locked deps, determinism). Fix everything before spending a registration. 4. **Score locally (the fast iteration loop)**: `cascade score ./my-generator --pool-dir ./my-heldout --device cuda` trains at the cheap heat budget and scores offline (needs the `.[train]` extra, ideally a GPU). Baseline against the king (`cascade score ./king --pool-dir …`) and iterate until you beat its number. Caveats: your local pool is directional, not the verdict — the validator's pool is private and rotates; and do not overfit one fixed local pool, rotate/expand it. 5. **Register**: create a bittensor wallet, then `btcli subnets register --netuid 91 --network finney --wallet-name … --wallet-hotkey …` (testnet: `--netuid 259 --network test`). 6. **Set registry credentials** (env, never in config): `HIPPIUS_HUB_USERNAME`/`HIPPIUS_HUB_PASSWORD` or `HIPPIUS_HUB_TOKEN`. Miners do NOT need S3 credentials. 7. **Deploy**: `cascade deploy ./my-generator --hub-namespace --wallet-name … --wallet-hotkey …` verifies, pushes the repo to the Hippius Hub registry (content-addressed `repo@digest`), and commits the on-chain pointer `metro-v1:gen:hippius:@` via a **timed reveal** that decrypts ~25 blocks (~5 min) before the epoch boundary, so your submission stays hidden for its whole window and cannot be copied into its own round. Prefer `--hub-namespace` (fresh non-guessable repo per deploy) over a fixed `--hub-repo` name. Your Hippius project MUST be public or every round rejects it as `generator_artifact_unreachable`. Commit from this repo's pinned environment (`bittensor==10.5.0`) — older SDKs write reveals the subnet cannot decode and you are silently skipped. 8. **Fund your training leg** (required once funded rounds are live — block 9046800, ≈ Fri 2026-09-11 20:30 UTC): after your reveal lands, `export LIUM_API_KEY=sk-…` (env only, never argv) and `cascade fund https://submissions.cascadesub.net --ref --wallet-name … --wallet-hotkey …`. Your hotkey must be REGISTERED on the subnet and the ref must match your revealed commitment. The leg's pod rents on your Lium account only when your seat comes up (budget ~4h: the 3h leg plus ~1h benching your own checkpoint on that pod after the duel); requeues never burn your entry, and `cascade fund … --withdraw` exits a still-queued entry (the operator forgets your key). Watch your seat with `cascade queue` (add `--intake ` for the live queue). 9. **Time and confirm**: `cascade round` shows the live countdown to the submission deadline, the round stage, and your commit landing (`● new`); `cascade reveal-status --watch` confirms the reveal beat the boundary. Re-deploy any time — the latest pre-cutoff reveal per hotkey competes; a missed reveal rolls forward without burning your submission. 10. **Read results**: `cascade heat --hotkey ` (your screening rank, gap to the leader, raw CRPS/MASE, published as soon as the heat settles), `cascade duel` (the full signed verdict once the round settles), the public training logs (`logs/round-/…jsonl`; `data_wait_frac` high = your generator was too slow, `host_bench_tokens_per_s` low = the pod was slow), and `cascade-audit latest` to verify any round yourself. Losing duels while iterating is normal: the pool is broad real-world data. Widen the prior (mix families) rather than fitting one shape — and under funded rounds, iterate locally (`cascade score`) BEFORE funding a leg: every seat you take bills your own key for ~3h of GPU. ## Key configuration values (chain.toml, shipped) - netuid 91 mainnet (testnet 259 via chain.testnet.toml); epoch 3600 blocks ≈ 12h - heat (before block 8992800): 1h train budget, scored on the round's eval draw; separated leader advances alone, tied cohort capped at `max_finalists` (3) - duel-only (from block 8992800): no heat; the whole field seats in reveal order (`duel_field_cap = 0`), the fleet sizes to fit it in the epoch, and only the lanes' physical overflow waits unburned for the next round - funded rounds (from block 9046800): `funded_mode = "required"`, `funded_pods = "rent"` (your leg bills your Lium key), field cap 8 clamped to live GPU-market capacity, GPU type per round from ["RTX4090", "RTX3090", "L40S", "L40", "A6000"], king rents JIT operator-billed, unfunded boundaries skip - heat (pre-funded-era): 1h train budget; separated leader advanced alone, tied cohort capped at `max_finalists` (3) - eval: jittered ~1200-window draw per round (`mix_target_windows`) from the private rotating pool — the domain mix re-rolls every round; from block 8992800 the verdict draw is a horizon ladder (`scored_horizons` = 64/256/720, one even-by-domain rung each, `n_windows` split evenly) - final: 3h token-budget train per side, Toto2-4M from the shared round init - dethrone: paired-bootstrap LCB (B=10000, α=0.05, α/k across a tied cohort) must clear the tenure-decayed margin (2% → 0.5% over 8 rounds); ≥200 common windows or no decision - rewards: king + 4 prior kings, geometric 0.5 decay; remainder burns to uid 0 - cascade promotion (LIVE): after 5 undethroned rounds, top-k (≤3) reign checkpoints within 5% of the best bench geomean become the next warm-start generation; a no-downgrade guard holds vs the current generation's best; rounds then rotate members by epoch index ## Docs - [README](README.md): why compete on data, how a round works, roadmap, console scripts - [docs/MINER.md](docs/MINER.md): the complete miner operator walkthrough (fork → verify → score → register → deploy → confirm), timed-reveal threat model, failure table - [docs/MINER_FUNDED_ROUNDS.md](docs/MINER_FUNDED_ROUNDS.md): funded rounds — the funding contract, queue/seniority rules, failure classes, and the operator runbook - [docs/INTERFACE.md](docs/INTERFACE.md): the DataGenerator submission contract (the code you must write) - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): end-to-end flow, trust model, the controlled-experiment invariant - [docs/AUDIT.md](docs/AUDIT.md): verify published rounds with cascade-audit (no wallet/GPU for tiers 0–1) - [chain.toml](chain.toml): the single source of truth for every live limit and rule cited above - [scripts/example_generator/](scripts/example_generator/): a minimal forkable reference generator ## Optional - [docs/VALIDATOR.md](docs/VALIDATOR.md): run a validator (eval GPU + chain weights) - [docs/EVAL_POOL.md](docs/EVAL_POOL.md): the private eval-window pool and its rotation - [docs/COMMUNICATION.md](docs/COMMUNICATION.md), [docs/DEPLOY_PODS.md](docs/DEPLOY_PODS.md), [docs/MARGIN_DECAY_ROLLOUT.md](docs/MARGIN_DECAY_ROLLOUT.md), [docs/SCRATCH_SHADOW.md](docs/SCRATCH_SHADOW.md): owner/operator internals - [decisions/](decisions/): the design-decision graph (DEC-CA-#### nodes) recording why each rule is the way it is