Skip to main content
Miners upload submissions to a challenge through a signed proxy route on the subnet master. The master verifies the miner’s signature, reserves a one-time nonce, then bridges the body to the challenge with verified-identity headers.

POST /v1/challenges/{challenge_name}/submissions

Uploads a signed submission for the named challenge (app_proxy.py:510-512, app_proxy.py:424-484). The challenge must be registered and active; otherwise the master returns 404 (app_proxy.py:425, app_proxy.py:243-254).

Required signature headers

Every upload MUST carry these four headers; a missing header is rejected with 401 (miner_auth.py:159-162, miner_auth.py:230-234): An optional X-Submission-Filename header is forwarded to the challenge when present (app_proxy.py:463-465).

Canonical message

The signature is computed over this exact byte string (canonical_upload_message, miner_auth.py:96-111):
Where (miner_auth.py:107-111, miner_auth.py:170-180):
  • netuid — the subnet id, 100 for BASE (config/settings.py:12).
  • challenge_slug — the active challenge’s slug (app_proxy.py:438).
  • METHOD — the HTTP method, upper-cased (miner_auth.py:109).
  • path — the request path being signed, i.e. the public submissions path (app_proxy.py:435-436).
  • hotkey, nonce, timestamp — the values from the matching headers (miner_auth.py:171-178).
  • body_hashsha256(body).hexdigest() of the raw request body (miner_auth.py:170).
The signature is verified against the hotkey as a substrate SS58 keypair; a 0x-prefixed hex signature is hex-decoded before verification (verify_substrate_signature, miner_auth.py:114-121; _decode_signature, miner_auth.py:222-227).

Verification rules

The master enforces, in order:
  1. Body size — bodies larger than the configured limit (default 2_000_000 bytes) return 413 (app_proxy.py:274, app_proxy.py:427-431).
  2. Timestamp freshness — if abs(now - timestamp) exceeds the TTL (default 300 seconds) the signature is rejected as stale (app_proxy.py:272, miner_auth.py:163-169).
  3. Signature — an invalid signature is rejected (miner_auth.py:181-182).
  4. Hotkey registration — by default the hotkey must be registered in the metagraph; an unknown hotkey is rejected and UID 0 is blocked (app_proxy.py:275, miner_auth.py:200-219).
  5. Nonce replay — the nonce is reserved once; a repeat returns 409 (miner_auth.py:184-191, app_proxy.py:440-441).

Response and error codes

On success, the master bridges the body to the challenge and returns the challenge’s response (status, body, and content type) unchanged (app_proxy.py:479-484). The response body shape is owned by the challenge and is not defined in the master.

What the master forwards to the challenge

After verification, the master POSTs the body to the challenge’s internal bridge route /internal/v1/bridge/submissions (app_proxy.py:470) with these headers (app_proxy.py:450-465):

Example

The path you sign must match the request path exactly (/v1/challenges/{challenge_name}/submissions), and body_hash must be the SHA-256 hex digest of the exact bytes you send.

Security model

How signed uploads are verified at the proxy.

Submit to a challenge

The miner-side guide to building and signing a submission.

Proxy API

The proxy routes that sit alongside this upload.