affine-god/1111 / submit.py
affine-god's picture
download
raw
5.94 kB
"""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.