Submitting a proposal
Production submission is a hotkey-signed, timelock commit-reveal containing a content hash and an HTTPS fetch URL. The chain carries a reference, not the archive bytes.
The miner-side implementation is in submit.py, and the canonical payload is defined by payload.py.
The identity chain
Submission binds several related but non-interchangeable values:
bundle files --SHA-256--> content_hash --inside canonical payload--> commitment
| | |
exact proposal bytes fetch authentication finalized arrival orderThe URL says where to fetch; it does not define the proposal. The content hash says what bytes must be recovered; it does not prove the bytes are eligible or correct. The finalized reveal gives arrival authority; it does not prove that a fetch or qualification succeeded. Later selected-delta, stack, launch, evidence, and settlement digests bind the same proposal into progressively narrower decisions.
Keep the printed content hash with your bundle and operator receipts. A bundle name such
as alice-silu-v1 is for humans and is not enough to diagnose which bytes were evaluated.
Before you sign
Confirm all of the following against the operator's current announcement:
- network, netuid, active arena, target catalog, and evaluation stack;
- registered target and required target mode;
- submission window, timelock policy, eval-cost quote, and any admission limits;
- the designated version of the submission terms;
- how the operator publishes intake and qualification status.
The repository's submission terms are currently marked draft and become binding only when an operator announcement designates a version. Read the designated terms before signing. Ensure you own or can grant the required rights to every submitted source fragment.
A plain chain-submit is hotkey-signed. Paying the eval cost with --pay also
needs the coldkey: it transfers TAO to the current subnet owner coldkey and then
commits a v2 payload that points at that transfer.
Step-by-step commands
Set the operator's announced values once. Do not edit my_bundle after you
package or publish it.
NET="<NETWORK>"
NETUID="<NETUID>"
WALLET="<WALLET>"
HOTKEY="<HOTKEY>"
BUNDLE=my_bundle
URL="https://downloads.example.org/cacheon/my_bundle.tar.gz"
BLOCKS=10Use python -m cacheon.cli on GPU hosts. Substitute the real HTTPS URL from
chain-publish or from your own host.
1. Register the miner hotkey
Skip this if the hotkey is already registered on this netuid. Registration needs coldkey authorization.
python -m cacheon.cli chain-register \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY"2. Check the frozen bundle
python -m cacheon.cli scan "$BUNDLE"
python -m cacheon.cli verify "$BUNDLE" --device cuda --dtype bfloat16scan and verify are diagnostics; they do not pre-approve intake. See
Bundle checks for what to inspect.
3. Host the archive
Either publish through the miner's S3-compatible bucket:
python -m pip install -e ".[object-store]"
python -m cacheon.cli chain-publish "$BUNDLE" --out dist/my_bundle.tar.gzOr package and upload the archive yourself:
python -m cacheon.cli chain-package "$BUNDLE" --out dist/my_bundle.tar.gzCopy the printed content hash and the public HTTPS URL. Set URL to that
exact URL. Bucket variables, CDN origins, and fetch limits are under
Publish from the miner's object store.
Warning — Unavailable MiniMax-M3 targets Do not pay for or submit
norm.rmsnormorattention.msa_block_scoreto the current MiniMax-M3 mainnet arena. A candidate for either registered contract cannot execute in the deployed model/runtime. This restriction does not apply to the other registered targets. See Current MiniMax-M3 availability.
4. Dry-run the unpaid payload
python -m cacheon.cli chain-submit "$BUNDLE" \
--url "$URL" \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY" \
--blocks-until-reveal "$BLOCKS" \
--dry-runThe printed content_hash must match the package result. The unpaid payload is
canonical JSON with exactly three fields:
{"v":1,"h":"<64-lowercase-hex>","u":"https://.../my_bundle.tar.gz"}A refused dry-run has not signed or sent anything. The production payload cap is 1,024 bytes.
5. Submit — eval-cost gate off
If the operator's eval_cost_tao_rao is 0 (the code default), commit the
unpaid payload. Do not pass --pay.
python -m cacheon.cli chain-submit "$BUNDLE" \
--url "$URL" \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY" \
--blocks-until-reveal "$BLOCKS"Then skip to Inspect public chain state.
6. Submit — eval-cost gate on
If the operator requires a TAO admission transfer, quote, dry-run --pay, then
pay and commit. The destination is the current subnet owner coldkey.
python -m cacheon.cli chain-eval-cost --netuid "$NETUID" --network "$NET"
python -m cacheon.cli chain-submit "$BUNDLE" \
--url "$URL" \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY" \
--blocks-until-reveal "$BLOCKS" \
--pay \
--dry-run--pay --dry-run does not transfer TAO. The dry-run payload stays v1 because
there is no inclusion pointer yet. Then pay and commit:
python -m cacheon.cli chain-submit "$BUNDLE" \
--url "$URL" \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY" \
--blocks-until-reveal "$BLOCKS" \
--payA live --pay freezes the quoted amount for 300 blocks (~1 hour) until the
transfer lands, then commits v2. Copy the printed pointer:
eval_cost payment: block=<BLOCK> extrinsic=<INDEX>If the validator operator granted you a fee credit (a make-good after a
validator-side failure of a paid submission), submit as in the gate-off flow:
plain chain-submit with no --pay and no payment pointer. The credit admits
that one reveal.
{"v":2,"h":"<64-lowercase-hex>","u":"https://.../my_bundle.tar.gz","p":{"b":<block>,"i":<extrinsic_index>}}If the reveal commit fails after the transfer is included, retry without
--pay. Only this miner hotkey can spend that pointer, and only for this
bundle and netuid. There is no refund.
python -m cacheon.cli chain-submit "$BUNDLE" \
--url "$URL" \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY" \
--blocks-until-reveal "$BLOCKS" \
--eval-cost-payment-block <BLOCK> \
--eval-cost-payment-extrinsic-index <INDEX>7. Inspect public chain state
python -m cacheon.cli chain-status \
--netuid "$NETUID" --network "$NET" \
--wallet "$WALLET" --hotkey "$HOTKEY"chain-status shows subnet and revealed-commitment state. It does not read the
validator's private SQLite intake lifecycle; use the operator's published
status/receipt surface for later stages.
The SDK encrypts the payload for automatic reveal after the requested timelock. This is not the old local salt/round simulation. The finalized reveal position provides the consensus arrival order used by intake.
Bundle checks
Use an explicit contribution target and source-only contents. Then run the development checks in step 2. Inspect the tree for credentials, caches, generated binaries, model data, machine paths, unsupported licenses, and stale result metadata.
Publish from the miner's object store
Each miner owns and pays for their own bucket. The validator does not provision the bucket, receive the miner's credentials, or use authenticated object-store reads. Install the optional S3 client support:
python -m pip install -e ".[object-store]"Create S3 credentials and a bucket in the miner's account. Export the credentials from a private environment file:
set -a
source .env
set +aThe recognized variables are:
CACHEON_OBJECT_STORE_ACCESS_KEY_ID=...
CACHEON_OBJECT_STORE_SECRET_ACCESS_KEY=...
CACHEON_OBJECT_STORE_BUCKET=...chain-publish uses the generic S3 backend by default. AWS S3 needs no provider
flag. For another S3-compatible service, its endpoint URL identifies the
service; a custom endpoint defaults to path-style addressing:
CACHEON_OBJECT_STORE_ENDPOINT_URL=https://objects.example
CACHEON_OBJECT_STORE_REGION=us-east-1Use CACHEON_OBJECT_STORE_ADDRESSING_STYLE=virtual only when the service expects
virtual-hosted bucket URLs. Known provider names are optional convenience
presets. For example, CACHEON_OBJECT_STORE_PROVIDER=hippius supplies Hippius's
endpoint, decentralized region, and path-style addressing; the equivalent
fully explicit configuration is:
CACHEON_OBJECT_STORE_ENDPOINT_URL=https://s3.hippius.com
CACHEON_OBJECT_STORE_REGION=decentralized
CACHEON_OBJECT_STORE_ADDRESSING_STYLE=pathThe command packages the bundle, uploads it under a content-addressed key, grants anonymous read access, reopens the stored archive, and finally runs the validator's production HTTPS fetch and hash check without credentials:
python -m cacheon.cli chain-publish my_bundle \
--out dist/my_bundle.tar.gzPass --create-bucket only when the named bucket does not exist. The default
key retains the storage-compatibility prefix
cacheon/miner-bundles/sha256/<content_hash>.tar.gz. A repeated publication
reuses an existing object only after hardened extraction proves that it has the
committed tree hash; it never replaces a conflicting key. Use
--object-store-provider hippius|minio for a known preset, or
--object-store-endpoint for any S3-compatible service.
--public-base-url handles a separate HTTPS CDN or gateway origin.
The validator sees only the resulting HTTPS URL and content hash; it has no object-store provider setting or miner credential. Hippius connection details are maintained in its official S3 documentation. Do not copy a miner's credentials onto a validator.
Manual hosting alternative
For a non-S3 public HTTPS origin, package exactly the identity-bearing files:
python -m cacheon.cli chain-package my_bundle \
--out dist/my_bundle.tar.gzThe command prints a lowercase SHA-256 content hash. That hash identifies the canonical extracted bundle tree, not the gzip byte stream. The packager includes exactly the regular files covered by bundle identity.
Do not edit my_bundle after packaging. chain-submit re-hashes the directory;
if it changes while the hosted archive does not, the validator will reject the
fetch as a content mismatch.
For extra confidence, extract the hosted object into a clean temporary location and run
chain-package against that root, then compare its printed content hash. The wrapper
directory and gzip encoding are not the identity; the sorted relative paths and file bytes
are. Never “refresh” a stable URL with revised content after committing the old hash.
Upload that archive to a stable URL such as:
https://downloads.example.org/cacheon/my_bundle.tar.gzProduction URLs must be canonical HTTPS with a public-routable host. Credentials in the URL, fragments, plaintext HTTP, local files, and private/loopback destinations are rejected. Fetch retains TLS hostname verification and requires TLS 1.2 or newer.
Keep the exact object available long enough for reveal, finalized intake, and configured transport retries. Avoid a short-lived signed URL. The revealed URL is public chain data, so never embed a secret in it.
The production transport accepts gzip-compressed tar only. Current bounds include a 64 MiB archive, 256 MiB extracted content, 4,096 logical members, 16 MiB per regular file, 8 MiB per inspectable source/configuration file, 32 MiB across all inspectable files, bounded extension metadata, at most five redirects, and one 60-second absolute DNS/TLS/transfer/extraction deadline. The validator re-hashes the safely extracted identity-bearing tree. See fetch.py.
What happens after reveal
The authoritative path is staged:
- A finalized valid reveal is reserved in durable SQLite intake.
- The validator fetches the HTTPS archive into private storage, safely extracts it, and verifies the committed content hash.
- It republishes an immutable worker-readable tree and fingerprints the selected delta.
- Target resolution and the
static → build → ABI → graph → abbreviated servingnon-crown screens run through a registered arena service. - A promoted candidate receives a complete isolated version-3 qualification attempt: current v7 resident B/C/[B′] or v8 two-process B/C/B′, registered eager audit A, then pristine T.
- One PASS moves the proposal to
reproduction_pending. It has not crowned. - A second independent matching PASS completes qualification; the lower of the two reproduced speedups is retained.
- Transactional settlement may crown, neutralize, or hold the qualified candidate according to the frozen target/stack authority and competing cohort.
- Weight projection is a separate audited control-plane action.
Info — When a reward begins
qualifiedstill means no reward. If settlement crowns the proposal, it records the reward claim in the same transaction. The validator later combines eligible claims into a weight vector and publishes it on-chain. See How miners earn rewards. There is no universal completion time. Finality, queue bounds, arena capacity, retry policy, reproduction scheduling, and settlement cadence are operator configuration.
Follow one proposal through the states
Suppose the revealed content hash is H and its target is
activation.silu_and_mul:
reservedmeans the finalized arrival has a durable intake row. The proposal has not been fetched, so local correctness results are not relevant to its current wait.fetchingeither produces an authenticated private tree or a transport result. A timeout may becometransport_retryfor the sameH; a hash mismatch is a terminal candidate problem because the bytes at the URL are notH.publishedmeans an immutable worker tree and selected-delta identity exist. It does not mean candidate Python has passed any screen.screeningrecords the ordered stage receipts. If ABI fails, changing a local file cannot repairH; fix the source, package a new hash, and submit it as a new proposal. A validator storage fault should instead produce uncertainty for operator retry, not a fabricated candidate failure.promotedmeans all five non-crown screens passed and capacity may now be spent on the sealed v7 B/C/[B′] or v8 B/C/B′ schedule, registered eager audit A, then pristine T. It carries no speed score and no reward.reproduction_pendingmeans the first full attempt passed. Continue to describe the object as a proposal awaiting independent reproduction.qualifiedmeans two matching passes exist. Settlement still reopens evidence and considers priority/overlap before creating a crown.- A settlement crown is an economic record for this target and stack authority. It is still not an Engine release.
At each step, ask whether the next action changes proposal identity. Retrying fetch,
reopening retained evidence, or rerunning an independent attempt can preserve H under
operator policy. Editing source, metadata, the manifest, or any other identity-bearing
file necessarily creates a new hash and returns to submission.
What to record from the operator
When the operator exposes receipts, retain at least the content hash, finalized arrival position, target ID, arena and evaluation-stack digests, selected-delta digest, last durable status, decision/reason, and evidence or receipt digest. These let both sides distinguish “wrong bundle,” “same bundle under a different arena generation,” and “infrastructure could not decide.”
chain-status alone cannot supply those lifecycle fields. It observes public subnet and
reveal state, while production intake and qualification state live in validator storage.
Use the operator's designated status surface rather than assuming absence from
chain-status output means rejection.
A crown remains separate from source integration and a Cacheon Engine release. Submitting does not cause the validator to publish miner code as a release. Reward generation and confirmed publication are described in How miners earn rewards.
Production authority boundary
The supported submission path is chain-package followed by chain-submit. Finalized
chain intake, SQLite qualification state, transactional settlement, and journaled weight
publication are separate validator authorities. No local ledger or contributor-side
score can create those records.
If the proposal stalls or fails, map its reported lifecycle state through Diagnostics.
Example bundles
The repository examples are development fixtures for specific parts of the component ABI. They are not a catalog of active crowns, and their comments or metadata are not validator decisions.
Why submissions fail
This page is the measured record, not advice. The table below is the terminal disposition of every failed reservation on subnet 14 as of 2026-08-18.