Buckets:
| """Submit a model to SN120. THIS SPENDS THE HOTKEY'S ONE AND ONLY SLOT. | |
| The reveal format was not documented anywhere we had. It was recovered from the | |
| chain on 2026-08-12 by reading `Commitments.RevealedCommitments(120, hotkey)` | |
| for hotkeys that appear as `enqueued` in the validator's intake records, and it | |
| is identical across every submitter checked, including the reigning king: | |
| affine1|{repo}|{revision}|{hotkey_ss58} | |
| affine1|ttttxxxxsada/Affine-5guassq3tu|e86758f5...|5GuaSC6qTcjcfMY... block 8825370 | |
| Mechanics, also measured rather than assumed: | |
| * It is a TIMELOCKED commit, not a plain one. `CommitmentOf` is empty for | |
| every SN120 submitter; the payload only ever appears in | |
| `RevealedCommitments`. So the call is `set_reveal_commitment`, not | |
| `set_commitment`. | |
| * Observed delay between `LastCommitment` and the revealed block: 7, 8, 7, 8 | |
| blocks for the four most recent submitters. | |
| * That delay is the anti-memorisation mechanism: the duel slice is drawn from | |
| blake2b(reveal_block_hash || hotkey), so no one can know their turns ahead | |
| of the reveal. | |
| WHY THIS IS DRY-RUN BY DEFAULT. The validator does `seen_hotkeys.add(hotkey)` at | |
| enqueue, and `check_slot` treats ANY intake record as a burned slot — including | |
| `rejected` and `failed`. Historically 43% rejected + 27% failed. There is no | |
| test submission, no retry, and no way to un-burn a hotkey. | |
| python3 harness/submit.py --wallet subnet120 --hotkey hotkey-1 \ | |
| --repo dent1s2/Affine-5FjqRq3dGA-extrap2 --revision <40hex> # dry run | |
| python3 harness/submit.py ... --yes # spends it | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import re | |
| import sys | |
| PREFIX = "affine1" | |
| NETUID = 120 | |
| def build_payload(repo: str, revision: str, hotkey_ss58: str) -> str: | |
| return f"{PREFIX}|{repo}|{revision}|{hotkey_ss58}" | |
| def validate(repo: str, revision: str, hotkey_ss58: str, coldkey_ss58: str, | |
| cfg: dict) -> list[str]: | |
| """Everything checkable without touching the chain. Returns failures.""" | |
| bad = [] | |
| if not re.match(cfg["repo_pattern"], repo): | |
| bad.append(f"repo {repo!r} does not match {cfg['repo_pattern']!r}") | |
| if not re.fullmatch(r"[0-9a-f]{40}", revision or ""): | |
| bad.append(f"revision {revision!r} is not a 40-hex commit sha") | |
| # identity binding: the repo name must embed prefix+suffix of hotkey OR coldkey | |
| p, s = cfg["coldkey_prefix_len"], cfg["coldkey_suffix_len"] | |
| pairs = [] | |
| for key in (hotkey_ss58, coldkey_ss58): | |
| if key: | |
| pairs.append((key[:p], key[-s:])) | |
| if pairs and not any(a in repo and b in repo for a, b in pairs): | |
| bad.append("repo name embeds neither hotkey nor coldkey " | |
| f"prefix{p}+suffix{s}: tried {pairs}") | |
| return bad | |
| def main() -> None: | |
| ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) | |
| ap.add_argument("--wallet", default="subnet120") | |
| ap.add_argument("--hotkey", required=True, help="wallet hotkey name, e.g. hotkey-1") | |
| ap.add_argument("--repo", required=True) | |
| ap.add_argument("--revision", required=True, help="40-hex commit sha") | |
| ap.add_argument("--blocks-until-reveal", type=int, default=8, | |
| help="field convention is 7-8 blocks") | |
| ap.add_argument("--network", default="finney") | |
| ap.add_argument("--yes", action="store_true", | |
| help="REQUIRED to spend the slot. Without it this is a dry run.") | |
| args = ap.parse_args() | |
| import bittensor as bt | |
| w = bt.Wallet(name=args.wallet, hotkey=args.hotkey) | |
| hk = w.hotkey.ss58_address | |
| ck = w.coldkeypub.ss58_address | |
| import urllib.request, json as _json | |
| try: | |
| cfg = _json.loads(urllib.request.urlopen( | |
| "https://s3.hippius.com/affine-sn120/data/contract.json", timeout=30 | |
| ).read())["submission"] | |
| except Exception as e: | |
| sys.exit(f"cannot fetch the live contract ({e}); refusing to submit against " | |
| "assumed rules") | |
| payload = build_payload(args.repo, args.revision, hk) | |
| print(f" wallet/hotkey {args.wallet}/{args.hotkey}") | |
| print(f" hotkey ss58 {hk}") | |
| print(f" coldkey ss58 {ck}") | |
| print(f" netuid {NETUID}") | |
| print(f" payload {payload}") | |
| print(f" payload bytes {len(payload.encode())}") | |
| print(f" reveal delay {args.blocks_until_reveal} blocks") | |
| fails = validate(args.repo, args.revision, hk, ck, cfg) | |
| if fails: | |
| print("\n BLOCKED:") | |
| for f in fails: | |
| print(f" - {f}") | |
| sys.exit(1) | |
| print(" local validation: repo pattern + identity binding + revision OK") | |
| st = bt.Subtensor(network=args.network) | |
| mg = st.metagraph(netuid=NETUID) | |
| if hk not in mg.hotkeys: | |
| sys.exit(f" BLOCKED: {hk} is not registered on netuid {NETUID}") | |
| uid = mg.hotkeys.index(hk) | |
| print(f" registration uid {uid} OK") | |
| prior = st.get_revealed_commitment_by_hotkey(netuid=NETUID, hotkey_ss58=hk) | |
| if prior: | |
| print(f"\n WARNING: this hotkey already has {len(prior)} revealed " | |
| "commitment(s). Its slot is very likely already burned:") | |
| for blk, p in list(prior)[:3]: | |
| print(f" block {blk}: {str(p)[:90]}") | |
| if not args.yes: | |
| print("\n DRY RUN — nothing submitted. Re-run with --yes to spend " | |
| "this hotkey's one and only slot.") | |
| return | |
| print("\n SUBMITTING (irreversible)...") | |
| resp = st.set_reveal_commitment( | |
| wallet=w, netuid=NETUID, data=payload, | |
| blocks_until_reveal=args.blocks_until_reveal, | |
| wait_for_inclusion=True, wait_for_finalization=True, raise_error=True) | |
| print(f" response: {resp}") | |
| print(f" committed at block ~{st.get_current_block()}; the reveal lands in " | |
| f"~{args.blocks_until_reveal} blocks and the validator enqueues from there.") | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 5.94 kB
- Xet hash:
- 406666b0407106016ad69c56378633a57b9ca9546a1112cad3768c5515103669
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.