Skip to content

Commit d037620

Browse files
authored
Merge pull request #587 from opentensor/release/9.10.1
Release/9.10.1
2 parents 84d31f5 + db8387a commit d037620

File tree

9 files changed

+175
-36
lines changed

9 files changed

+175
-36
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## 9.10.1 /2025-08-12
4+
* Removes double param for `--cache` in `config set` by @thewhaleking in https://github.com/opentensor/btcli/pull/579
5+
* change root only sudo hyperparams by @thewhaleking in https://github.com/opentensor/btcli/pull/580
6+
* Better error formatting by @thewhaleking in https://github.com/opentensor/btcli/pull/581
7+
* Handle optional netuid better by @thewhaleking in https://github.com/opentensor/btcli/pull/582
8+
* wallet fixes by @thewhaleking in https://github.com/opentensor/btcli/pull/585
9+
* Adds `moving_price` attr to DynamicInfo by @thewhaleking in https://github.com/opentensor/btcli/pull/583
10+
11+
**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.10.0...v9.10.1
12+
313
## 9.10.0 /2025-08-06
414
* Sets default interval hours for subnets price to 4, bc of rate limiting. by @thewhaleking in https://github.com/opentensor/btcli/pull/568
515
* Subnets Price --current + improvements by @thewhaleking in https://github.com/opentensor/btcli/pull/569

bittensor_cli/cli.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,10 +410,15 @@ def get_optional_netuid(netuid: Optional[int], all_netuids: bool) -> Optional[in
410410
)
411411
if answer is None:
412412
return None
413+
answer = answer.strip()
413414
if answer.lower() == "all":
414415
return None
415416
else:
416-
return int(answer)
417+
try:
418+
return int(answer)
419+
except ValueError:
420+
err_console.print(f"Invalid netuid: {answer}")
421+
return get_optional_netuid(None, False)
417422
else:
418423
return netuid
419424

@@ -1264,7 +1269,7 @@ def set_config(
12641269
use_cache: Optional[bool] = typer.Option(
12651270
None,
12661271
"--cache/--no-cache",
1267-
"--cache/--no_cache",
1272+
" /--no_cache",
12681273
help="Disable caching of some commands. This will disable the `--reuse-last` and `--html` flags on "
12691274
"commands such as `subnets metagraph`, `stake show` and `subnets list`.",
12701275
),
@@ -4816,7 +4821,7 @@ def sudo_set(
48164821
wallet = self.wallet_ask(
48174822
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
48184823
)
4819-
result = self._run_command(
4824+
result, err_msg = self._run_command(
48204825
sudo.sudo_set_hyperparameter(
48214826
wallet,
48224827
self.initialize_chain(network),
@@ -4828,7 +4833,7 @@ def sudo_set(
48284833
)
48294834
)
48304835
if json_output:
4831-
json_console.print(json.dumps({"success": result}))
4836+
json_console.print(json.dumps({"success": result, "err_msg": err_msg}))
48324837
return result
48334838

48344839
def sudo_get(

bittensor_cli/src/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,10 +631,10 @@ class WalletValidationTypes(Enum):
631631
"min_allowed_weights": ("sudo_set_min_allowed_weights", False),
632632
"max_weights_limit": ("sudo_set_max_weight_limit", False),
633633
"tempo": ("sudo_set_tempo", True),
634-
"min_difficulty": ("sudo_set_min_difficulty", False),
634+
"min_difficulty": ("sudo_set_min_difficulty", True),
635635
"max_difficulty": ("sudo_set_max_difficulty", False),
636636
"weights_version": ("sudo_set_weights_version_key", False),
637-
"weights_rate_limit": ("sudo_set_weights_set_rate_limit", False),
637+
"weights_rate_limit": ("sudo_set_weights_set_rate_limit", True),
638638
"adjustment_interval": ("sudo_set_adjustment_interval", True),
639639
"activity_cutoff": ("sudo_set_activity_cutoff", False),
640640
"target_regs_per_interval": ("sudo_set_target_registrations_per_interval", True),
@@ -645,15 +645,15 @@ class WalletValidationTypes(Enum):
645645
"serving_rate_limit": ("sudo_set_serving_rate_limit", False),
646646
"max_validators": ("sudo_set_max_allowed_validators", True),
647647
"adjustment_alpha": ("sudo_set_adjustment_alpha", False),
648-
"difficulty": ("sudo_set_difficulty", False),
648+
"difficulty": ("sudo_set_difficulty", True),
649649
"commit_reveal_period": (
650650
"sudo_set_commit_reveal_weights_interval",
651651
False,
652652
),
653653
"commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False),
654654
"alpha_values": ("sudo_set_alpha_values", False),
655655
"liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False),
656-
"registration_allowed": ("sudo_set_network_registration_allowed", False),
656+
"registration_allowed": ("sudo_set_network_registration_allowed", True),
657657
"network_pow_registration_allowed": (
658658
"sudo_set_network_pow_registration_allowed",
659659
False,

bittensor_cli/src/bittensor/chain_data.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ class DynamicInfo(InfoBase):
718718
network_registered_at: int
719719
subnet_identity: Optional[SubnetIdentity]
720720
subnet_volume: Balance
721+
moving_price: float
721722

722723
@classmethod
723724
def _fix_decoded(cls, decoded: Any) -> "DynamicInfo":
@@ -786,6 +787,7 @@ def _fix_decoded(cls, decoded: Any) -> "DynamicInfo":
786787
network_registered_at=int(decoded.get("network_registered_at")),
787788
subnet_identity=subnet_identity,
788789
subnet_volume=subnet_volume,
790+
moving_price=fixed_to_float(decoded["moving_price"], 32),
789791
)
790792

791793
def tao_to_alpha(self, tao: Balance) -> Balance:

bittensor_cli/src/bittensor/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,9 @@ def format_error_message(error_message: Union[dict, Exception]) -> str:
575575
err_type = error_message.get("type", err_type)
576576
err_name = error_message.get("name", err_name)
577577
err_docs = error_message.get("docs", [err_description])
578-
err_description = " ".join(err_docs)
578+
err_description = (
579+
" ".join(err_docs) if not isinstance(err_docs, str) else err_docs
580+
)
579581
err_description += (
580582
f" | Please consult {BT_DOCS_LINK}/errors/subtensor#{err_name.lower()}"
581583
)
@@ -1441,5 +1443,5 @@ def get_hotkey_pub_ss58(wallet: Wallet) -> str:
14411443
"""
14421444
try:
14431445
return wallet.hotkeypub.ss58_address
1444-
except KeyFileError:
1446+
except (KeyFileError, AttributeError):
14451447
return wallet.hotkey.ss58_address

bittensor_cli/src/commands/sudo.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ async def set_hyperparameter_extrinsic(
177177
wait_for_inclusion: bool = False,
178178
wait_for_finalization: bool = True,
179179
prompt: bool = True,
180-
) -> bool:
180+
) -> tuple[bool, str]:
181181
"""Sets a hyperparameter for a specific subnetwork.
182182

183183
:param subtensor: initialized SubtensorInterface object
@@ -200,13 +200,14 @@ async def set_hyperparameter_extrinsic(
200200
params=[netuid],
201201
)
202202
if subnet_owner != wallet.coldkeypub.ss58_address:
203-
err_console.print(
203+
err_msg = (
204204
":cross_mark: [red]This wallet doesn't own the specified subnet.[/red]"
205205
)
206-
return False
206+
err_console.print(err_msg)
207+
return False, err_msg
207208

208-
if not unlock_key(wallet).success:
209-
return False
209+
if not (ulw := unlock_key(wallet)).success:
210+
return False, ulw.message
210211

211212
arbitrary_extrinsic = False
212213

@@ -218,15 +219,14 @@ async def set_hyperparameter_extrinsic(
218219
)
219220
extrinsic = parameter
220221
if not arbitrary_extrinsic:
221-
err_console.print(
222-
":cross_mark: [red]Invalid hyperparameter specified.[/red]"
223-
)
224-
return False
222+
err_msg = ":cross_mark: [red]Invalid hyperparameter specified.[/red]"
223+
err_console.print(err_msg)
224+
return False, err_msg
225225
if sudo_ and prompt:
226226
if not Confirm.ask(
227227
"This hyperparam is only settable by root sudo users. If you are not, this will fail. Please confirm"
228228
):
229-
return False
229+
return False, "This hyperparam is only settable by root sudo users"
230230

231231
substrate = subtensor.substrate
232232
msg_value = value if not arbitrary_extrinsic else call_params
@@ -254,10 +254,11 @@ async def set_hyperparameter_extrinsic(
254254
]
255255

256256
if len(value) < len(non_netuid_fields):
257-
err_console.print(
257+
err_msg = (
258258
"Not enough values provided in the list for all parameters"
259259
)
260-
return False
260+
err_console.print(err_msg)
261+
return False, err_msg
261262

262263
call_params.update(
263264
{name: val for name, val in zip(non_netuid_fields, value)}
@@ -290,20 +291,20 @@ async def set_hyperparameter_extrinsic(
290291
)
291292
if not success:
292293
err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
293-
return False
294+
return False, err_msg
294295
elif arbitrary_extrinsic:
295296
console.print(
296297
f":white_heavy_check_mark: "
297298
f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]"
298299
)
299-
return True
300+
return True, ""
300301
# Successful registration, final check for membership
301302
else:
302303
console.print(
303304
f":white_heavy_check_mark: "
304305
f"[dark_sea_green3]Hyperparameter {parameter} changed to {value}[/dark_sea_green3]"
305306
)
306-
return True
307+
return True, ""
307308

308309

309310
async def _get_senate_members(
@@ -619,25 +620,26 @@ async def sudo_set_hyperparameter(
619620
param_value: Optional[str],
620621
prompt: bool,
621622
json_output: bool,
622-
):
623+
) -> tuple[bool, str]:
623624
"""Set subnet hyperparameters."""
624625
is_allowed_value, value = allowed_value(param_name, param_value)
625626
if not is_allowed_value:
626-
err_console.print(
627+
err_msg = (
627628
f"Hyperparameter [dark_orange]{param_name}[/dark_orange] value is not within bounds. "
628629
f"Value is {param_value} but must be {value}"
629630
)
630-
return False
631-
success = await set_hyperparameter_extrinsic(
631+
err_console.print(err_msg)
632+
return False, err_msg
633+
success, err_msg = await set_hyperparameter_extrinsic(
632634
subtensor, wallet, netuid, param_name, value, prompt=prompt
633635
)
634636
if json_output:
635-
return success
637+
return success, err_msg
636638
if success:
637639
console.print("\n")
638640
print_verbose("Fetching hyperparameters")
639641
await get_hyperparameters(subtensor, netuid=netuid)
640-
return success
642+
return success, err_msg
641643

642644

643645
async def get_hyperparameters(

bittensor_cli/src/commands/wallets.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,13 +452,15 @@ async def wallet_create(
452452
"error": "",
453453
"data": None,
454454
}
455+
455456
if uri:
456457
try:
457458
keypair = Keypair.create_from_uri(uri)
458-
wallet.set_coldkey(keypair=keypair, encrypt=False, overwrite=False)
459-
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False)
460-
wallet.set_hotkey(keypair=keypair, encrypt=False, overwrite=False)
461-
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=False)
459+
wallet.set_coldkey(keypair=keypair, encrypt=False, overwrite=overwrite)
460+
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=overwrite)
461+
wallet.set_hotkey(keypair=keypair, encrypt=False, overwrite=overwrite)
462+
wallet.set_hotkeypub(keypair=keypair, encrypt=False, overwrite=overwrite)
463+
wallet.set_coldkeypub(keypair=keypair, encrypt=False, overwrite=overwrite)
462464
output_dict["success"] = True
463465
output_dict["data"] = {
464466
"name": wallet.name,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "bittensor-cli"
7-
version = "9.10.0"
7+
version = "9.10.1"
88
description = "Bittensor CLI"
99
readme = "README.md"
1010
authors = [
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import json
2+
3+
from bittensor_cli.src import HYPERPARAMS
4+
5+
"""
6+
Verify commands:
7+
8+
* btcli subnets create
9+
* btcli sudo set
10+
* btcli sudo get
11+
"""
12+
13+
14+
def test_hyperparams_setting(local_chain, wallet_setup):
15+
netuid = 2
16+
wallet_path_alice = "//Alice"
17+
# Create wallet for Alice
18+
keypair_alice, wallet_alice, wallet_path_alice, exec_command_alice = wallet_setup(
19+
wallet_path_alice
20+
)
21+
22+
# Register a subnet with sudo as Alice
23+
result = exec_command_alice(
24+
command="subnets",
25+
sub_command="create",
26+
extra_args=[
27+
"--wallet-path",
28+
wallet_path_alice,
29+
"--network",
30+
"ws://127.0.0.1:9945",
31+
"--wallet-name",
32+
wallet_alice.name,
33+
"--wallet-hotkey",
34+
wallet_alice.hotkey_str,
35+
"--subnet-name",
36+
"Test Subnet",
37+
"--repo",
38+
"https://github.com/username/repo",
39+
"--contact",
40+
41+
"--url",
42+
"https://testsubnet.com",
43+
"--discord",
44+
"alice#1234",
45+
"--description",
46+
"A test subnet for e2e testing",
47+
"--additional-info",
48+
"Created by Alice",
49+
"--logo-url",
50+
"https://testsubnet.com/logo.png",
51+
"--no-prompt",
52+
"--json-output",
53+
],
54+
)
55+
result_output = json.loads(result.stdout)
56+
assert result_output["success"] is True
57+
assert result_output["netuid"] == netuid
58+
print(result_output)
59+
60+
# Fetch the hyperparameters of the subnet
61+
hyperparams = exec_command_alice(
62+
command="sudo",
63+
sub_command="get",
64+
extra_args=[
65+
"--network",
66+
"ws://127.0.0.1:9945",
67+
"--netuid",
68+
netuid,
69+
"--json-out",
70+
],
71+
)
72+
73+
# Parse all hyperparameters and single out max_burn in TAO
74+
all_hyperparams = json.loads(hyperparams.stdout)
75+
hp = {}
76+
for hyperparam in all_hyperparams:
77+
hp[hyperparam["hyperparameter"]] = hyperparam["value"]
78+
for key, (_, sudo_only) in HYPERPARAMS.items():
79+
if key in hp.keys() and not sudo_only:
80+
if isinstance(hp[key], bool):
81+
new_val = not hp[key]
82+
elif isinstance(hp[key], int):
83+
if hp[key] < 100:
84+
new_val = hp[key] + 1
85+
else:
86+
new_val = hp[key] - 1
87+
else:
88+
raise ValueError(
89+
f"Unrecognized hyperparameter value type: {key}: {hp[key]}"
90+
)
91+
cmd = exec_command_alice(
92+
command="sudo",
93+
sub_command="set",
94+
extra_args=[
95+
"--wallet-path",
96+
wallet_path_alice,
97+
"--network",
98+
"ws://127.0.0.1:9945",
99+
"--wallet-name",
100+
wallet_alice.name,
101+
"--wallet-hotkey",
102+
wallet_alice.hotkey_str,
103+
"--netuid",
104+
netuid,
105+
"--json-out",
106+
"--no-prompt",
107+
"--param",
108+
key,
109+
"--value",
110+
new_val,
111+
],
112+
)
113+
cmd_json = json.loads(cmd.stdout)
114+
assert cmd_json["success"] is True, (key, new_val, cmd.stdout, cmd_json)
115+
print(f"Successfully set hyperparameter {key} to value {new_val}")
116+
print("Successfully set hyperparameters")

0 commit comments

Comments
 (0)