The KOTH Protocol
King-of-the-Hill over miner-run, TEE-attested benchmarks. Miners run the owner's benchmark suite inside their own confidential VM and publish an attested proof to their own HuggingFace repo. Validators only verify the proof and grade the reports — no validator-side inference, no centralized API. A formula over the verified reports crowns the king.
The load-bearing idea: because the artifact — source and weights — is public and cryptographically bound to what ran, cheating is publicly detectable rather than something we must prevent by hiding data. That is what makes static, public benchmarks safe here.
The trust inversion
Other benchmark-scored subnets run evaluation on infrastructure you must trust. KOTH moves execution into the miner's own TEE and keeps it trustworthy with hardware attestation.
| Layer | Trusted? | Author |
|---|---|---|
| TEE hardware root (Intel TDX) | yes — vendor | Intel |
| Measured enclave runtime (on the approved list) | yes — public, audited | subnet owner |
| Benchmark suite + public gold | yes — public | subnet owner |
| Miner agent: routing model + orchestration source | no — public, bound, run under attestation | miner |
| Validator | verify-only; holds no secret | subnet owner |
The enclave runs the miner's arbitrary agent but hands it only a metered call_model, and it stamps the agent's source_hash/weights_hash into the attestation. So anyone — not just a validator — can check that a given public artifact produced a given score, without re-running it.
Data models
BenchmarkResult: # one graded item
benchmark str # "math" | "mmlu" | "gpqa" | "swe"
task_id str # validator re-derives the gold from the nonce
answer str # graded validator-side against PUBLIC gold
cost_usd float # metered by the runtime — un-forgeable
Proof: # one per miner-epoch; the unit validators verify
epoch, nonce, hotkey # chain-derived nonce; hotkey bound (anti-resubmit)
source_hash, weights_hash, model_id # BINDING: ties the score to the public artifact
results: [BenchmarkResult] # the whole suite in one attested run
total_cost_usd, n_calls, call_log_hash
measurement # runtime image hash; must be on the approved list
quote = Platform.quote(measurement, report_data) # hardware signature
report_data()= sha256(payload-minus-quote) # binds EVERY field above
The on-chain commit is salted with your hotkey:
koth1|<hf_repo>|<revision>|sha256(source_hash|weights_hash|hotkey)
One hardware signature over {measurement, report_data} asserts two things at once: "this approved enclave ran" and "it produced exactly this payload." Mutate any field and report_data() changes, breaking the quote.
Miner flow
- Build the agent. A Python source file defining
build_agent(weights) -> agent, whereagent(prompt, call_model) -> answer.call_modelis your only channel to the pool. - Run the suite in your TEE. The measured runtime samples the epoch's nonce-seeded slice, executes your agent under no-egress confinement, meters every pool call, and produces an attested
Proofplus the full behavioural trace. - Publish the bundle to your own HF repo:
source.py,weights.bin,proofs/<epoch>.json,traces/<epoch>.json. All public, all auditable. - Commit on-chain via
set_reveal_commitment. The reveal delay defeats front-running; the hotkey salt defeats commit-copying.
Validator flow
Cheap, and re-execution-free. Per epoch, for each committed miner:
- Download the public bundle yourself, recompute
source_hash/weights_hash, andverify_committhem against the on-chain commit. The binding is checked here — never taken on the miner's word. verify_proofagainst those recomputed hashes: quote valid → measurement approved →report_databound → issued(epoch, nonce)→ bound hotkey → hashes match.- Re-derive the same nonce-seeded slice and grade the attested answers against the public gold. Missing or substituted tasks count as wrong. No agent re-run.
- Check the trace hashes to
call_log_hash, and that every scored task has ≥ 1 metered pool call. - Scan the public source for hardcoded answer tables.
- Grounding check (default): every scored answer must match a pool response logged in the hash-attested trace. An agent that ignores the pool and answers from its own memorised weights matches nothing →
ungrounded. This is pure proof-inspection — no miner code runs — so by default the validator does zero inference. (Opt-in--probe-bankmode instead re-executes the downloaded artifact on a secret held-out slice and applies a collapse test →memorization; it fails closed.) - Behavioural dedup on the attested answer vectors, then the Pareto dethrone guard against the persisted king baseline, then
KingChain→set_weights.
Because scoring is a lookup over attested reports — and by default runs no agent inference at all — validator cost is flat in the number of miners.
Scoring
The reign ranks on one bounded scalar, the cost-budgeted quality:
Q_lcb = Σ_b w_b · lcb_b # bounded [0,1]
lcb_b = bootstrap lower confidence bound on benchmark b's accuracy
(alpha = 0.05, 1000 resamples)
Scoring on the lower bound, not the point accuracy, is deliberate: a lucky run cannot dethrone a king.
| Benchmark | Weight w_b |
Source |
|---|---|---|
math |
0.30 | Hendrycks MATH · public gold |
mmlu |
0.22 | MMLU · public gold |
gpqa |
0.23 | GPQA Diamond · public gold |
swe |
0.25 | SWE-bench Pro · public gold |
The live loader currently wires
math+mmlu(0.5 / 0.5). GPQA is HuggingFace-gated and SWE needs the Docker patch-apply loop; both are implemented behind the sameBenchmarkinterface.
Eligibility
A miner earns nothing this epoch unless all of these hold. Ineligible miners are excluded from the reign — not fed a score of zero (which would still pay a slot when the reign is short).
| Gate | Default | Reason |
|---|---|---|
total_cost ≤ budget |
0.50 USD per slice |
over_budget |
acc_b ≥ f_min on every benchmark |
0.10 |
below_floor:<benchmark> |
| ≥ 1 metered pool call on every scored task | — | no_pool_call |
Cost is a ceiling, not a divisor. Being cheaper buys nothing once you are under the budget; above the quality bar, better still wins. And you must actually orchestrate the pool — answering "for free" from your own weights is disqualified.
The dethrone guard
Beating the king on Q_lcb is not sufficient. To take slot 1 a challenger must clear a Pareto-with-tolerance guard, or it is clamped strictly below the king:
| Condition | Default | Failure reason |
|---|---|---|
Not-worse on every benchmark: acc_c(b) ≥ acc_king(b) − tol |
tol = 0.02 |
regression:<b> |
Confidently dominant on ≥ 1: lcb_c(b) > acc_king(b) + margin |
margin = 0.03 |
no_confident_gain |
Sample gate: n_b ≥ min_tasks |
5 |
thin_eval:<b> |
Cost not-worse: cost_c ≤ cost_king × (1 + cost_tol) |
cost_tol = 0.10 |
cost_regression |
You cannot dethrone by trading a regression for a spike.
The reign
Up to 5 slots — the king plus the last 4 ex-kings still registered — share emissions equally (20% each when full; fewer paid slots means a bigger share each). The reward for climbing is entering the chain at all — the only door in is taking the crown — so the gradient lives at the coronation, not in graduated slot weights: a dethroned king keeps earning while it decays out of the chain (FIFO, oldest bumped first) instead of dropping straight to zero.
- Incumbency margin. Only the king's slot is contested. A challenger must beat the king by
ε, andεdecays with the king's artifact age — a stale king becomes easier to unseat; a fresh one is protected from noise:eps(age) = 0.002 + (0.02 - 0.002) * exp(-age / 8) - Tiebreak. Exact ties for the crown go to the earliest commit block. Copying late never pays.
- Burn. Weight burns to uid 0 only if nobody in the chain is still registered — a deregistered ex-king's share is re-split among the rest, not burned.
Scoring over time — stability + anti-grind (opt-in)
A single epoch samples only ~32 tasks, which is noisy: per-epoch scoring lets a lucky slice dethrone and lets two decoupled validators, drawing independent slices, disagree. Three refinements are landed but off by default, enabled per validator once their windows are calibrated on testnet:
| Refinement | What it does |
|---|---|
Evidence accumulation (scoring_mode="accumulate") |
Pools each epoch's verified per-benchmark result for a fixed artifact into one decayed binomial (Wilson lower bound, EWMA half_life_epochs default 200). Re-committing a new artifact resets the accumulator, and a missing epoch counts as n_expected tasks / 0 correct — so hiding bad epochs is strictly dominated. |
Commit window (F7, commit_window=W) |
Each epoch the miner commits its proof's report_data() on-chain within [epoch·blocks, +W], then reveals it. The validator scores it only if the revealed proof matches the commit and it landed in-window — capping best-of-N grinding to W's wall-clock. |
Grace window (F2, grace_blocks=G) |
Scores a settled epoch — the latest whose grace deadline has passed, (current_block − G) // blocks — never the live one, so every miner had the full window and two validators agree. |
Enable commit_window + grace_blocks together on mainnet once W and G are measured. The default (per_epoch, both windows off) keeps the offline sim and single-validator testnet simple.
Anti-cheat backstops
| Attack | Backstop |
|---|---|
| Run code B, claim artifact A's hashes | The runtime computes the hashes from the bytes it loads and runs → artifact_binding_mismatch |
| Hardcode an answer table | The source is public and scanned → hardcoded_answers |
| Memorise the benchmark (table hidden in the opaque weights) | Grounding check (default): every scored answer must derive from a logged pool call → ungrounded. Opt-in secret held-out probe (probe_commit) adds a re-execution collapse test → memorization |
| Copy a rival's artifact | Hotkey-salted commit-reveal + behavioural dedup (≥ 95 % answer-vector agreement, earliest commit wins) → copy_of:<uid> |
| Replay a good proof / best-of-N | The proof binds (epoch, nonce) → epoch_nonce_mismatch. An optional intra-epoch commit window (F7) adds a wall-clock bound → commit_out_of_window / commit_mismatch |
| Call a stronger model off the allow-list | PinnedBackend raises UnpinnedModelError; the run fails |
| Answer without using the pool | no_pool_call |
| Under-report cost | Cost is metered in-enclave, and the agent has zero network egress |
Parameter reference
| Parameter | Default | Where |
|---|---|---|
EPOCH_BLOCKS |
100 (≈ 20 min) |
koth/epoch.py |
n_per_bench |
8 (→ 32 graded tasks/epoch) |
validator |
budget |
0.50 USD |
validator |
f_min |
0.10 |
validator |
margin / tol / cost_tol / min_tasks |
0.03 / 0.02 / 0.10 / 5 |
dethrone guard |
alpha / boot |
0.05 / 1000 |
bootstrap LCB |
dedup_agree |
0.95 |
behavioural dedup |
| king-chain size | 5 (king + 4 ex-kings), equal share 20 % each when full |
reign.py KingChain |
eps0 / eps_floor / tau |
0.02 / 0.002 / 8.0 |
king incumbency hysteresis |
audit_mode |
grounding (default) · probe (opt-in re-execution) |
memorization backstop |
scoring_mode |
per_epoch (default) · accumulate (opt-in) |
reign scalar |
commit_window / grace_blocks |
off / 0 (opt-in anti-grind) |
validator |
tcb_accept |
{UpToDate, SWHardeningNeeded} |
attestation |
See also
- Attestation & Trust Model — what the hardware signature actually proves
- Bittensor Integration — epochs, commit-reveal, weight setting
- Mine the Subnet — build an agent and compete