Skip to main content

6.4 Local Deployment Guide

Run a fully isolated C-SWON subnet on your local machine using Docker. No testnet TAO. No external APIs.

Prerequisites

RequirementVersionCheck
Python3.10–3.12python3 --version
Dockerrecentdocker --version
bittensor10.xpython -c "import bittensor; print(bittensor.__version__)"

Step 1 — Install C-SWON

git clone https://github.com/adysingh5711/C-SWON.git
cd C-SWON
python3.12 -m venv .venv && source .venv/bin/activate
pip install bittensor && pip install -e .

Step 2 — Create .env

python -c "
import secrets
lines = [
'CSWON_MOCK_EXEC=true',
'CSWON_SYNTHETIC_SALT=' + secrets.token_hex(32),
]
open('.env', 'w').write('\n'.join(lines) + '\n')
print(open('.env').read())
"
set -a && source .env && set +a

Step 3 — Start Local Chain

docker pull ghcr.io/opentensor/subtensor-localnet:devnet-ready

docker run -d --name local_chain -p 9944:9944 -p 9945:9945 \
ghcr.io/opentensor/subtensor-localnet:devnet-ready

# Wait for blocks
docker logs -f local_chain # Ctrl-C once blocks appear
PortUse
ws://127.0.0.1:9944Metagraph, neuron traffic
ws://127.0.0.1:9945Wallet ops (transfer, stake, register)

docker restart resets all chain state — redo Steps 4–8.

Step 4 — Create Wallets

btcli wallet new_coldkey --wallet.name owner
btcli wallet new_hotkey --wallet.name owner --wallet.hotkey default

btcli wallet new_coldkey --wallet.name vali
btcli wallet new_hotkey --wallet.name vali --wallet.hotkey default

btcli wallet new_coldkey --wallet.name miner
btcli wallet new_hotkey --wallet.name miner --wallet.hotkey default

Import Alice (dev faucet, 1M TAO):

btcli wallet regen_coldkey --wallet.name alice --uri //Alice --network ws://127.0.0.1:9945

Step 5 — Fund Wallets

# Transfer 100k TAO from Alice to each wallet
for wallet_addr in <owner-coldkey> <vali-coldkey> <miner-coldkey>; do
btcli wallet transfer \
--wallet.name alice \
--destination $wallet_addr \
--network ws://127.0.0.1:9945
# Enter amount: 100000
done

Step 6 — Create and Start Subnet

btcli subnet create \
--network ws://127.0.0.1:9945 \
--wallet-name owner \
--hotkey default \
--no-mev-protection

# Note the netuid (usually 2)
export NETUID=2

# Start emissions (required before staking)
btcli subnet start \
--network ws://127.0.0.1:9945 \
--wallet-name owner \
--netuid "$NETUID"

Step 7 — Configure Hyperparameters

The devnet defaults break local testing. Fix using Alice's sudo key:

import asyncio
from bittensor_wallet import Wallet
from async_substrate_interface import AsyncSubstrateInterface

async def configure():
alice = Wallet(name='alice', path='~/.bittensor/wallets')
owner = Wallet(name='owner', path='~/.bittensor/wallets')
owner_kp = owner.get_coldkey(password='<your-password>')

sub = AsyncSubstrateInterface(url='ws://127.0.0.1:9945')
await sub.initialize()

# Disable commit-reveal (causes bad-signature on devnet)
for attempt in range(5):
call = await sub.compose_call(
call_module='AdminUtils',
call_function='sudo_set_commit_reveal_weights_enabled',
call_params={'netuid': 2, 'enabled': False},
)
ext = await sub.create_signed_extrinsic(call=call, keypair=owner_kp)
receipt = await sub.submit_extrinsic(ext, wait_for_inclusion=True)
if await receipt.is_success:
print('commit_reveal disabled')
break
err = await receipt.error_message
if 'WeightsWindow' in str(err):
await asyncio.sleep(12)
else:
print(f'Failed: {err}'); break

# Set weights_rate_limit = tempo (needs Alice sudo)
inner = await sub.compose_call(
call_module='AdminUtils',
call_function='sudo_set_weights_set_rate_limit',
call_params={'netuid': 2, 'weights_set_rate_limit': 10},
)
sudo = await sub.compose_call(call_module='Sudo', call_function='sudo', call_params={'call': inner})
ext = await sub.create_signed_extrinsic(call=sudo, keypair=alice.coldkey)
receipt = await sub.submit_extrinsic(ext, wait_for_inclusion=True)
print(f'weights_rate_limit: {await receipt.is_success}')
await sub.close()

asyncio.run(configure())

Verify:

python -c "
import bittensor as bt
hp = bt.Subtensor(network='ws://127.0.0.1:9944').get_subnet_hyperparameters(netuid=2)
print(f'commit_reveal={hp.commit_reveal_weights_enabled}')
print(f'weights_rate_limit={hp.weights_rate_limit}')
print(f'tempo={hp.tempo}')
"

Expected: commit_reveal=False, weights_rate_limit=10, tempo=10.

Step 8 — Register and Stake

# Register validator
btcli subnets register --network ws://127.0.0.1:9945 --netuid "$NETUID" \
--wallet-name vali --hotkey default --no-prompt

# Register miner
btcli subnets register --network ws://127.0.0.1:9945 --netuid "$NETUID" \
--wallet-name miner --hotkey default --no-prompt

# Stake validator (small amount — AMM pool is thin)
btcli stake add --network ws://127.0.0.1:9945 --wallet-name vali --hotkey default \
--amount 100 --no-mev-protection --tolerance 1.0
# When prompted for netuid, enter your NETUID (e.g. 2)

Verify:

btcli subnet metagraph --netuid "$NETUID" --network ws://127.0.0.1:9944

Step 9 — Resolve Axon IP

export LOCAL_AXON_IP="$(python -c "
from cswon.utils.hotkey_extrinsics import get_preferred_local_axon_ip
ip = get_preferred_local_axon_ip()
print(ip or '127.0.0.1')
")"
echo "$LOCAL_AXON_IP"

Step 10 — Start Miner (first)

python neurons/miner.py \
--netuid "$NETUID" \
--subtensor.network local \
--subtensor.chain_endpoint ws://127.0.0.1:9944 \
--wallet.name miner --wallet.hotkey default \
--axon.port 8091 --axon.external_port 8091 --axon.external_ip "$LOCAL_AXON_IP" \
--logging.debug

Step 11 — Start Validator (separate terminal)

set -a && source .env && set +a

python neurons/validator.py \
--netuid "$NETUID" \
--subtensor.network local \
--subtensor.chain_endpoint ws://127.0.0.1:9944 \
--wallet.name vali --wallet.hotkey default \
--axon.port 8092 --axon.external_port 8092 --axon.external_ip "$LOCAL_AXON_IP" \
--logging.debug

Step 12 — Verify Operation

Expected validator log:

Selected task: data_001 type=data_transform synthetic=False at block 1234
Received 1 responses from 1 miners
Validated 1 responses
Scored 1 miners: mean=0.9500

Check emissions:

import bittensor as bt
s = bt.Subtensor(network='ws://127.0.0.1:9944')
mg = s.metagraph(netuid=2)
for i in range(int(mg.n)):
print(f'UID {i}: stake={mg.S[i]:.2f} incentive={mg.I[i]:.4f} dividend={mg.D[i]:.4f}')

Troubleshooting

SymptomFix
bad signature on set_weightsDisable commit-reveal (Step 7)
SubtokenDisabled on stakingRun btcli subnet start first (Step 6)
SlippageTooHigh on stakingUse --tolerance 1.0 or smaller amount
No serving miners foundStart miner first, wait 10s
docker restart lost stateRedo Steps 4–8
AdminActionProhibitedDuringWeightsWindowRetry after 12 seconds

← Previous6.3 Running Locally (Staging)
→ Next6.5 Testnet Deploy Guide
IndexDocumentation Index