Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bittensor/core/extrinsics/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def root_register_extrinsic(

logging.info(":satellite: [magenta]Registering to root network...[/magenta]")
success, err_msg = _do_root_register(
self=subtensor,
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
Expand Down Expand Up @@ -235,6 +236,7 @@ def set_root_weights_extrinsic(
netuids, weights
)
success, error_message = _do_set_root_weights(
self=subtensor,
wallet=wallet,
netuid=0,
uids=weight_uids,
Expand Down
207 changes: 207 additions & 0 deletions tests/e2e_tests/test_root_set_weights.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import asyncio
import sys
import numpy as np
import pytest

from bittensor.core.subtensor import Subtensor
from tests.e2e_tests.utils.chain_interactions import (
register_subnet,
wait_epoch,
sudo_set_hyperparameter_values,
)
from tests.e2e_tests.utils.e2e_test_utils import (
setup_wallet,
template_path,
templates_repo,
)

"""
Verifies:

* root_register()
* neurons()
* register_subnet()
* burned_register()
* immunity_period()
* tempo()
* get_uid_for_hotkey_on_subnet()
* blocks_since_last_update()
* subnetwork_n()
* min_allowed_weights()
* max_weight_limit()
* weights_rate_limit()
* root_set_weights()
* neurons_lite()
"""


@pytest.mark.asyncio
async def test_root_reg_hyperparams(local_chain):
"""
Test root weights and hyperparameters in the Subtensor network.

Steps:
1. Register Alice in the root network (netuid=0).
2. Create a new subnet (netuid=1) and register Alice on this subnet using burned registration.
3. Verify that the subnet's `immunity_period` and `tempo` match the default values.
4. Run Alice as a validator in the background.
5. Fetch Alice's UID on the subnet and record the blocks since her last update.
6. Verify that the subnet was created successfully by checking `subnetwork_n`.
7. Verify hyperparameters related to weights: `min_allowed_weights`, `max_weight_limit`, and `weights_rate_limit`.
8. Wait until the next epoch and set root weights for netuids 0 and 1.
9. Verify that the weights are correctly set on the chain.
10. Adjust hyperparameters to allow proof-of-work (PoW) registration.
11. Verify that the `blocks_since_last_update` has incremented.
12. Fetch neurons using `neurons_lite` for the subnet and verify Alice's participation.

Raises:
AssertionError: If any of the checks or verifications fail.
"""

print("Testing root register, weights, and hyperparams")
netuid = 1

# Default immunity period & tempo set through the subtensor side
default_immunity_period = 5000
default_tempo = 360

# 0.2 for root network, 0.8 for sn 1
weights = [0.2, 0.8]

# Create Alice, SN1 owner and root network member
alice_keypair, alice_wallet = setup_wallet("//Alice")
subtensor = Subtensor(network="ws://localhost:9945")

# Register Alice in root network (0)
assert subtensor.root_register(alice_wallet)

# Assert Alice is successfully registered to root
alice_root_neuron = subtensor.neurons(netuid=0)[0]
assert alice_root_neuron.coldkey == alice_wallet.coldkeypub.ss58_address
assert alice_root_neuron.hotkey == alice_wallet.hotkey.ss58_address

# Create netuid = 1
register_subnet(local_chain, alice_wallet)

# Register Alice as a neuron on the subnet
assert subtensor.burned_register(
alice_wallet, netuid
), "Unable to register Alice as a neuron"

# Ensure correct immunity period & tempo is being fetched
assert subtensor.immunity_period(netuid=netuid) == default_immunity_period
assert subtensor.tempo(netuid=netuid) == default_tempo

# Prepare to run Alice as validator
cmd = " ".join(
[
f"{sys.executable}",
f'"{template_path}{templates_repo}/neurons/validator.py"',
"--netuid",
str(netuid),
"--subtensor.network",
"local",
"--subtensor.chain_endpoint",
"ws://localhost:9945",
"--wallet.path",
alice_wallet.path,
"--wallet.name",
alice_wallet.name,
"--wallet.hotkey",
"default",
"--logging.trace",
]
)

# Run Alice as validator in the background
await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
print("Neuron Alice is now validating")
await asyncio.sleep(5) # Wait a bit for chain to process data

# Fetch uid against Alice's hotkey on sn 1 (it will be 0 as she is the only registered neuron)
alice_uid_sn_1 = subtensor.get_uid_for_hotkey_on_subnet(
alice_wallet.hotkey.ss58_address, netuid
)

# Fetch the block since last update, so we can compare later
initial_block = subtensor.blocks_since_last_update(
netuid=netuid, uid=alice_uid_sn_1
)

# Verify subnet <netuid> created successfully
assert local_chain.query(
"SubtensorModule", "NetworksAdded", [netuid]
).serialize(), "Subnet wasn't created successfully"

# Use subnetwork_n hyperparam to check sn creation
assert subtensor.subnetwork_n(netuid) == netuid
assert subtensor.subnetwork_n(2) is None

# Ensure correct hyperparams are being fetched regarding weights
assert subtensor.min_allowed_weights(netuid=1) is not None
assert subtensor.max_weight_limit(netuid=1) is not None
assert subtensor.weights_rate_limit(netuid) is not None

# Wait until next epoch so we can set root weights
await wait_epoch(subtensor)

# Set root weights for netuids 0, 1
assert subtensor.root_set_weights(
alice_wallet,
[0, 1],
weights,
wait_for_inclusion=False,
wait_for_finalization=True,
)

# Query the weights from the chain
weights_raw = local_chain.query("SubtensorModule", "Weights", [0, 0]).serialize()

weights_array = np.array(weights_raw)
normalized_weights = weights_array[:, 1] / max(np.sum(weights_array, axis=0)[1], 1)
rounded_weights = [round(weight, 1) for weight in normalized_weights]

# Assert correct weights were set for root and sn 1
assert weights == rounded_weights

# Register Bob as miner
bob_keypair, bob_wallet = setup_wallet("//Bob")

# Change hyperparams so we can execute pow_register
assert sudo_set_hyperparameter_values(
local_chain,
alice_wallet,
call_function="sudo_set_difficulty",
call_params={"netuid": netuid, "difficulty": "1_000_000"},
return_error_message=True,
)

assert sudo_set_hyperparameter_values(
local_chain,
alice_wallet,
call_function="sudo_set_network_pow_registration_allowed",
call_params={"netuid": netuid, "registration_allowed": True},
return_error_message=True,
)

updated_block = subtensor.blocks_since_last_update(netuid=netuid, uid=0)
# Ensure updates are reflected through incremental block numbers
assert updated_block > initial_block

# TODO: Implement
# This registers neuron using pow but it doesn't work on fast-blocks - we get stale pow
# pow_registration = subtensor.register(bob_wallet, netuid=1)

# Fetch neuron lite for sn one and assert Alice participation
sn_one_neurons = subtensor.neurons_lite(netuid=netuid)
assert (
sn_one_neurons[alice_uid_sn_1].coldkey == alice_wallet.coldkeypub.ss58_address
)
assert sn_one_neurons[alice_uid_sn_1].hotkey == alice_wallet.hotkey.ss58_address
assert sn_one_neurons[alice_uid_sn_1].validator_permit is True

print("✅ Passed root tests")