Internals
Mainnet clone testing
How CI sudo-upgrades a clone of live mainnet with your runtime, and how to reproduce it locally when it fails.
Every PR runs the Clone Upgrade Check (runtime-checks.yml): it
builds your proposed runtime, applies it to a local copy of real mainnet
state via a sudo upgrade, then runs regression tests and the Python SDK
metadata drift gate against the upgraded chain. This catches problems unit
tests can't - migrations that break on real storage, changed RPC shapes, SDK
incompatibilities - before anything ships.
This page explains what the check does and how to reproduce each step locally.
How it works
node-subtensor build-patched-spec(invoked byclones/scripts/clone-mainnet.sh) spins up a temporary node, syncs current mainnet state from a bootnode, exports it as a raw chainspec, and patches it for local use: block authorship (Aura/Grandpa authorities) and the sudo key are handed to the well-known dev account Alice. The result is written toclones/mainnet-clone-chainspec.json(gitignored).clones/scripts/start-local-clone.shstarts a single local validator from that chainspec onws://127.0.0.1:9944, authoring blocks as Alice.npm run runtime:update:alice(inclones/js-tests/) reads your built runtime wasm fromtarget/release/wbuild/node-subtensor-runtime/node_subtensor_runtime.compact.compressed.wasmand submitssudo(system.setCode(...))from Alice. The clone is now running mainnet state under your runtime, including any migrations it triggered.npm testruns the smoke test; CI then runs the SDK metadata drift gate (python -m codegen.check --drift) against the upgraded chain.
Reproducing locally
# 1. Build the node and your runtime
cargo build --release -p node-subtensor
# 2. Create (or reuse) the patched mainnet clone chainspec.
# First run syncs mainnet state — this takes a while and needs disk space.
# Later runs reuse the existing chainspec file.
./clones/scripts/clone-mainnet.sh
# 3. Start the clone node (leave this running; use a second terminal for the rest)
./clones/scripts/start-local-clone.sh
# 4. Sudo-upgrade the clone to your runtime
cd clones/js-tests
npm ci
npm run runtime:update:alice
# 5. Run the smoke test (what `npm test` runs in CI)
npm test
# 6. When you're done
cd ../..
./clones/scripts/stop-local-clone.shTo re-sync fresh mainnet state instead of reusing the cached spec, delete
clones/mainnet-clone-chainspec.json and rerun clone-mainnet.sh.
start-local-clone.sh wipes the chain database (clones/mainnet-clone/) on
every start, so each run replays your upgrade from the cached state — restart
the node to retry a failed upgrade from scratch.
Running the SDK drift gate against the clone
cd sdk/python
uv sync --locked --all-extras --dev
uv run pytest # offline unit tests
uv run python -m codegen.check --drift ws://127.0.0.1:9944Targeted regression tests
clones/js-tests/package.json has one npm script per regression test, e.g.:
npm run test:balancer-operation
npm run test:locks-conviction
npm run test:proxy-filter-security-regressionsPoint a test at a different endpoint with WS_ENDPOINT=ws://..., and at a
different runtime wasm with RUNTIME_WASM_PATH=/path/to/runtime.wasm.
When it fails on your PR
- Upgrade step fails — your runtime doesn't apply cleanly to mainnet state. Usually a migration panicking on real storage; reproduce with steps 1–4 above and watch the node log. Complement with try-runtime.
- Smoke or regression tests fail — your change altered on-chain behavior or storage shapes that existing features depend on. Run the specific failing script locally (see targeted tests above).
- SDK checks fail — you changed calls, events, errors, or queries the SDK
has codegen'd bindings for. Regenerate
bittensor/_generated/against your upgraded clone (python -m codegen ws://127.0.0.1:9944) and commit the result; see Testing. - Skipping: adding the
skip-clone-upgradelabel to a PR skips the check; reserve that for changes that can't affect the runtime, SDK, or docs.