Skip to content
Open
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: 1 addition & 1 deletion bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from rich.prompt import FloatPrompt, Prompt, IntPrompt
from rich.table import Column, Table
from rich.tree import Tree
from typing_extensions import Annotated
from typing import Annotated
from yaml import safe_dump, safe_load

from bittensor_cli.src import (
Expand Down
21 changes: 21 additions & 0 deletions bittensor_cli/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,9 @@ class RootSudoOnly(Enum):
"bonds_reset_enabled": ("sudo_set_bonds_reset_enabled", RootSudoOnly.FALSE),
"transfers_enabled": ("sudo_set_toggle_transfer", RootSudoOnly.FALSE),
"min_allowed_uids": ("sudo_set_min_allowed_uids", RootSudoOnly.TRUE),
"sn_owner_hotkey": ("sudo_set_sn_owner_hotkey", RootSudoOnly.FALSE),
"subnet_owner_hotkey": ("sudo_set_sn_owner_hotkey", RootSudoOnly.FALSE),
"recycle_or_burn": ("sudo_set_recycle_or_burn", RootSudoOnly.FALSE),
# Note: These are displayed but not directly settable via HYPERPARAMS
# They are derived or set via other mechanisms
"alpha_high": ("", RootSudoOnly.FALSE), # Derived from alpha_values
Expand Down Expand Up @@ -895,6 +898,24 @@ class RootSudoOnly(Enum):
"owner_settable": False,
"docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters#minalloweduids",
},
"sn_owner_hotkey": {
"description": "Set the subnet owner hotkey.",
"side_effects": "Changes which hotkey is authorized as subnet owner for the given subnet.",
"owner_settable": True,
"docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters",
},
"subnet_owner_hotkey": {
"description": "Alias for sn_owner_hotkey; sets the subnet owner hotkey.",
"side_effects": "Same as sn_owner_hotkey.",
"owner_settable": True,
"docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters",
},
"recycle_or_burn": {
"description": "Set whether subnet TAO is recycled or burned.",
"side_effects": "Controls whether unstaked TAO is recycled back into the subnet or burned.",
"owner_settable": True,
"docs_link": "docs.learnbittensor.org/subnets/subnet-hyperparameters",
},
# Additional hyperparameters that appear in chain data but aren't directly settable via HYPERPARAMS
"alpha_high": {
"description": "High bound of the alpha range for stake calculations.",
Expand Down
35 changes: 35 additions & 0 deletions tests/unit_tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from async_substrate_interface import AsyncSubstrateInterface

from bittensor_cli.cli import parse_mnemonic, CLIManager
from bittensor_cli.src import HYPERPARAMS, HYPERPARAMS_METADATA, RootSudoOnly
from bittensor_cli.src.bittensor.extrinsics.root import (
get_current_weights_for_uid,
set_root_weights_extrinsic,
Expand Down Expand Up @@ -805,3 +806,37 @@ async def test_set_root_weights_skips_current_weights_without_prompt():
)

mock_get_current.assert_not_called()


# HYPERPARAMS / HYPERPARAMS_METADATA (issue #826)
NEW_HYPERPARAMS_826 = {"sn_owner_hotkey", "subnet_owner_hotkey", "recycle_or_burn"}


def test_new_hyperparams_in_hyperparams():
for key in NEW_HYPERPARAMS_826:
assert key in HYPERPARAMS, f"{key} should be in HYPERPARAMS"
extrinsic, root_only = HYPERPARAMS[key]
assert extrinsic, f"{key} must have non-empty extrinsic name"
assert root_only is RootSudoOnly.FALSE


def test_subnet_owner_hotkey_alias_maps_to_same_extrinsic():
ext_sn, _ = HYPERPARAMS["sn_owner_hotkey"]
ext_subnet, _ = HYPERPARAMS["subnet_owner_hotkey"]
assert ext_sn == ext_subnet == "sudo_set_sn_owner_hotkey"


def test_new_hyperparams_have_metadata():
required = {"description", "side_effects", "owner_settable", "docs_link"}
for key in NEW_HYPERPARAMS_826:
assert key in HYPERPARAMS_METADATA, f"{key} should be in HYPERPARAMS_METADATA"
meta = HYPERPARAMS_METADATA[key]
for field in required:
assert field in meta, f"{key} metadata missing '{field}'"
assert isinstance(meta["description"], str)
assert isinstance(meta["owner_settable"], bool)


def test_new_hyperparams_owner_settable_true():
for key in NEW_HYPERPARAMS_826:
assert HYPERPARAMS_METADATA[key]["owner_settable"] is True
40 changes: 40 additions & 0 deletions tests/unit_tests/test_hyperparams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Unit tests for HYPERPARAMS and HYPERPARAMS_METADATA (issue #826)."""

from bittensor_cli.src import HYPERPARAMS, HYPERPARAMS_METADATA, RootSudoOnly


NEW_HYPERPARAMS_826 = {
"sn_owner_hotkey",
"subnet_owner_hotkey",
"recycle_or_burn",
}


def test_new_hyperparams_in_hyperparams():
for key in NEW_HYPERPARAMS_826:
assert key in HYPERPARAMS, f"{key} should be in HYPERPARAMS"
extrinsic, root_only = HYPERPARAMS[key]
assert extrinsic, f"{key} must have non-empty extrinsic name"
assert root_only is RootSudoOnly.FALSE


def test_subnet_owner_hotkey_alias_maps_to_same_extrinsic():
ext_sn, _ = HYPERPARAMS["sn_owner_hotkey"]
ext_subnet, _ = HYPERPARAMS["subnet_owner_hotkey"]
assert ext_sn == ext_subnet == "sudo_set_sn_owner_hotkey"


def test_new_hyperparams_have_metadata():
required = {"description", "side_effects", "owner_settable", "docs_link"}
for key in NEW_HYPERPARAMS_826:
assert key in HYPERPARAMS_METADATA, f"{key} should be in HYPERPARAMS_METADATA"
meta = HYPERPARAMS_METADATA[key]
for field in required:
assert field in meta, f"{key} metadata missing '{field}'"
assert isinstance(meta["description"], str)
assert isinstance(meta["owner_settable"], bool)


def test_new_hyperparams_owner_settable_true():
for key in NEW_HYPERPARAMS_826:
assert HYPERPARAMS_METADATA[key]["owner_settable"] is True
Loading