Skip to content

Commit ad64a11

Browse files
committed
Sudo commands.
1 parent 419fa6b commit ad64a11

File tree

2 files changed

+110
-34
lines changed

2 files changed

+110
-34
lines changed

bittensor_cli/cli.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,6 +4163,7 @@ def sudo_set(
41634163
),
41644164
quiet: bool = Options.quiet,
41654165
verbose: bool = Options.verbose,
4166+
json_output: bool = Options.json_output,
41664167
):
41674168
"""
41684169
Used to set hyperparameters for a specific subnet.
@@ -4173,7 +4174,7 @@ def sudo_set(
41734174
41744175
[green]$[/green] btcli sudo set --netuid 1 --param tempo --value 400
41754176
"""
4176-
self.verbosity_handler(quiet, verbose)
4177+
self.verbosity_handler(quiet, verbose, json_output)
41774178

41784179
if not param_name or not param_value:
41794180
hyperparams = self._run_command(
@@ -4218,22 +4219,27 @@ def sudo_set(
42184219
wallet = self.wallet_ask(
42194220
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
42204221
)
4221-
return self._run_command(
4222+
result = self._run_command(
42224223
sudo.sudo_set_hyperparameter(
42234224
wallet,
42244225
self.initialize_chain(network),
42254226
netuid,
42264227
param_name,
42274228
param_value,
4229+
json_output,
42284230
)
42294231
)
4232+
if json_output:
4233+
json_console.print(json.dumps({"success": result}))
4234+
return result
42304235

42314236
def sudo_get(
42324237
self,
42334238
network: Optional[list[str]] = Options.network,
42344239
netuid: int = Options.netuid,
42354240
quiet: bool = Options.quiet,
42364241
verbose: bool = Options.verbose,
4242+
json_output: bool = Options.json_output,
42374243
):
42384244
"""
42394245
Shows a list of the hyperparameters for the specified subnet.
@@ -4244,14 +4250,17 @@ def sudo_get(
42444250
"""
42454251
self.verbosity_handler(quiet, verbose)
42464252
return self._run_command(
4247-
sudo.get_hyperparameters(self.initialize_chain(network), netuid)
4253+
sudo.get_hyperparameters(
4254+
self.initialize_chain(network), netuid, json_output
4255+
)
42484256
)
42494257

42504258
def sudo_senate(
42514259
self,
42524260
network: Optional[list[str]] = Options.network,
42534261
quiet: bool = Options.quiet,
42544262
verbose: bool = Options.verbose,
4263+
json_output: bool = Options.json_output,
42554264
):
42564265
"""
42574266
Shows the Senate members of the Bittensor's governance protocol.
@@ -4261,14 +4270,17 @@ def sudo_senate(
42614270
EXAMPLE
42624271
[green]$[/green] btcli sudo senate
42634272
"""
4264-
self.verbosity_handler(quiet, verbose)
4265-
return self._run_command(sudo.get_senate(self.initialize_chain(network)))
4273+
self.verbosity_handler(quiet, verbose, json_output)
4274+
return self._run_command(
4275+
sudo.get_senate(self.initialize_chain(network), json_output)
4276+
)
42664277

42674278
def sudo_proposals(
42684279
self,
42694280
network: Optional[list[str]] = Options.network,
42704281
quiet: bool = Options.quiet,
42714282
verbose: bool = Options.verbose,
4283+
json_output: bool = Options.json_output,
42724284
):
42734285
"""
42744286
View active proposals for the senate in the Bittensor's governance protocol.
@@ -4278,7 +4290,7 @@ def sudo_proposals(
42784290
EXAMPLE
42794291
[green]$[/green] btcli sudo proposals
42804292
"""
4281-
self.verbosity_handler(quiet, verbose)
4293+
self.verbosity_handler(quiet, verbose, json_output)
42824294
return self._run_command(
42834295
sudo.proposals(self.initialize_chain(network), verbose)
42844296
)
@@ -4317,6 +4329,7 @@ def sudo_senate_vote(
43174329
EXAMPLE
43184330
[green]$[/green] btcli sudo senate_vote --proposal <proposal_hash>
43194331
"""
4332+
# TODO discuss whether this should receive json_output. I don't think it should.
43204333
self.verbosity_handler(quiet, verbose)
43214334
wallet = self.wallet_ask(
43224335
wallet_name,
@@ -4340,6 +4353,7 @@ def sudo_set_take(
43404353
take: float = typer.Option(None, help="The new take value."),
43414354
quiet: bool = Options.quiet,
43424355
verbose: bool = Options.verbose,
4356+
json_output: bool = Options.json_output,
43434357
):
43444358
"""
43454359
Allows users to change their delegate take percentage.
@@ -4352,7 +4366,7 @@ def sudo_set_take(
43524366
"""
43534367
max_value = 0.18
43544368
min_value = 0.00
4355-
self.verbosity_handler(quiet, verbose)
4369+
self.verbosity_handler(quiet, verbose, json_output)
43564370

43574371
wallet = self.wallet_ask(
43584372
wallet_name,
@@ -4377,9 +4391,12 @@ def sudo_set_take(
43774391
)
43784392
raise typer.Exit()
43794393

4380-
return self._run_command(
4394+
result = self._run_command(
43814395
sudo.set_take(wallet, self.initialize_chain(network), take)
43824396
)
4397+
if json_output:
4398+
json_console.print(json.dumps({"success": result}))
4399+
return result
43834400

43844401
def sudo_get_take(
43854402
self,
@@ -4389,6 +4406,7 @@ def sudo_get_take(
43894406
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
43904407
quiet: bool = Options.quiet,
43914408
verbose: bool = Options.verbose,
4409+
json_output: bool = Options.json_output,
43924410
):
43934411
"""
43944412
Allows users to check their delegate take percentage.
@@ -4398,7 +4416,7 @@ def sudo_get_take(
43984416
EXAMPLE
43994417
[green]$[/green] btcli sudo get-take --wallet-name my_wallet --wallet-hotkey my_hotkey
44004418
"""
4401-
self.verbosity_handler(quiet, verbose)
4419+
self.verbosity_handler(quiet, verbose, json_output)
44024420

44034421
wallet = self.wallet_ask(
44044422
wallet_name,
@@ -4407,10 +4425,15 @@ def sudo_get_take(
44074425
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
44084426
validate=WV.WALLET_AND_HOTKEY,
44094427
)
4410-
4411-
self._run_command(
4412-
sudo.display_current_take(self.initialize_chain(network), wallet)
4413-
)
4428+
if json_output:
4429+
result = self._run_command(
4430+
sudo.get_current_take(self.initialize_chain(network), wallet)
4431+
)
4432+
json_console.print(json.dumps({"current_take": result}))
4433+
else:
4434+
self._run_command(
4435+
sudo.display_current_take(self.initialize_chain(network), wallet)
4436+
)
44144437

44154438
def subnets_list(
44164439
self,

bittensor_cli/src/commands/sudo.py

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import json
23
from typing import TYPE_CHECKING, Union, Optional
34

45
from bittensor_wallet import Wallet
@@ -19,6 +20,7 @@
1920
blocks_to_duration,
2021
float_to_u64,
2122
float_to_u16,
23+
json_console,
2224
)
2325

2426
if TYPE_CHECKING:
@@ -350,6 +352,19 @@ def display_votes(
350352
return "\n".join(vote_list)
351353

352354

355+
def serialize_vote_data(
356+
vote_data: "ProposalVoteData", delegate_info: dict[str, DelegatesDetails]
357+
) -> list[dict[str, bool]]:
358+
vote_list = []
359+
for address in vote_data.ayes:
360+
f_add = delegate_info[address].display if address in delegate_info else address
361+
vote_list.append({f_add: True})
362+
for address in vote_data.nays:
363+
f_add = delegate_info[address].display if address in delegate_info else address
364+
vote_list.append({f_add: False})
365+
return vote_list
366+
367+
353368
def format_call_data(call_data: dict) -> str:
354369
# Extract the module and call details
355370
module, call_details = next(iter(call_data.items()))
@@ -559,6 +574,7 @@ async def sudo_set_hyperparameter(
559574
netuid: int,
560575
param_name: str,
561576
param_value: Optional[str],
577+
json_output: bool,
562578
):
563579
"""Set subnet hyperparameters."""
564580

@@ -584,17 +600,22 @@ async def sudo_set_hyperparameter(
584600
f"Hyperparameter [dark_orange]{param_name}[/dark_orange] value is not within bounds. "
585601
f"Value is {normalized_value} but must be {value}"
586602
)
587-
return
603+
return False
588604
success = await set_hyperparameter_extrinsic(
589605
subtensor, wallet, netuid, param_name, value
590606
)
607+
if json_output:
608+
return success
591609
if success:
592610
console.print("\n")
593611
print_verbose("Fetching hyperparameters")
594-
return await get_hyperparameters(subtensor, netuid=netuid)
612+
await get_hyperparameters(subtensor, netuid=netuid)
613+
return success
595614

596615

597-
async def get_hyperparameters(subtensor: "SubtensorInterface", netuid: int):
616+
async def get_hyperparameters(
617+
subtensor: "SubtensorInterface", netuid: int, json_output: bool = False
618+
) -> bool:
598619
"""View hyperparameters of a subnetwork."""
599620
print_verbose("Fetching hyperparameters")
600621
if not await subtensor.subnet_exists(netuid):
@@ -607,32 +628,43 @@ async def get_hyperparameters(subtensor: "SubtensorInterface", netuid: int):
607628
return False
608629

609630
table = Table(
610-
Column("[white]HYPERPARAMETER", style=COLOR_PALETTE["SUDO"]["HYPERPARAMETER"]),
611-
Column("[white]VALUE", style=COLOR_PALETTE["SUDO"]["VALUE"]),
612-
Column("[white]NORMALIZED", style=COLOR_PALETTE["SUDO"]["NORMALIZED"]),
613-
title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]\nSubnet Hyperparameters\n NETUID: "
614-
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid}"
631+
Column("[white]HYPERPARAMETER", style=COLOR_PALETTE.SU.HYPERPARAMETER),
632+
Column("[white]VALUE", style=COLOR_PALETTE.SU.VALUE),
633+
Column("[white]NORMALIZED", style=COLOR_PALETTE.SU.NORMAL),
634+
title=f"[{COLOR_PALETTE.G.HEADER}]\nSubnet Hyperparameters\n NETUID: "
635+
f"[{COLOR_PALETTE.G.SUBHEAD}]{netuid}"
615636
f"{f' ({subnet_info.subnet_name})' if subnet_info.subnet_name is not None else ''}"
616-
f"[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
617-
f" - Network: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{subtensor.network}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\n",
637+
f"[/{COLOR_PALETTE.G.SUBHEAD}]"
638+
f" - Network: [{COLOR_PALETTE.G.SUBHEAD}]{subtensor.network}[/{COLOR_PALETTE.G.SUBHEAD}]\n",
618639
show_footer=True,
619640
width=None,
620641
pad_edge=False,
621642
box=box.SIMPLE,
622643
show_edge=True,
623644
)
645+
dict_out = []
624646

625647
normalized_values = normalize_hyperparameters(subnet)
626648

627649
for param, value, norm_value in normalized_values:
628650
table.add_row(" " + param, value, norm_value)
629-
651+
dict_out.append(
652+
{
653+
"hyperparameter": param,
654+
"value": value,
655+
"normalized_value": norm_value,
656+
}
657+
)
658+
if json_output:
659+
json_console.print(json.dumps(dict_out))
630660
console.print(table)
631661
return True
632662

633663

634-
async def get_senate(subtensor: "SubtensorInterface"):
635-
"""View Bittensor's senate memebers"""
664+
async def get_senate(
665+
subtensor: "SubtensorInterface", json_output: bool = False
666+
) -> None:
667+
"""View Bittensor's senate members"""
636668
with console.status(
637669
f":satellite: Syncing with chain: [white]{subtensor}[/white] ...",
638670
spinner="aesthetic",
@@ -663,21 +695,27 @@ async def get_senate(subtensor: "SubtensorInterface"):
663695
border_style="bright_black",
664696
leading=True,
665697
)
698+
dict_output = []
666699

667700
for ss58_address in senate_members:
701+
member_name = (
702+
delegate_info[ss58_address].display
703+
if ss58_address in delegate_info
704+
else "~"
705+
)
668706
table.add_row(
669-
(
670-
delegate_info[ss58_address].display
671-
if ss58_address in delegate_info
672-
else "~"
673-
),
707+
member_name,
674708
ss58_address,
675709
)
676-
710+
dict_output.append({"name": member_name, "ss58_address": ss58_address})
711+
if json_output:
712+
json_console.print(json.dumps(dict_output))
677713
return console.print(table)
678714

679715

680-
async def proposals(subtensor: "SubtensorInterface", verbose: bool):
716+
async def proposals(
717+
subtensor: "SubtensorInterface", verbose: bool, json_output: bool = False
718+
) -> None:
681719
console.print(
682720
":satellite: Syncing with chain: [white]{}[/white] ...".format(
683721
subtensor.network
@@ -723,6 +761,7 @@ async def proposals(subtensor: "SubtensorInterface", verbose: bool):
723761
width=None,
724762
border_style="bright_black",
725763
)
764+
dict_output = []
726765
for hash_, (call_data, vote_data) in all_proposals.items():
727766
blocks_remaining = vote_data.end - current_block
728767
if blocks_remaining > 0:
@@ -741,15 +780,29 @@ async def proposals(subtensor: "SubtensorInterface", verbose: bool):
741780
if vote_data.threshold > 0
742781
else 0
743782
)
783+
f_call_data = format_call_data(call_data)
744784
table.add_row(
745785
hash_ if verbose else f"{hash_[:4]}...{hash_[-4:]}",
746786
str(vote_data.threshold),
747787
f"{len(vote_data.ayes)} ({ayes_threshold:.2f}%)",
748788
f"{len(vote_data.nays)} ({nays_threshold:.2f}%)",
749789
display_votes(vote_data, registered_delegate_info),
750790
vote_end_cell,
751-
format_call_data(call_data),
791+
f_call_data,
792+
)
793+
dict_output.append(
794+
{
795+
"hash": hash_,
796+
"threshold": vote_data.threshold,
797+
"ayes": len(vote_data.ayes),
798+
"nays": len(vote_data.nays),
799+
"votes": serialize_vote_data(vote_data, registered_delegate_info),
800+
"end": vote_data.end,
801+
"call_data": f_call_data,
802+
}
752803
)
804+
if json_output:
805+
json_console.print(json.dumps(dict_output))
753806
console.print(table)
754807
console.print(
755808
"\n[dim]* Both Ayes and Nays percentages are calculated relative to the proposal's threshold.[/dim]"

0 commit comments

Comments
 (0)