Skip to content

Commit fedfc23

Browse files
authored
Merge pull request #487 from opentensor/feat/thewhaleking/add-yuma3-set
Add Yuma3 Enabled for Sudo Set/Get
2 parents 00d977d + d03a87a commit fedfc23

File tree

6 files changed

+140
-70
lines changed

6 files changed

+140
-70
lines changed

bittensor_cli/src/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ class WalletValidationTypes(Enum):
658658
"sudo_set_network_pow_registration_allowed",
659659
False,
660660
),
661+
"yuma3_enabled": ("sudo_set_yuma3_enabled", False),
661662
}
662663

663664
# Help Panels for cli help

bittensor_cli/src/bittensor/chain_data.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class SubnetHyperparameters(InfoBase):
177177
alpha_high: int
178178
alpha_low: int
179179
liquid_alpha_enabled: bool
180+
yuma3_enabled: bool
180181

181182
@classmethod
182183
def _fix_decoded(
@@ -210,6 +211,7 @@ def _fix_decoded(
210211
alpha_high=decoded.get("alpha_high"),
211212
alpha_low=decoded.get("alpha_low"),
212213
liquid_alpha_enabled=decoded.get("liquid_alpha_enabled"),
214+
yuma3_enabled=decoded.get("yuma3_enabled"),
213215
)
214216

215217

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,14 +1128,18 @@ async def get_subnet_hyperparameters(
11281128
Understanding the hyperparameters is crucial for comprehending how subnets are configured and
11291129
managed, and how they interact with the network's consensus and incentive mechanisms.
11301130
"""
1131-
result = await self.query_runtime_api(
1132-
runtime_api="SubnetInfoRuntimeApi",
1133-
method="get_subnet_hyperparams",
1134-
params=[netuid],
1135-
block_hash=block_hash,
1131+
main_result, yuma3_result = await asyncio.gather(
1132+
self.query_runtime_api(
1133+
runtime_api="SubnetInfoRuntimeApi",
1134+
method="get_subnet_hyperparams",
1135+
params=[netuid],
1136+
block_hash=block_hash,
1137+
),
1138+
self.query("SubtensorModule", "Yuma3On", [netuid]),
11361139
)
1140+
result = {**main_result, **{"yuma3_enabled": yuma3_result}}
11371141

1138-
if not result:
1142+
if not main_result:
11391143
return []
11401144

11411145
return SubnetHyperparameters.from_any(result)

bittensor_cli/src/bittensor/utils.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import math
44
import os
55
import sqlite3
6-
import platform
76
import webbrowser
87
from pathlib import Path
98
from typing import TYPE_CHECKING, Any, Collection, Optional, Union, Callable
@@ -719,11 +718,14 @@ def millify_tao(n: float, start_at: str = "K") -> str:
719718

720719
def normalize_hyperparameters(
721720
subnet: "SubnetHyperparameters",
721+
json_output: bool = False,
722722
) -> list[tuple[str, str, str]]:
723723
"""
724724
Normalizes the hyperparameters of a subnet.
725725
726726
:param subnet: The subnet hyperparameters object.
727+
:param json_output: Whether this normalisation will be for a JSON output or console string (determines whether
728+
items get stringified or safe for JSON encoding)
727729
728730
:return: A list of tuples containing the parameter name, value, and normalized value.
729731
"""
@@ -750,13 +752,17 @@ def normalize_hyperparameters(
750752
norm_value = param_mappings[param](value)
751753
if isinstance(norm_value, float):
752754
norm_value = f"{norm_value:.{10}g}"
755+
if isinstance(norm_value, Balance) and json_output:
756+
norm_value = norm_value.to_dict()
753757
else:
754758
norm_value = value
755759
except Exception:
756760
# bittensor.logging.warning(f"Error normalizing parameter '{param}': {e}")
757761
norm_value = "-"
758-
759-
normalized_values.append((param, str(value), str(norm_value)))
762+
if not json_output:
763+
normalized_values.append((param, str(value), str(norm_value)))
764+
else:
765+
normalized_values.append((param, value, norm_value))
760766

761767
return normalized_values
762768

bittensor_cli/src/commands/sudo.py

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ def allowed_value(
7373
return True, value
7474

7575

76+
def string_to_bool(val) -> bool:
77+
try:
78+
return {"true": True, "1": True, "0": False, "false": False}[val.lower()]
79+
except KeyError:
80+
return ValueError
81+
82+
7683
def search_metadata(
7784
param_name: str, value: Union[str, bool, float, list[float]], netuid: int, metadata
7885
) -> tuple[bool, Optional[dict]]:
@@ -91,12 +98,6 @@ def search_metadata(
9198
9299
"""
93100

94-
def string_to_bool(val) -> bool:
95-
try:
96-
return {"true": True, "1": True, "0": False, "false": False}[val.lower()]
97-
except KeyError:
98-
return ValueError
99-
100101
def type_converter_with_retry(type_, val, arg_name):
101102
try:
102103
if val is None:
@@ -112,37 +113,55 @@ def type_converter_with_retry(type_, val, arg_name):
112113

113114
call_crafter = {"netuid": netuid}
114115

115-
for pallet in metadata.pallets:
116-
if pallet.name == "AdminUtils":
117-
for call in pallet.calls:
118-
if call.name == param_name:
119-
if "netuid" not in [x.name for x in call.args]:
120-
return False, None
121-
call_args = [
122-
arg for arg in call.args if arg.value["name"] != "netuid"
123-
]
124-
if len(call_args) == 1:
125-
arg = call_args[0].value
126-
call_crafter[arg["name"]] = type_converter_with_retry(
127-
arg["typeName"], value, arg["name"]
128-
)
129-
else:
130-
for arg_ in call_args:
131-
arg = arg_.value
132-
call_crafter[arg["name"]] = type_converter_with_retry(
133-
arg["typeName"], None, arg["name"]
134-
)
135-
return True, call_crafter
116+
pallet = metadata.get_metadata_pallet("AdminUtils")
117+
for call in pallet.calls:
118+
if call.name == param_name:
119+
if "netuid" not in [x.name for x in call.args]:
120+
return False, None
121+
call_args = [arg for arg in call.args if arg.value["name"] != "netuid"]
122+
if len(call_args) == 1:
123+
arg = call_args[0].value
124+
call_crafter[arg["name"]] = type_converter_with_retry(
125+
arg["typeName"], value, arg["name"]
126+
)
127+
else:
128+
for arg_ in call_args:
129+
arg = arg_.value
130+
call_crafter[arg["name"]] = type_converter_with_retry(
131+
arg["typeName"], None, arg["name"]
132+
)
133+
return True, call_crafter
136134
else:
137135
return False, None
138136

139137

138+
def requires_bool(metadata, param_name) -> bool:
139+
"""
140+
Determines whether a given hyperparam takes a single arg (besides netuid) that is of bool type.
141+
"""
142+
pallet = metadata.get_metadata_pallet("AdminUtils")
143+
for call in pallet.calls:
144+
if call.name == param_name:
145+
if "netuid" not in [x.name for x in call.args]:
146+
return False, None
147+
call_args = [arg for arg in call.args if arg.value["name"] != "netuid"]
148+
if len(call_args) != 1:
149+
return False
150+
else:
151+
arg = call_args[0].value
152+
if arg["typeName"] == "bool":
153+
return True
154+
else:
155+
return False
156+
raise ValueError(f"{param_name} not found in pallet.")
157+
158+
140159
async def set_hyperparameter_extrinsic(
141160
subtensor: "SubtensorInterface",
142161
wallet: "Wallet",
143162
netuid: int,
144163
parameter: str,
145-
value: Optional[Union[str, bool, float, list[float]]],
164+
value: Optional[Union[str, float, list[float]]],
146165
wait_for_inclusion: bool = False,
147166
wait_for_finalization: bool = True,
148167
prompt: bool = True,
@@ -221,15 +240,20 @@ async def set_hyperparameter_extrinsic(
221240
]
222241

223242
if len(value) < len(non_netuid_fields):
224-
raise ValueError(
243+
err_console.print(
225244
"Not enough values provided in the list for all parameters"
226245
)
246+
return False
227247

228248
call_params.update(
229249
{str(name): val for name, val in zip(non_netuid_fields, value)}
230250
)
231251

232252
else:
253+
if requires_bool(
254+
substrate.metadata, param_name=extrinsic
255+
) and isinstance(value, str):
256+
value = string_to_bool(value)
233257
value_argument = extrinsic_params["fields"][
234258
len(extrinsic_params["fields"]) - 1
235259
]
@@ -252,12 +276,13 @@ async def set_hyperparameter_extrinsic(
252276
)
253277
if not success:
254278
err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
255-
await asyncio.sleep(0.5)
279+
return False
256280
elif arbitrary_extrinsic:
257281
console.print(
258282
f":white_heavy_check_mark: "
259283
f"[dark_sea_green3]Hyperparameter {parameter} values changed to {call_params}[/dark_sea_green3]"
260284
)
285+
return True
261286
# Successful registration, final check for membership
262287
else:
263288
console.print(
@@ -581,28 +606,11 @@ async def sudo_set_hyperparameter(
581606
json_output: bool,
582607
):
583608
"""Set subnet hyperparameters."""
584-
585-
normalized_value: Union[str, bool]
586-
if param_name in [
587-
"registration_allowed",
588-
"network_pow_registration_allowed",
589-
"commit_reveal_weights_enabled",
590-
"liquid_alpha_enabled",
591-
]:
592-
normalized_value = param_value.lower() in ["true", "1"]
593-
elif param_value in ("True", "False"):
594-
normalized_value = {
595-
"True": True,
596-
"False": False,
597-
}[param_value]
598-
else:
599-
normalized_value = param_value
600-
601-
is_allowed_value, value = allowed_value(param_name, normalized_value)
609+
is_allowed_value, value = allowed_value(param_name, param_value)
602610
if not is_allowed_value:
603611
err_console.print(
604612
f"Hyperparameter [dark_orange]{param_name}[/dark_orange] value is not within bounds. "
605-
f"Value is {normalized_value} but must be {value}"
613+
f"Value is {param_value} but must be {value}"
606614
)
607615
return False
608616
success = await set_hyperparameter_extrinsic(
@@ -625,8 +633,9 @@ async def get_hyperparameters(
625633
if not await subtensor.subnet_exists(netuid):
626634
print_error(f"Subnet with netuid {netuid} does not exist.")
627635
return False
628-
subnet = await subtensor.get_subnet_hyperparameters(netuid)
629-
subnet_info = await subtensor.subnet(netuid)
636+
subnet, subnet_info = await asyncio.gather(
637+
subtensor.get_subnet_hyperparameters(netuid), subtensor.subnet(netuid)
638+
)
630639
if subnet_info is None:
631640
print_error(f"Subnet with netuid {netuid} does not exist.")
632641
return False
@@ -648,17 +657,18 @@ async def get_hyperparameters(
648657
)
649658
dict_out = []
650659

651-
normalized_values = normalize_hyperparameters(subnet)
652-
660+
normalized_values = normalize_hyperparameters(subnet, json_output=json_output)
653661
for param, value, norm_value in normalized_values:
654-
table.add_row(" " + param, value, norm_value)
655-
dict_out.append(
656-
{
657-
"hyperparameter": param,
658-
"value": value,
659-
"normalized_value": norm_value,
660-
}
661-
)
662+
if not json_output:
663+
table.add_row(" " + param, value, norm_value)
664+
else:
665+
dict_out.append(
666+
{
667+
"hyperparameter": param,
668+
"value": value,
669+
"normalized_value": norm_value,
670+
}
671+
)
662672
if json_output:
663673
json_console.print(json.dumps(dict_out))
664674
else:

tests/e2e_tests/test_staking_sudo.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,4 +461,51 @@ def test_staking(local_chain, wallet_setup):
461461
)["value"]
462462
assert Balance.from_rao(max_burn_tao_from_json) == Balance.from_tao(10.0)
463463

464+
change_yuma3_hyperparam = exec_command_alice(
465+
command="sudo",
466+
sub_command="set",
467+
extra_args=[
468+
"--wallet-path",
469+
wallet_path_alice,
470+
"--wallet-name",
471+
wallet_alice.name,
472+
"--hotkey",
473+
wallet_alice.hotkey_str,
474+
"--chain",
475+
"ws://127.0.0.1:9945",
476+
"--netuid",
477+
netuid,
478+
"--param",
479+
"yuma3_enabled",
480+
"--value",
481+
"true",
482+
"--no-prompt",
483+
"--json-output",
484+
],
485+
)
486+
change_yuma3_hyperparam_json = json.loads(change_yuma3_hyperparam.stdout)
487+
assert change_yuma3_hyperparam_json["success"] is True, (
488+
change_yuma3_hyperparam.stdout
489+
)
490+
491+
changed_yuma3_hyperparam = exec_command_alice(
492+
command="sudo",
493+
sub_command="get",
494+
extra_args=[
495+
"--chain",
496+
"ws://127.0.0.1:9945",
497+
"--netuid",
498+
netuid,
499+
"--json-output",
500+
],
501+
)
502+
503+
yuma3_val = next(
504+
filter(
505+
lambda x: x["hyperparameter"] == "yuma3_enabled",
506+
json.loads(changed_yuma3_hyperparam.stdout),
507+
)
508+
)
509+
assert yuma3_val["value"] is True
510+
assert yuma3_val["normalized_value"] is True
464511
print("✅ Passed staking and sudo commands")

0 commit comments

Comments
 (0)