bittensor-cli 9.10.2__py3-none-any.whl → 9.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bittensor_cli/cli.py +541 -104
- bittensor_cli/src/__init__.py +3 -0
- bittensor_cli/src/bittensor/subtensor_interface.py +43 -15
- bittensor_cli/src/bittensor/utils.py +18 -2
- bittensor_cli/src/commands/stake/remove.py +1 -0
- bittensor_cli/src/commands/subnets/price.py +11 -1
- bittensor_cli/src/commands/subnets/subnets.py +68 -0
- bittensor_cli/src/commands/sudo.py +5 -4
- bittensor_cli/src/commands/wallets.py +12 -3
- {bittensor_cli-9.10.2.dist-info → bittensor_cli-9.11.0.dist-info}/METADATA +31 -5
- {bittensor_cli-9.10.2.dist-info → bittensor_cli-9.11.0.dist-info}/RECORD +14 -14
- {bittensor_cli-9.10.2.dist-info → bittensor_cli-9.11.0.dist-info}/WHEEL +0 -0
- {bittensor_cli-9.10.2.dist-info → bittensor_cli-9.11.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-9.10.2.dist-info → bittensor_cli-9.11.0.dist-info}/top_level.txt +0 -0
bittensor_cli/cli.py
CHANGED
@@ -4,6 +4,7 @@ import copy
|
|
4
4
|
import curses
|
5
5
|
import importlib
|
6
6
|
import json
|
7
|
+
import logging
|
7
8
|
import os.path
|
8
9
|
import re
|
9
10
|
import ssl
|
@@ -12,7 +13,7 @@ import traceback
|
|
12
13
|
import warnings
|
13
14
|
from dataclasses import fields
|
14
15
|
from pathlib import Path
|
15
|
-
from typing import Coroutine, Optional, Union
|
16
|
+
from typing import Coroutine, Optional, Union, Literal
|
16
17
|
|
17
18
|
import numpy as np
|
18
19
|
import rich
|
@@ -42,7 +43,10 @@ from bittensor_cli.src import (
|
|
42
43
|
from bittensor_cli.src.bittensor import utils
|
43
44
|
from bittensor_cli.src.bittensor.balances import Balance
|
44
45
|
from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters
|
45
|
-
from bittensor_cli.src.bittensor.subtensor_interface import
|
46
|
+
from bittensor_cli.src.bittensor.subtensor_interface import (
|
47
|
+
SubtensorInterface,
|
48
|
+
best_connection,
|
49
|
+
)
|
46
50
|
from bittensor_cli.src.bittensor.utils import (
|
47
51
|
console,
|
48
52
|
err_console,
|
@@ -86,11 +90,19 @@ except ImportError:
|
|
86
90
|
pass
|
87
91
|
|
88
92
|
|
93
|
+
logger = logging.getLogger("btcli")
|
89
94
|
_epilog = "Made with [bold red]:heart:[/bold red] by The Openτensor Foundaτion"
|
90
95
|
|
91
96
|
np.set_printoptions(precision=8, suppress=True, floatmode="fixed")
|
92
97
|
|
93
98
|
|
99
|
+
def arg__(arg_name: str) -> str:
|
100
|
+
"""
|
101
|
+
Helper function to 'arg' format a string for rich console
|
102
|
+
"""
|
103
|
+
return f"[{COLORS.G.ARG}]{arg_name}[/{COLORS.G.ARG}]"
|
104
|
+
|
105
|
+
|
94
106
|
class Options:
|
95
107
|
"""
|
96
108
|
Re-usable typer args
|
@@ -592,6 +604,42 @@ def commands_callback(value: bool):
|
|
592
604
|
if value:
|
593
605
|
cli = CLIManager()
|
594
606
|
console.print(cli.generate_command_tree())
|
607
|
+
|
608
|
+
|
609
|
+
def debug_callback(value: bool):
|
610
|
+
if value:
|
611
|
+
debug_file_loc = Path(
|
612
|
+
os.getenv("BTCLI_DEBUG_FILE")
|
613
|
+
or os.path.expanduser(defaults.config.debug_file_path)
|
614
|
+
)
|
615
|
+
if not debug_file_loc.exists():
|
616
|
+
err_console.print(
|
617
|
+
f"[red]Error: The debug file '{arg__(str(debug_file_loc))}' does not exist. This indicates that you have"
|
618
|
+
f" not run a command which has logged debug output, or you deleted this file. Debug logging only occurs"
|
619
|
+
f" if {arg__('use_cache')} is set to True in your config ({arg__('btcli config set')}). If the debug "
|
620
|
+
f"file was created using the {arg__('BTCLI_DEBUG_FILE')} environment variable, please set the value for"
|
621
|
+
f" the same location, and re-run this {arg__('btcli --debug')} command.[/red]"
|
622
|
+
)
|
623
|
+
raise typer.Exit()
|
624
|
+
save_file_loc_ = Prompt.ask(
|
625
|
+
"Enter the file location to save the debug log for the previous command.",
|
626
|
+
default="~/.bittensor/debug-export",
|
627
|
+
).strip()
|
628
|
+
save_file_loc = Path(os.path.expanduser(save_file_loc_))
|
629
|
+
if not save_file_loc.parent.exists():
|
630
|
+
if Confirm.ask(
|
631
|
+
f"The directory '{save_file_loc.parent}' does not exist. Would you like to create it?"
|
632
|
+
):
|
633
|
+
save_file_loc.parent.mkdir(parents=True, exist_ok=True)
|
634
|
+
try:
|
635
|
+
with (
|
636
|
+
open(save_file_loc, "w+") as save_file,
|
637
|
+
open(debug_file_loc, "r") as current_file,
|
638
|
+
):
|
639
|
+
save_file.write(current_file.read())
|
640
|
+
console.print(f"Saved debug log to {save_file_loc}")
|
641
|
+
except FileNotFoundError as e:
|
642
|
+
print_error(str(e))
|
595
643
|
raise typer.Exit()
|
596
644
|
|
597
645
|
|
@@ -612,7 +660,7 @@ class CLIManager:
|
|
612
660
|
wallet_app: typer.Typer
|
613
661
|
subnets_app: typer.Typer
|
614
662
|
weights_app: typer.Typer
|
615
|
-
utils_app
|
663
|
+
utils_app: typer.Typer
|
616
664
|
view_app: typer.Typer
|
617
665
|
asyncio_runner = asyncio
|
618
666
|
|
@@ -623,6 +671,7 @@ class CLIManager:
|
|
623
671
|
"wallet_hotkey": None,
|
624
672
|
"network": None,
|
625
673
|
"use_cache": True,
|
674
|
+
"disk_cache": False,
|
626
675
|
"rate_tolerance": None,
|
627
676
|
"safe_staking": True,
|
628
677
|
"allow_partial_stake": False,
|
@@ -664,6 +713,9 @@ class CLIManager:
|
|
664
713
|
self.config_path = os.getenv("BTCLI_CONFIG_PATH") or os.path.expanduser(
|
665
714
|
defaults.config.path
|
666
715
|
)
|
716
|
+
self.debug_file_path = os.getenv("BTCLI_DEBUG_FILE") or os.path.expanduser(
|
717
|
+
defaults.config.debug_file_path
|
718
|
+
)
|
667
719
|
|
668
720
|
self.app = typer.Typer(
|
669
721
|
rich_markup_mode="rich",
|
@@ -674,8 +726,8 @@ class CLIManager:
|
|
674
726
|
self.config_app = typer.Typer(
|
675
727
|
epilog=_epilog,
|
676
728
|
help=f"Allows for getting/setting the config. "
|
677
|
-
f"Default path for the config file is
|
678
|
-
f"You can set your own with the env var
|
729
|
+
f"Default path for the config file is {arg__(defaults.config.path)}. "
|
730
|
+
f"You can set your own with the env var {arg__('BTCLI_CONFIG_PATH')}",
|
679
731
|
)
|
680
732
|
self.wallet_app = typer.Typer(epilog=_epilog)
|
681
733
|
self.stake_app = typer.Typer(epilog=_epilog)
|
@@ -684,6 +736,7 @@ class CLIManager:
|
|
684
736
|
self.weights_app = typer.Typer(epilog=_epilog)
|
685
737
|
self.view_app = typer.Typer(epilog=_epilog)
|
686
738
|
self.liquidity_app = typer.Typer(epilog=_epilog)
|
739
|
+
self.utils_app = typer.Typer(epilog=_epilog)
|
687
740
|
|
688
741
|
# config alias
|
689
742
|
self.app.add_typer(
|
@@ -758,7 +811,7 @@ class CLIManager:
|
|
758
811
|
|
759
812
|
# utils app
|
760
813
|
self.app.add_typer(
|
761
|
-
self.utils_app, name="utils", no_args_is_help=True, hidden=
|
814
|
+
self.utils_app, name="utils", no_args_is_help=True, hidden=False
|
762
815
|
)
|
763
816
|
|
764
817
|
# view app
|
@@ -948,6 +1001,9 @@ class CLIManager:
|
|
948
1001
|
self.subnets_app.command(
|
949
1002
|
"check-start", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
|
950
1003
|
)(self.subnets_check_start)
|
1004
|
+
self.subnets_app.command(
|
1005
|
+
"set-symbol", rich_help_panel=HELP_PANELS["SUBNETS"]["IDENTITY"]
|
1006
|
+
)(self.subnets_set_symbol)
|
951
1007
|
|
952
1008
|
# weights commands
|
953
1009
|
self.weights_app.command(
|
@@ -1040,6 +1096,10 @@ class CLIManager:
|
|
1040
1096
|
"remove", rich_help_panel=HELP_PANELS["LIQUIDITY"]["LIQUIDITY_MGMT"]
|
1041
1097
|
)(self.liquidity_remove)
|
1042
1098
|
|
1099
|
+
# utils app
|
1100
|
+
self.utils_app.command("convert")(self.convert)
|
1101
|
+
self.utils_app.command("latency")(self.best_connection)
|
1102
|
+
|
1043
1103
|
def generate_command_tree(self) -> Tree:
|
1044
1104
|
"""
|
1045
1105
|
Generates a rich.Tree of the commands, subcommands, and groups of this app
|
@@ -1092,6 +1152,7 @@ class CLIManager:
|
|
1092
1152
|
"Verify this is intended.",
|
1093
1153
|
)
|
1094
1154
|
if not self.subtensor:
|
1155
|
+
use_disk_cache = self.config.get("disk_cache", False)
|
1095
1156
|
if network:
|
1096
1157
|
network_ = None
|
1097
1158
|
for item in network:
|
@@ -1105,18 +1166,24 @@ class CLIManager:
|
|
1105
1166
|
if not_selected_networks:
|
1106
1167
|
console.print(
|
1107
1168
|
f"Networks not selected: "
|
1108
|
-
f"
|
1169
|
+
f"{arg__(', '.join(not_selected_networks))}"
|
1109
1170
|
)
|
1110
1171
|
|
1111
|
-
self.subtensor = SubtensorInterface(
|
1172
|
+
self.subtensor = SubtensorInterface(
|
1173
|
+
network_, use_disk_cache=use_disk_cache
|
1174
|
+
)
|
1112
1175
|
elif self.config["network"]:
|
1113
1176
|
console.print(
|
1114
1177
|
f"Using the specified network [{COLORS.G.LINKS}]{self.config['network']}"
|
1115
1178
|
f"[/{COLORS.G.LINKS}] from config"
|
1116
1179
|
)
|
1117
|
-
self.subtensor = SubtensorInterface(
|
1180
|
+
self.subtensor = SubtensorInterface(
|
1181
|
+
self.config["network"], use_disk_cache=use_disk_cache
|
1182
|
+
)
|
1118
1183
|
else:
|
1119
|
-
self.subtensor = SubtensorInterface(
|
1184
|
+
self.subtensor = SubtensorInterface(
|
1185
|
+
defaults.subtensor.network, use_disk_cache=use_disk_cache
|
1186
|
+
)
|
1120
1187
|
return self.subtensor
|
1121
1188
|
|
1122
1189
|
def _run_command(self, cmd: Coroutine, exit_early: bool = True):
|
@@ -1179,10 +1246,18 @@ class CLIManager:
|
|
1179
1246
|
"--commands", callback=commands_callback, help="Show BTCLI commands"
|
1180
1247
|
),
|
1181
1248
|
] = None,
|
1249
|
+
debug_log: Annotated[
|
1250
|
+
Optional[bool],
|
1251
|
+
typer.Option(
|
1252
|
+
"--debug",
|
1253
|
+
callback=debug_callback,
|
1254
|
+
help="Saves the debug log from the last used command",
|
1255
|
+
),
|
1256
|
+
] = None,
|
1182
1257
|
):
|
1183
1258
|
"""
|
1184
1259
|
Command line interface (CLI) for Bittensor. Uses the values in the configuration file. These values can be
|
1185
|
-
|
1260
|
+
overridden by passing them explicitly in the command line.
|
1186
1261
|
"""
|
1187
1262
|
# Load or create the config file
|
1188
1263
|
if os.path.exists(self.config_path):
|
@@ -1206,6 +1281,9 @@ class CLIManager:
|
|
1206
1281
|
if sub_key not in config[key]:
|
1207
1282
|
config[key][sub_key] = sub_value
|
1208
1283
|
updated = True
|
1284
|
+
elif isinstance(value, bool) and config[key] is None:
|
1285
|
+
config[key] = value
|
1286
|
+
updated = True
|
1209
1287
|
if updated:
|
1210
1288
|
with open(self.config_path, "w") as f:
|
1211
1289
|
safe_dump(config, f)
|
@@ -1213,6 +1291,27 @@ class CLIManager:
|
|
1213
1291
|
for k, v in config.items():
|
1214
1292
|
if k in self.config.keys():
|
1215
1293
|
self.config[k] = v
|
1294
|
+
if self.config.get("use_cache", False):
|
1295
|
+
with open(self.debug_file_path, "w+") as f:
|
1296
|
+
f.write(
|
1297
|
+
f"BTCLI {__version__}\n"
|
1298
|
+
f"Async-Substrate-Interface: {importlib.metadata.version('async-substrate-interface')}\n"
|
1299
|
+
f"Bittensor-Wallet: {importlib.metadata.version('bittensor-wallet')}\n"
|
1300
|
+
f"Command: {' '.join(sys.argv)}\n"
|
1301
|
+
f"Config: {self.config}\n"
|
1302
|
+
f"Python: {sys.version}\n"
|
1303
|
+
f"System: {sys.platform}\n\n"
|
1304
|
+
)
|
1305
|
+
asi_logger = logging.getLogger("async_substrate_interface")
|
1306
|
+
asi_logger.setLevel(logging.DEBUG)
|
1307
|
+
logger.setLevel(logging.DEBUG)
|
1308
|
+
formatter = logging.Formatter(
|
1309
|
+
"%(asctime)s - %(levelname)s - %(name)s - %(module)s:%(lineno)d - %(message)s"
|
1310
|
+
)
|
1311
|
+
handler = logging.FileHandler(self.debug_file_path)
|
1312
|
+
handler.setFormatter(formatter)
|
1313
|
+
asi_logger.addHandler(handler)
|
1314
|
+
logger.addHandler(handler)
|
1216
1315
|
|
1217
1316
|
def verbosity_handler(
|
1218
1317
|
self, quiet: bool, verbose: bool, json_output: bool = False
|
@@ -1273,6 +1372,13 @@ class CLIManager:
|
|
1273
1372
|
help="Disable caching of some commands. This will disable the `--reuse-last` and `--html` flags on "
|
1274
1373
|
"commands such as `subnets metagraph`, `stake show` and `subnets list`.",
|
1275
1374
|
),
|
1375
|
+
disk_cache: Optional[bool] = typer.Option(
|
1376
|
+
None,
|
1377
|
+
"--disk-cache/--no-disk-cache",
|
1378
|
+
" /--no-disk-cache",
|
1379
|
+
help="Enables or disables the caching on disk. Enabling this can significantly speed up commands run "
|
1380
|
+
"sequentially",
|
1381
|
+
),
|
1276
1382
|
rate_tolerance: Optional[float] = typer.Option(
|
1277
1383
|
None,
|
1278
1384
|
"--tolerance",
|
@@ -1319,12 +1425,13 @@ class CLIManager:
|
|
1319
1425
|
"wallet_hotkey": wallet_hotkey,
|
1320
1426
|
"network": network,
|
1321
1427
|
"use_cache": use_cache,
|
1428
|
+
"disk_cache": disk_cache,
|
1322
1429
|
"rate_tolerance": rate_tolerance,
|
1323
1430
|
"safe_staking": safe_staking,
|
1324
1431
|
"allow_partial_stake": allow_partial_stake,
|
1325
1432
|
"dashboard_path": dashboard_path,
|
1326
1433
|
}
|
1327
|
-
bools = ["use_cache", "safe_staking", "allow_partial_stake"]
|
1434
|
+
bools = ["use_cache", "disk_cache", "safe_staking", "allow_partial_stake"]
|
1328
1435
|
if all(v is None for v in args.values()):
|
1329
1436
|
# Print existing configs
|
1330
1437
|
self.get_config()
|
@@ -1373,8 +1480,7 @@ class CLIManager:
|
|
1373
1480
|
if n := args.get("network"):
|
1374
1481
|
if n in Constants.networks:
|
1375
1482
|
if not Confirm.ask(
|
1376
|
-
f"You provided a network
|
1377
|
-
f"[{COLORS.G.ARG}]{Constants.network_map[n]}[/{COLORS.G.ARG}]\n"
|
1483
|
+
f"You provided a network {arg__(n)} which is mapped to {arg__(Constants.network_map[n])}\n"
|
1378
1484
|
"Do you want to continue?"
|
1379
1485
|
):
|
1380
1486
|
typer.Exit()
|
@@ -1389,14 +1495,13 @@ class CLIManager:
|
|
1389
1495
|
)
|
1390
1496
|
args["network"] = known_network
|
1391
1497
|
if not Confirm.ask(
|
1392
|
-
f"You provided an endpoint
|
1393
|
-
f"[{COLORS.G.ARG}]{known_network}[/{COLORS.G.ARG}]\n"
|
1498
|
+
f"You provided an endpoint {arg__(n)} which is mapped to {arg__(known_network)}\n"
|
1394
1499
|
"Do you want to continue?"
|
1395
1500
|
):
|
1396
1501
|
raise typer.Exit()
|
1397
1502
|
else:
|
1398
1503
|
if not Confirm.ask(
|
1399
|
-
f"You provided a chain endpoint URL
|
1504
|
+
f"You provided a chain endpoint URL {arg__(n)}\n"
|
1400
1505
|
"Do you want to continue?"
|
1401
1506
|
):
|
1402
1507
|
raise typer.Exit()
|
@@ -1406,6 +1511,7 @@ class CLIManager:
|
|
1406
1511
|
|
1407
1512
|
for arg, val in args.items():
|
1408
1513
|
if val is not None:
|
1514
|
+
logger.debug(f"Config: setting {arg} to {val}")
|
1409
1515
|
self.config[arg] = val
|
1410
1516
|
with open(self.config_path, "w") as f:
|
1411
1517
|
safe_dump(self.config, f)
|
@@ -1470,17 +1576,12 @@ class CLIManager:
|
|
1470
1576
|
if not any(args.values()):
|
1471
1577
|
for arg in args.keys():
|
1472
1578
|
if self.config.get(arg) is not None:
|
1473
|
-
if Confirm.ask(
|
1474
|
-
f"
|
1475
|
-
):
|
1579
|
+
if Confirm.ask(f"Do you want to clear the {arg__(arg)} config?"):
|
1580
|
+
logger.debug(f"Config: clearing {arg}.")
|
1476
1581
|
self.config[arg] = None
|
1477
|
-
console.print(
|
1478
|
-
f"Cleared [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config and set to 'None'."
|
1479
|
-
)
|
1582
|
+
console.print(f"Cleared {arg__(arg)} config and set to 'None'.")
|
1480
1583
|
else:
|
1481
|
-
console.print(
|
1482
|
-
f"Skipped clearing [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config."
|
1483
|
-
)
|
1584
|
+
console.print(f"Skipped clearing {arg__(arg)} config.")
|
1484
1585
|
|
1485
1586
|
else:
|
1486
1587
|
# Check each specified argument
|
@@ -1488,21 +1589,19 @@ class CLIManager:
|
|
1488
1589
|
if should_clear:
|
1489
1590
|
if self.config.get(arg) is not None:
|
1490
1591
|
if Confirm.ask(
|
1491
|
-
f"Do you want to clear the
|
1592
|
+
f"Do you want to clear the {arg__(arg)}"
|
1492
1593
|
f" [bold cyan]({self.config.get(arg)})[/bold cyan] config?"
|
1493
1594
|
):
|
1494
1595
|
self.config[arg] = None
|
1596
|
+
logger.debug(f"Config: clearing {arg}.")
|
1495
1597
|
console.print(
|
1496
|
-
f"Cleared
|
1598
|
+
f"Cleared {arg__(arg)} config and set to 'None'."
|
1497
1599
|
)
|
1498
1600
|
else:
|
1499
|
-
console.print(
|
1500
|
-
f"Skipped clearing [{COLORS.G.ARG}]{arg}[/{COLORS.G.ARG}] config."
|
1501
|
-
)
|
1601
|
+
console.print(f"Skipped clearing {arg__(arg)} config.")
|
1502
1602
|
else:
|
1503
1603
|
console.print(
|
1504
|
-
f"No config set for
|
1505
|
-
f" Use [{COLORS.G.ARG}]`btcli config set`[/{COLORS.G.ARG}] to set it."
|
1604
|
+
f"No config set for {arg__(arg)}. Use {arg__('btcli config set')} to set it."
|
1506
1605
|
)
|
1507
1606
|
with open(self.config_path, "w") as f:
|
1508
1607
|
safe_dump(self.config, f)
|
@@ -1518,8 +1617,7 @@ class CLIManager:
|
|
1518
1617
|
Column("[bold white]Value", style="gold1"),
|
1519
1618
|
Column("", style="medium_purple"),
|
1520
1619
|
box=box.SIMPLE_HEAD,
|
1521
|
-
title=f"[{COLORS.G.HEADER}]BTCLI Config[/{COLORS.G.HEADER}]: "
|
1522
|
-
f"[{COLORS.G.ARG}]{self.config_path}[/{COLORS.G.ARG}]",
|
1620
|
+
title=f"[{COLORS.G.HEADER}]BTCLI Config[/{COLORS.G.HEADER}]: {arg__(self.config_path)}",
|
1523
1621
|
)
|
1524
1622
|
|
1525
1623
|
for key, value in self.config.items():
|
@@ -1593,26 +1691,31 @@ class CLIManager:
|
|
1593
1691
|
bool: Safe staking setting
|
1594
1692
|
"""
|
1595
1693
|
if safe_staking is not None:
|
1694
|
+
enabled = "enabled" if safe_staking else "disabled"
|
1596
1695
|
console.print(
|
1597
|
-
f"[dim][blue]Safe staking[/blue]: [bold cyan]{
|
1696
|
+
f"[dim][blue]Safe staking[/blue]: [bold cyan]{enabled}[/bold cyan]."
|
1598
1697
|
)
|
1698
|
+
logger.debug(f"Safe staking {enabled}")
|
1599
1699
|
return safe_staking
|
1600
1700
|
elif self.config.get("safe_staking") is not None:
|
1601
1701
|
safe_staking = self.config["safe_staking"]
|
1702
|
+
enabled = "enabled" if safe_staking else "disabled"
|
1602
1703
|
console.print(
|
1603
|
-
f"[dim][blue]Safe staking[/blue]: [bold cyan]{
|
1704
|
+
f"[dim][blue]Safe staking[/blue]: [bold cyan]{enabled}[/bold cyan] (from config)."
|
1604
1705
|
)
|
1706
|
+
logger.debug(f"Safe staking {enabled}")
|
1605
1707
|
return safe_staking
|
1606
1708
|
else:
|
1607
1709
|
safe_staking = True
|
1608
1710
|
console.print(
|
1609
1711
|
"[dim][blue]Safe staking[/blue]: "
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1614
|
-
|
1712
|
+
f"[bold cyan]enabled[/bold cyan] "
|
1713
|
+
"by default. Set this using "
|
1714
|
+
"[dark_sea_green3 italic]`btcli config set`[/dark_sea_green3 italic] "
|
1715
|
+
"or "
|
1716
|
+
"[dark_sea_green3 italic]`--safe/--unsafe`[/dark_sea_green3 italic] flag[/dim]"
|
1615
1717
|
)
|
1718
|
+
logger.debug(f"Safe staking enabled.")
|
1616
1719
|
return safe_staking
|
1617
1720
|
|
1618
1721
|
def ask_partial_stake(
|
@@ -1629,25 +1732,31 @@ class CLIManager:
|
|
1629
1732
|
bool: Partial stake setting
|
1630
1733
|
"""
|
1631
1734
|
if allow_partial_stake is not None:
|
1735
|
+
partial_staking = "enabled" if allow_partial_stake else "disabled"
|
1632
1736
|
console.print(
|
1633
|
-
f"[dim][blue]Partial staking[/blue]: [bold cyan]{
|
1737
|
+
f"[dim][blue]Partial staking[/blue]: [bold cyan]{partial_staking}[/bold cyan]."
|
1634
1738
|
)
|
1739
|
+
logger.debug(f"Partial staking {partial_staking}")
|
1635
1740
|
return allow_partial_stake
|
1636
1741
|
elif self.config.get("allow_partial_stake") is not None:
|
1637
1742
|
config_partial = self.config["allow_partial_stake"]
|
1743
|
+
partial_staking = "enabled" if allow_partial_stake else "disabled"
|
1638
1744
|
console.print(
|
1639
|
-
f"[dim][blue]Partial staking[/blue]: [bold cyan]{
|
1745
|
+
f"[dim][blue]Partial staking[/blue]: [bold cyan]{partial_staking}[/bold cyan] (from config)."
|
1640
1746
|
)
|
1747
|
+
logger.debug(f"Partial staking {partial_staking}")
|
1641
1748
|
return config_partial
|
1642
1749
|
else:
|
1750
|
+
partial_staking = "enabled" if allow_partial_stake else "disabled"
|
1643
1751
|
console.print(
|
1644
1752
|
"[dim][blue]Partial staking[/blue]: "
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1753
|
+
f"[bold cyan]{partial_staking}[/bold cyan] "
|
1754
|
+
"by default. Set this using "
|
1755
|
+
"[dark_sea_green3 italic]`btcli config set`[/dark_sea_green3 italic] "
|
1756
|
+
"or "
|
1757
|
+
"[dark_sea_green3 italic]`--partial/--no-partial`[/dark_sea_green3 italic] flag[/dim]"
|
1650
1758
|
)
|
1759
|
+
logger.debug(f"Partial staking {partial_staking}")
|
1651
1760
|
return False
|
1652
1761
|
|
1653
1762
|
def wallet_ask(
|
@@ -1655,7 +1764,7 @@ class CLIManager:
|
|
1655
1764
|
wallet_name: Optional[str],
|
1656
1765
|
wallet_path: Optional[str],
|
1657
1766
|
wallet_hotkey: Optional[str],
|
1658
|
-
ask_for: Optional[list[
|
1767
|
+
ask_for: Optional[list[Literal[WO.NAME, WO.PATH, WO.HOTKEY]]] = None,
|
1659
1768
|
validate: WV = WV.WALLET,
|
1660
1769
|
return_wallet_and_hotkey: bool = False,
|
1661
1770
|
) -> Union[Wallet, tuple[Wallet, str]]:
|
@@ -1720,13 +1829,14 @@ class CLIManager:
|
|
1720
1829
|
if wallet_path:
|
1721
1830
|
wallet_path = os.path.expanduser(wallet_path)
|
1722
1831
|
wallet = Wallet(name=wallet_name, path=wallet_path, hotkey=wallet_hotkey)
|
1832
|
+
logger.debug(f"Using wallet {wallet}")
|
1723
1833
|
|
1724
1834
|
# Validate the wallet if required
|
1725
1835
|
if validate == WV.WALLET or validate == WV.WALLET_AND_HOTKEY:
|
1726
1836
|
valid = utils.is_valid_wallet(wallet)
|
1727
1837
|
if not valid[0]:
|
1728
1838
|
utils.err_console.print(
|
1729
|
-
f"[red]Error: Wallet does not
|
1839
|
+
f"[red]Error: Wallet does not exist. \n"
|
1730
1840
|
f"Please verify your wallet information: {wallet}[/red]"
|
1731
1841
|
)
|
1732
1842
|
raise typer.Exit()
|
@@ -1875,6 +1985,15 @@ class CLIManager:
|
|
1875
1985
|
str,
|
1876
1986
|
"Hotkeys names must be a comma-separated list, e.g., `--exclude-hotkeys hk1,hk2`.",
|
1877
1987
|
)
|
1988
|
+
logger.debug(
|
1989
|
+
"args:\n"
|
1990
|
+
f"all_wallets: {all_wallets}\n"
|
1991
|
+
f"sort_by: {sort_by}\n"
|
1992
|
+
f"sort_order: {sort_order}\n"
|
1993
|
+
f"include_hotkeys: {include_hotkeys}\n"
|
1994
|
+
f"exclude_hotkeys: {exclude_hotkeys}\n"
|
1995
|
+
f"netuids: {netuids}\n"
|
1996
|
+
)
|
1878
1997
|
|
1879
1998
|
return self._run_command(
|
1880
1999
|
wallets.overview(
|
@@ -1964,6 +2083,15 @@ class CLIManager:
|
|
1964
2083
|
amount = 0
|
1965
2084
|
elif not amount:
|
1966
2085
|
amount = FloatPrompt.ask("Enter amount (in TAO) to transfer.")
|
2086
|
+
logger.debug(
|
2087
|
+
"args:\n"
|
2088
|
+
f"destination: {destination_ss58_address}\n"
|
2089
|
+
f"amount: {amount}\n"
|
2090
|
+
f"transfer_all: {transfer_all}\n"
|
2091
|
+
f"allow_death: {allow_death}\n"
|
2092
|
+
f"period: {period}\n"
|
2093
|
+
f"prompt: {prompt}\n"
|
2094
|
+
)
|
1967
2095
|
return self._run_command(
|
1968
2096
|
wallets.transfer(
|
1969
2097
|
wallet=wallet,
|
@@ -2033,6 +2161,13 @@ class CLIManager:
|
|
2033
2161
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
2034
2162
|
validate=WV.WALLET_AND_HOTKEY,
|
2035
2163
|
)
|
2164
|
+
logger.debug(
|
2165
|
+
"args:\n"
|
2166
|
+
f"original_wallet: {original_wallet}\n"
|
2167
|
+
f"new_wallet: {new_wallet}\n"
|
2168
|
+
f"netuid: {netuid}\n"
|
2169
|
+
f"prompt: {prompt}\n"
|
2170
|
+
)
|
2036
2171
|
self.initialize_chain(network)
|
2037
2172
|
return self._run_command(
|
2038
2173
|
wallets.swap_hotkey(
|
@@ -2196,6 +2331,17 @@ class CLIManager:
|
|
2196
2331
|
ask_for=[WO.NAME, WO.PATH],
|
2197
2332
|
validate=WV.WALLET,
|
2198
2333
|
)
|
2334
|
+
logger.debug(
|
2335
|
+
"args:\n"
|
2336
|
+
f"network {network}\n"
|
2337
|
+
f"threads_per_block {threads_per_block}\n"
|
2338
|
+
f"update_interval {update_interval}\n"
|
2339
|
+
f"processors {processors}\n"
|
2340
|
+
f"use_cuda {use_cuda}\n"
|
2341
|
+
f"dev_id {dev_id}\n"
|
2342
|
+
f"output_in_place {output_in_place}\n"
|
2343
|
+
f"max_successes {max_successes}\n"
|
2344
|
+
)
|
2199
2345
|
return self._run_command(
|
2200
2346
|
wallets.faucet(
|
2201
2347
|
wallet,
|
@@ -2263,6 +2409,7 @@ class CLIManager:
|
|
2263
2409
|
mnemonic, seed, json_path, json_password = get_creation_data(
|
2264
2410
|
mnemonic, seed, json_path, json_password
|
2265
2411
|
)
|
2412
|
+
# logger.debug should NOT be used here, it's simply too risky
|
2266
2413
|
return self._run_command(
|
2267
2414
|
wallets.regen_coldkey(
|
2268
2415
|
wallet,
|
@@ -2332,6 +2479,7 @@ class CLIManager:
|
|
2332
2479
|
):
|
2333
2480
|
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
|
2334
2481
|
return
|
2482
|
+
# do not logger.debug any creation cmds
|
2335
2483
|
return self._run_command(
|
2336
2484
|
wallets.regen_coldkey_pub(
|
2337
2485
|
wallet, ss58_address, public_key_hex, overwrite, json_output
|
@@ -2384,6 +2532,7 @@ class CLIManager:
|
|
2384
2532
|
mnemonic, seed, json_path, json_password = get_creation_data(
|
2385
2533
|
mnemonic, seed, json_path, json_password
|
2386
2534
|
)
|
2535
|
+
# do not logger.debug any creation cmds
|
2387
2536
|
return self._run_command(
|
2388
2537
|
wallets.regen_hotkey(
|
2389
2538
|
wallet,
|
@@ -2453,6 +2602,7 @@ class CLIManager:
|
|
2453
2602
|
):
|
2454
2603
|
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
|
2455
2604
|
return False
|
2605
|
+
# do not logger.debug any creation cmds
|
2456
2606
|
return self._run_command(
|
2457
2607
|
wallets.regen_hotkey_pub(
|
2458
2608
|
wallet, ss58_address, public_key_hex, overwrite, json_output
|
@@ -2517,6 +2667,7 @@ class CLIManager:
|
|
2517
2667
|
)
|
2518
2668
|
if not uri:
|
2519
2669
|
n_words = get_n_words(n_words)
|
2670
|
+
# do not logger.debug any creation cmds
|
2520
2671
|
return self._run_command(
|
2521
2672
|
wallets.new_hotkey(
|
2522
2673
|
wallet, n_words, use_password, uri, overwrite, json_output
|
@@ -2583,7 +2734,13 @@ class CLIManager:
|
|
2583
2734
|
f"hotkey [blue]{wallet_hotkey}[/blue] "
|
2584
2735
|
f"[{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
|
2585
2736
|
)
|
2586
|
-
|
2737
|
+
logger.debug(
|
2738
|
+
"args:\n"
|
2739
|
+
f"network {network}\n"
|
2740
|
+
f"hotkey_ss58 {hotkey_ss58}\n"
|
2741
|
+
f"hotkey_display {hotkey_display}\n"
|
2742
|
+
f"prompt {prompt}\n"
|
2743
|
+
)
|
2587
2744
|
return self._run_command(
|
2588
2745
|
wallets.associate_hotkey(
|
2589
2746
|
wallet,
|
@@ -2731,7 +2888,8 @@ class CLIManager:
|
|
2731
2888
|
|
2732
2889
|
if not scheduled_block:
|
2733
2890
|
block_input = Prompt.ask(
|
2734
|
-
"[blue]Enter the block number[/blue] where the swap was scheduled
|
2891
|
+
"[blue]Enter the block number[/blue] where the swap was scheduled "
|
2892
|
+
"[dim](optional, press enter to skip)[/dim]",
|
2735
2893
|
default="",
|
2736
2894
|
)
|
2737
2895
|
if block_input:
|
@@ -2740,7 +2898,12 @@ class CLIManager:
|
|
2740
2898
|
except ValueError:
|
2741
2899
|
print_error("Invalid block number")
|
2742
2900
|
raise typer.Exit()
|
2743
|
-
|
2901
|
+
logger.debug(
|
2902
|
+
"args:\n"
|
2903
|
+
f"scheduled_block {scheduled_block}\n"
|
2904
|
+
f"ss58_address {ss58_address}\n"
|
2905
|
+
f"network {network}\n"
|
2906
|
+
)
|
2744
2907
|
return self._run_command(
|
2745
2908
|
wallets.check_swap_status(self.subtensor, ss58_address, scheduled_block)
|
2746
2909
|
)
|
@@ -2797,6 +2960,7 @@ class CLIManager:
|
|
2797
2960
|
)
|
2798
2961
|
if not uri:
|
2799
2962
|
n_words = get_n_words(n_words)
|
2963
|
+
# do not logger.debug any creation commands
|
2800
2964
|
return self._run_command(
|
2801
2965
|
wallets.wallet_create(
|
2802
2966
|
wallet, n_words, use_password, uri, overwrite, json_output
|
@@ -2905,6 +3069,12 @@ class CLIManager:
|
|
2905
3069
|
ask_for=ask_for,
|
2906
3070
|
validate=validate,
|
2907
3071
|
)
|
3072
|
+
logger.debug(
|
3073
|
+
"args:\n"
|
3074
|
+
f"all_balances {all_balances}\n"
|
3075
|
+
f"ss58_addresses {ss58_addresses}\n"
|
3076
|
+
f"network {network}"
|
3077
|
+
)
|
2908
3078
|
subtensor = self.initialize_chain(network)
|
2909
3079
|
return self._run_command(
|
2910
3080
|
wallets.wallet_balance(
|
@@ -3055,6 +3225,7 @@ class CLIManager:
|
|
3055
3225
|
additional,
|
3056
3226
|
github_repo,
|
3057
3227
|
)
|
3228
|
+
logger.debug(f"args:\nidentity {identity}\nnetwork {network}\n")
|
3058
3229
|
|
3059
3230
|
return self._run_command(
|
3060
3231
|
wallets.set_id(
|
@@ -3316,7 +3487,12 @@ class CLIManager:
|
|
3316
3487
|
f"[dark_sea_green3]{new_wallet}[/dark_sea_green3]\n"
|
3317
3488
|
)
|
3318
3489
|
new_wallet_coldkey_ss58 = new_wallet.coldkeypub.ss58_address
|
3319
|
-
|
3490
|
+
logger.debug(
|
3491
|
+
"args:\n"
|
3492
|
+
f"network {network}\n"
|
3493
|
+
f"new_coldkey_ss58 {new_wallet_coldkey_ss58}\n"
|
3494
|
+
f"force_swap {force_swap}"
|
3495
|
+
)
|
3320
3496
|
return self._run_command(
|
3321
3497
|
wallets.schedule_coldkey_swap(
|
3322
3498
|
wallet=wallet,
|
@@ -3388,7 +3564,13 @@ class CLIManager:
|
|
3388
3564
|
wallet = self.wallet_ask(
|
3389
3565
|
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
|
3390
3566
|
)
|
3391
|
-
|
3567
|
+
logger.debug(
|
3568
|
+
"args:\n"
|
3569
|
+
f"coldkey_ss58 {coldkey_ss58}\n"
|
3570
|
+
f"network {network}\n"
|
3571
|
+
f"live: {live}\n"
|
3572
|
+
f"no_prompt: {no_prompt}\n"
|
3573
|
+
)
|
3392
3574
|
return self._run_command(
|
3393
3575
|
list_stake.stake_list(
|
3394
3576
|
wallet,
|
@@ -3637,6 +3819,7 @@ class CLIManager:
|
|
3637
3819
|
),
|
3638
3820
|
exit_early=False,
|
3639
3821
|
)
|
3822
|
+
logger.debug(f"Free balance: {free_balance}")
|
3640
3823
|
if free_balance == Balance.from_tao(0):
|
3641
3824
|
print_error("You dont have any balance to stake.")
|
3642
3825
|
return
|
@@ -3657,7 +3840,21 @@ class CLIManager:
|
|
3657
3840
|
f"You dont have enough balance to stake. Current free Balance: {free_balance}."
|
3658
3841
|
)
|
3659
3842
|
raise typer.Exit()
|
3660
|
-
|
3843
|
+
logger.debug(
|
3844
|
+
"args:\n"
|
3845
|
+
f"network: {network}\n"
|
3846
|
+
f"netuids: {netuids}\n"
|
3847
|
+
f"stake_all: {stake_all}\n"
|
3848
|
+
f"amount: {amount}\n"
|
3849
|
+
f"prompt: {prompt}\n"
|
3850
|
+
f"all_hotkeys: {all_hotkeys}\n"
|
3851
|
+
f"include_hotkeys: {include_hotkeys}\n"
|
3852
|
+
f"exclude_hotkeys: {exclude_hotkeys}\n"
|
3853
|
+
f"safe_staking: {safe_staking}\n"
|
3854
|
+
f"rate_tolerance: {rate_tolerance}\n"
|
3855
|
+
f"allow_partial_stake: {allow_partial_stake}\n"
|
3856
|
+
f"period: {period}\n"
|
3857
|
+
)
|
3661
3858
|
return self._run_command(
|
3662
3859
|
add_stake.stake_add(
|
3663
3860
|
wallet,
|
@@ -3782,11 +3979,11 @@ class CLIManager:
|
|
3782
3979
|
"Interactive mode cannot be used with hotkey selection options like "
|
3783
3980
|
"--include-hotkeys, --exclude-hotkeys, --all-hotkeys, or --hotkey."
|
3784
3981
|
)
|
3785
|
-
|
3982
|
+
return False
|
3786
3983
|
|
3787
3984
|
if unstake_all and unstake_all_alpha:
|
3788
3985
|
print_error("Cannot specify both unstake-all and unstake-all-alpha.")
|
3789
|
-
|
3986
|
+
return False
|
3790
3987
|
|
3791
3988
|
if not interactive and not unstake_all and not unstake_all_alpha:
|
3792
3989
|
netuid = get_optional_netuid(netuid, all_netuids)
|
@@ -3795,23 +3992,39 @@ class CLIManager:
|
|
3795
3992
|
"You have specified hotkeys to include and also the `--all-hotkeys` flag. The flag"
|
3796
3993
|
" should only be used standalone (to use all hotkeys) or with `--exclude-hotkeys`."
|
3797
3994
|
)
|
3798
|
-
|
3995
|
+
return False
|
3799
3996
|
|
3800
3997
|
if include_hotkeys and exclude_hotkeys:
|
3801
3998
|
print_error(
|
3802
3999
|
"You have specified both including and excluding hotkeys options. Select one or the other."
|
3803
4000
|
)
|
3804
|
-
|
4001
|
+
return False
|
3805
4002
|
|
3806
4003
|
if unstake_all and amount:
|
3807
4004
|
print_error(
|
3808
4005
|
"Cannot specify both a specific amount and 'unstake-all'. Choose one or the other."
|
3809
4006
|
)
|
3810
|
-
|
4007
|
+
return False
|
3811
4008
|
|
3812
4009
|
if amount and amount <= 0:
|
3813
4010
|
print_error(f"You entered an incorrect unstake amount: {amount}")
|
3814
|
-
|
4011
|
+
return False
|
4012
|
+
|
4013
|
+
if include_hotkeys:
|
4014
|
+
include_hotkeys = parse_to_list(
|
4015
|
+
include_hotkeys,
|
4016
|
+
str,
|
4017
|
+
"Hotkeys must be a comma-separated list of ss58s or names, e.g., `--include-hotkeys hk1,hk2`.",
|
4018
|
+
is_ss58=False,
|
4019
|
+
)
|
4020
|
+
|
4021
|
+
if exclude_hotkeys:
|
4022
|
+
exclude_hotkeys = parse_to_list(
|
4023
|
+
exclude_hotkeys,
|
4024
|
+
str,
|
4025
|
+
"Hotkeys must be a comma-separated list of ss58s or names, e.g., `--exclude-hotkeys hk3,hk4`.",
|
4026
|
+
is_ss58=False,
|
4027
|
+
)
|
3815
4028
|
|
3816
4029
|
if (
|
3817
4030
|
not wallet_hotkey
|
@@ -3828,7 +4041,8 @@ class CLIManager:
|
|
3828
4041
|
default=self.config.get("wallet_name") or defaults.wallet.name,
|
3829
4042
|
)
|
3830
4043
|
hotkey_or_ss58 = Prompt.ask(
|
3831
|
-
"Enter the [blue]hotkey[/blue] name or [blue]ss58 address[/blue] to unstake from [dim]
|
4044
|
+
"Enter the [blue]hotkey[/blue] name or [blue]ss58 address[/blue] to unstake from [dim]"
|
4045
|
+
"(or Press Enter to view existing staked hotkeys)[/dim]",
|
3832
4046
|
)
|
3833
4047
|
if hotkey_or_ss58 == "":
|
3834
4048
|
wallet = self.wallet_ask(
|
@@ -3859,12 +4073,12 @@ class CLIManager:
|
|
3859
4073
|
if include_hotkeys:
|
3860
4074
|
if len(include_hotkeys) > 1:
|
3861
4075
|
print_error("Cannot unstake_all from multiple hotkeys at once.")
|
3862
|
-
|
4076
|
+
return False
|
3863
4077
|
elif is_valid_ss58_address(include_hotkeys[0]):
|
3864
4078
|
hotkey_ss58_address = include_hotkeys[0]
|
3865
4079
|
else:
|
3866
4080
|
print_error("Invalid hotkey ss58 address.")
|
3867
|
-
|
4081
|
+
return False
|
3868
4082
|
elif all_hotkeys:
|
3869
4083
|
wallet = self.wallet_ask(
|
3870
4084
|
wallet_name,
|
@@ -3875,7 +4089,8 @@ class CLIManager:
|
|
3875
4089
|
else:
|
3876
4090
|
if not hotkey_ss58_address and not wallet_hotkey:
|
3877
4091
|
hotkey_or_ss58 = Prompt.ask(
|
3878
|
-
"Enter the [blue]hotkey[/blue] name or [blue]ss58 address[/blue] to unstake all from [dim]
|
4092
|
+
"Enter the [blue]hotkey[/blue] name or [blue]ss58 address[/blue] to unstake all from [dim]"
|
4093
|
+
"(or enter 'all' to unstake from all hotkeys)[/dim]",
|
3879
4094
|
default=self.config.get("wallet_hotkey")
|
3880
4095
|
or defaults.wallet.hotkey,
|
3881
4096
|
)
|
@@ -3907,6 +4122,17 @@ class CLIManager:
|
|
3907
4122
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
3908
4123
|
validate=WV.WALLET_AND_HOTKEY,
|
3909
4124
|
)
|
4125
|
+
logger.debug(
|
4126
|
+
"args:\n"
|
4127
|
+
f"network: {network}\n"
|
4128
|
+
f"hotkey_ss58_address: {hotkey_ss58_address}\n"
|
4129
|
+
f"unstake_all: {unstake_all}\n"
|
4130
|
+
f"unstake_all_alpha: {unstake_all_alpha}\n"
|
4131
|
+
f"all_hotkeys: {all_hotkeys}\n"
|
4132
|
+
f"include_hotkeys: {include_hotkeys}\n"
|
4133
|
+
f"exclude_hotkeys: {exclude_hotkeys}\n"
|
4134
|
+
f"era: {period}"
|
4135
|
+
)
|
3910
4136
|
return self._run_command(
|
3911
4137
|
remove_stake.unstake_all(
|
3912
4138
|
wallet=wallet,
|
@@ -3941,22 +4167,38 @@ class CLIManager:
|
|
3941
4167
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
3942
4168
|
validate=WV.WALLET_AND_HOTKEY,
|
3943
4169
|
)
|
3944
|
-
|
3945
|
-
|
3946
|
-
|
3947
|
-
|
3948
|
-
str,
|
3949
|
-
"Hotkeys must be a comma-separated list of ss58s or names, e.g., `--include-hotkeys hk1,hk2`.",
|
3950
|
-
is_ss58=False,
|
4170
|
+
if not amount and not prompt:
|
4171
|
+
print_error(
|
4172
|
+
f"Ambiguous request! Specify {arg__('--amount')}, {arg__('--all')}, or {arg__('--all-alpha')} "
|
4173
|
+
f"to use {arg__('--no-prompt')}"
|
3951
4174
|
)
|
4175
|
+
return False
|
3952
4176
|
|
3953
|
-
if
|
3954
|
-
|
3955
|
-
|
3956
|
-
|
3957
|
-
|
3958
|
-
|
4177
|
+
if not amount and json_output:
|
4178
|
+
json_console.print_json(
|
4179
|
+
data={
|
4180
|
+
"success": False,
|
4181
|
+
"err_msg": "Ambiguous request! Specify '--amount', '--all', "
|
4182
|
+
"or '--all-alpha' to use '--json-output'",
|
4183
|
+
}
|
3959
4184
|
)
|
4185
|
+
return False
|
4186
|
+
logger.debug(
|
4187
|
+
"args:\n"
|
4188
|
+
f"network: {network}\n"
|
4189
|
+
f"hotkey_ss58_address: {hotkey_ss58_address}\n"
|
4190
|
+
f"all_hotkeys: {all_hotkeys}\n"
|
4191
|
+
f"include_hotkeys: {include_hotkeys}\n"
|
4192
|
+
f"exclude_hotkeys: {exclude_hotkeys}\n"
|
4193
|
+
f"amount: {amount}\n"
|
4194
|
+
f"prompt: {prompt}\n"
|
4195
|
+
f"interactive: {interactive}\n"
|
4196
|
+
f"netuid: {netuid}\n"
|
4197
|
+
f"safe_staking: {safe_staking}\n"
|
4198
|
+
f"rate_tolerance: {rate_tolerance}\n"
|
4199
|
+
f"allow_partial_stake: {allow_partial_stake}\n"
|
4200
|
+
f"era: {period}"
|
4201
|
+
)
|
3960
4202
|
|
3961
4203
|
return self._run_command(
|
3962
4204
|
remove_stake.unstake(
|
@@ -4121,7 +4363,19 @@ class CLIManager:
|
|
4121
4363
|
destination_netuid = IntPrompt.ask(
|
4122
4364
|
"Enter the [blue]destination subnet[/blue] (netuid) to move stake to"
|
4123
4365
|
)
|
4124
|
-
|
4366
|
+
logger.debug(
|
4367
|
+
"args:\n"
|
4368
|
+
f"network: {network}\n"
|
4369
|
+
f"origin_netuid: {origin_netuid}\n"
|
4370
|
+
f"origin_hotkey: {origin_hotkey}\n"
|
4371
|
+
f"destination_hotkey: {destination_hotkey}\n"
|
4372
|
+
f"destination_netuid: {destination_netuid}\n"
|
4373
|
+
f"amount: {amount}\n"
|
4374
|
+
f"stake_all: {stake_all}\n"
|
4375
|
+
f"era: {period}\n"
|
4376
|
+
f"interactive_selection: {interactive_selection}\n"
|
4377
|
+
f"prompt: {prompt}\n"
|
4378
|
+
)
|
4125
4379
|
result = self._run_command(
|
4126
4380
|
move_stake.move_stake(
|
4127
4381
|
subtensor=self.initialize_chain(network),
|
@@ -4286,7 +4540,18 @@ class CLIManager:
|
|
4286
4540
|
dest_netuid = IntPrompt.ask(
|
4287
4541
|
"Enter the [blue]destination subnet[/blue] (netuid)"
|
4288
4542
|
)
|
4289
|
-
|
4543
|
+
logger.debug(
|
4544
|
+
"args:\n"
|
4545
|
+
f"network: {network}\n"
|
4546
|
+
f"origin_hotkey: {origin_hotkey}\n"
|
4547
|
+
f"origin_netuid: {origin_netuid}\n"
|
4548
|
+
f"dest_netuid: {dest_netuid}\n"
|
4549
|
+
f"dest_hotkey: {origin_hotkey}\n"
|
4550
|
+
f"dest_coldkey_ss58: {dest_ss58}\n"
|
4551
|
+
f"amount: {amount}\n"
|
4552
|
+
f"era: {period}\n"
|
4553
|
+
f"stake_all: {stake_all}"
|
4554
|
+
)
|
4290
4555
|
result = self._run_command(
|
4291
4556
|
move_stake.transfer_stake(
|
4292
4557
|
wallet=wallet,
|
@@ -4394,7 +4659,19 @@ class CLIManager:
|
|
4394
4659
|
)
|
4395
4660
|
if not amount and not swap_all:
|
4396
4661
|
amount = FloatPrompt.ask("Enter the [blue]amount[/blue] to swap")
|
4397
|
-
|
4662
|
+
logger.debug(
|
4663
|
+
"args:\n"
|
4664
|
+
f"network: {network}\n"
|
4665
|
+
f"origin_netuid: {origin_netuid}\n"
|
4666
|
+
f"dest_netuid: {dest_netuid}\n"
|
4667
|
+
f"amount: {amount}\n"
|
4668
|
+
f"swap_all: {swap_all}\n"
|
4669
|
+
f"era: {period}\n"
|
4670
|
+
f"interactive_selection: {interactive_selection}\n"
|
4671
|
+
f"prompt: {prompt}\n"
|
4672
|
+
f"wait_for_inclusion: {wait_for_inclusion}\n"
|
4673
|
+
f"wait_for_finalization: {wait_for_finalization}\n"
|
4674
|
+
)
|
4398
4675
|
result = self._run_command(
|
4399
4676
|
move_stake.swap_stake(
|
4400
4677
|
wallet=wallet,
|
@@ -4510,7 +4787,7 @@ class CLIManager:
|
|
4510
4787
|
|
4511
4788
|
EXAMPLE
|
4512
4789
|
|
4513
|
-
[green]$[/green] btcli stake child set -c 5FCL3gmjtQV4xxxxuEPEFQVhyyyyqYgNwX7drFLw7MSdBnxP -c 5Hp5dxxxxtGg7pu8dN2btyyyyVA1vELmM9dy8KQv3LxV8PA7 --hotkey default --netuid 1
|
4790
|
+
[green]$[/green] btcli stake child set -c 5FCL3gmjtQV4xxxxuEPEFQVhyyyyqYgNwX7drFLw7MSdBnxP -c 5Hp5dxxxxtGg7pu8dN2btyyyyVA1vELmM9dy8KQv3LxV8PA7 --hotkey default --netuid 1 --prop 0.3 --prop 0.7
|
4514
4791
|
"""
|
4515
4792
|
self.verbosity_handler(quiet, verbose, json_output)
|
4516
4793
|
netuid = get_optional_netuid(netuid, all_netuids)
|
@@ -4543,6 +4820,15 @@ class CLIManager:
|
|
4543
4820
|
ask_for=[WO.NAME, WO.HOTKEY],
|
4544
4821
|
validate=WV.WALLET_AND_HOTKEY,
|
4545
4822
|
)
|
4823
|
+
logger.debug(
|
4824
|
+
"args:\n"
|
4825
|
+
f"network: {network}\n"
|
4826
|
+
f"netuid: {netuid}\n"
|
4827
|
+
f"children: {children}\n"
|
4828
|
+
f"proportions: {proportions}\n"
|
4829
|
+
f"wait_for_inclusion: {wait_for_inclusion}\n"
|
4830
|
+
f"wait_for_finalization: {wait_for_finalization}\n"
|
4831
|
+
)
|
4546
4832
|
return self._run_command(
|
4547
4833
|
children_hotkeys.set_children(
|
4548
4834
|
wallet=wallet,
|
@@ -4608,6 +4894,13 @@ class CLIManager:
|
|
4608
4894
|
netuid = IntPrompt.ask(
|
4609
4895
|
"Enter netuid (leave blank for all)", default=None, show_default=True
|
4610
4896
|
)
|
4897
|
+
logger.debug(
|
4898
|
+
"args:\n"
|
4899
|
+
f"network: {network}\n"
|
4900
|
+
f"netuid: {netuid}\n"
|
4901
|
+
f"wait_for_inclusion: {wait_for_inclusion}\n"
|
4902
|
+
f"wait_for_finalization: {wait_for_finalization}\n"
|
4903
|
+
)
|
4611
4904
|
return self._run_command(
|
4612
4905
|
children_hotkeys.revoke_children(
|
4613
4906
|
wallet,
|
@@ -4686,6 +4979,14 @@ class CLIManager:
|
|
4686
4979
|
netuid = IntPrompt.ask(
|
4687
4980
|
"Enter netuid (leave blank for all)", default=None, show_default=True
|
4688
4981
|
)
|
4982
|
+
logger.debug(
|
4983
|
+
"args:\n"
|
4984
|
+
f"network: {network}\n"
|
4985
|
+
f"netuid: {netuid}\n"
|
4986
|
+
f"take: {take}\n"
|
4987
|
+
f"wait_for_inclusion: {wait_for_inclusion}\n"
|
4988
|
+
f"wait_for_finalization: {wait_for_finalization}\n"
|
4989
|
+
)
|
4689
4990
|
results: list[tuple[Optional[int], bool]] = self._run_command(
|
4690
4991
|
children_hotkeys.childkey_take(
|
4691
4992
|
wallet=wallet,
|
@@ -4771,12 +5072,8 @@ class CLIManager:
|
|
4771
5072
|
)
|
4772
5073
|
return False
|
4773
5074
|
param_name = "alpha_values"
|
4774
|
-
low_val = FloatPrompt.ask(
|
4775
|
-
|
4776
|
-
)
|
4777
|
-
high_val = FloatPrompt.ask(
|
4778
|
-
f"Enter the new value for [{COLORS.G.ARG}]alpha_high[/{COLORS.G.ARG}]"
|
4779
|
-
)
|
5075
|
+
low_val = FloatPrompt.ask(f"Enter the new value for {arg__('alpha_low')}")
|
5076
|
+
high_val = FloatPrompt.ask(f"Enter the new value for {arg__('alpha_high')}")
|
4780
5077
|
param_value = f"{low_val},{high_val}"
|
4781
5078
|
if param_name == "yuma_version":
|
4782
5079
|
if not prompt:
|
@@ -4800,7 +5097,7 @@ class CLIManager:
|
|
4800
5097
|
if param_name == "subnet_is_active":
|
4801
5098
|
err_console.print(
|
4802
5099
|
f"[{COLORS.SU.HYPERPARAM}]subnet_is_active[/{COLORS.SU.HYPERPARAM}] "
|
4803
|
-
f"is set by using
|
5100
|
+
f"is set by using {arg__('btcli subnets start')} command."
|
4804
5101
|
)
|
4805
5102
|
return False
|
4806
5103
|
|
@@ -4821,6 +5118,13 @@ class CLIManager:
|
|
4821
5118
|
wallet = self.wallet_ask(
|
4822
5119
|
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME, WO.PATH]
|
4823
5120
|
)
|
5121
|
+
logger.debug(
|
5122
|
+
"args:\n"
|
5123
|
+
f"network: {network}\n"
|
5124
|
+
f"netuid: {netuid}\n"
|
5125
|
+
f"param_name: {param_name}\n"
|
5126
|
+
f"param_value: {param_value}"
|
5127
|
+
)
|
4824
5128
|
result, err_msg = self._run_command(
|
4825
5129
|
sudo.sudo_set_hyperparameter(
|
4826
5130
|
wallet,
|
@@ -4941,6 +5245,7 @@ class CLIManager:
|
|
4941
5245
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
4942
5246
|
validate=WV.WALLET_AND_HOTKEY,
|
4943
5247
|
)
|
5248
|
+
logger.debug(f"args:\nnetwork: {network}\nproposal: {proposal}\nvote: {vote}\n")
|
4944
5249
|
return self._run_command(
|
4945
5250
|
sudo.senate_vote(
|
4946
5251
|
wallet, self.initialize_chain(network), proposal, vote, prompt
|
@@ -4993,7 +5298,7 @@ class CLIManager:
|
|
4993
5298
|
f"Take value must be between {min_value} and {max_value}. Provided value: {take}"
|
4994
5299
|
)
|
4995
5300
|
raise typer.Exit()
|
4996
|
-
|
5301
|
+
logger.debug(f"args:\nnetwork: {network}\ntake: {take}")
|
4997
5302
|
result = self._run_command(
|
4998
5303
|
sudo.set_take(wallet, self.initialize_chain(network), take)
|
4999
5304
|
)
|
@@ -5142,14 +5447,12 @@ class CLIManager:
|
|
5142
5447
|
"""
|
5143
5448
|
if json_output and html_output:
|
5144
5449
|
print_error(
|
5145
|
-
f"Cannot specify both
|
5146
|
-
f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
|
5450
|
+
f"Cannot specify both {arg__('--json-output')} and {arg__('--html')}"
|
5147
5451
|
)
|
5148
5452
|
return
|
5149
5453
|
if current_only and html_output:
|
5150
5454
|
print_error(
|
5151
|
-
f"Cannot specify both
|
5152
|
-
f"and [{COLORS.G.ARG}]--html[/{COLORS.G.ARG}]"
|
5455
|
+
f"Cannot specify both {arg__('--current')} and {arg__('--html')}"
|
5153
5456
|
)
|
5154
5457
|
return
|
5155
5458
|
self.verbosity_handler(quiet=quiet, verbose=verbose, json_output=json_output)
|
@@ -5160,9 +5463,8 @@ class CLIManager:
|
|
5160
5463
|
Constants.network_map[x] for x in non_archives
|
5161
5464
|
]:
|
5162
5465
|
err_console.print(
|
5163
|
-
f"[red]Error[/red] Running this command without
|
5164
|
-
"
|
5165
|
-
f"Try running again with the [{COLORS.G.ARG}]--network archive[/{COLORS.G.ARG}] flag."
|
5466
|
+
f"[red]Error[/red] Running this command without {arg__('--current')} requires use of an archive node. "
|
5467
|
+
f"Try running again with the {arg__('--network archive')} flag."
|
5166
5468
|
)
|
5167
5469
|
return False
|
5168
5470
|
|
@@ -5225,7 +5527,7 @@ class CLIManager:
|
|
5225
5527
|
|
5226
5528
|
EXAMPLE
|
5227
5529
|
|
5228
|
-
[green]$[/green] btcli subnets
|
5530
|
+
[green]$[/green] btcli subnets show
|
5229
5531
|
"""
|
5230
5532
|
self.verbosity_handler(quiet, verbose, json_output)
|
5231
5533
|
subtensor = self.initialize_chain(network)
|
@@ -5337,6 +5639,7 @@ class CLIManager:
|
|
5337
5639
|
logo_url=logo_url,
|
5338
5640
|
additional=additional_info,
|
5339
5641
|
)
|
5642
|
+
logger.debug(f"args:\nnetwork: {network}\nidentity: {identity}\n")
|
5340
5643
|
self._run_command(
|
5341
5644
|
subnets.create(
|
5342
5645
|
wallet, self.initialize_chain(network), identity, json_output, prompt
|
@@ -5398,6 +5701,7 @@ class CLIManager:
|
|
5398
5701
|
],
|
5399
5702
|
validate=WV.WALLET,
|
5400
5703
|
)
|
5704
|
+
logger.debug(f"args:\nnetwork: {network}\nnetuid: {netuid}\n")
|
5401
5705
|
return self._run_command(
|
5402
5706
|
subnets.start_subnet(
|
5403
5707
|
wallet,
|
@@ -5513,7 +5817,9 @@ class CLIManager:
|
|
5513
5817
|
logo_url=logo_url,
|
5514
5818
|
additional=additional_info,
|
5515
5819
|
)
|
5516
|
-
|
5820
|
+
logger.debug(
|
5821
|
+
f"args:\nnetwork: {network}\nnetuid: {netuid}\nidentity: {identity}"
|
5822
|
+
)
|
5517
5823
|
success = self._run_command(
|
5518
5824
|
subnets.set_identity(
|
5519
5825
|
wallet, self.initialize_chain(network), netuid, identity, prompt
|
@@ -5651,6 +5957,7 @@ class CLIManager:
|
|
5651
5957
|
ask_for=[WO.NAME, WO.HOTKEY],
|
5652
5958
|
validate=WV.WALLET_AND_HOTKEY,
|
5653
5959
|
)
|
5960
|
+
logger.debug(f"args:\nnetwork: {network}\nnetuid: {netuid}\nperiod: {period}\n")
|
5654
5961
|
return self._run_command(
|
5655
5962
|
subnets.register(
|
5656
5963
|
wallet,
|
@@ -5763,6 +6070,55 @@ class CLIManager:
|
|
5763
6070
|
)
|
5764
6071
|
)
|
5765
6072
|
|
6073
|
+
def subnets_set_symbol(
|
6074
|
+
self,
|
6075
|
+
wallet_name: str = Options.wallet_name,
|
6076
|
+
wallet_path: str = Options.wallet_path,
|
6077
|
+
wallet_hotkey: str = Options.wallet_hotkey,
|
6078
|
+
network: Optional[list[str]] = Options.network,
|
6079
|
+
netuid: int = Options.netuid,
|
6080
|
+
json_output: bool = Options.json_output,
|
6081
|
+
prompt: bool = Options.prompt,
|
6082
|
+
quiet: bool = Options.quiet,
|
6083
|
+
verbose: bool = Options.verbose,
|
6084
|
+
symbol: str = typer.Argument(help="The symbol to set for your subnet."),
|
6085
|
+
):
|
6086
|
+
"""
|
6087
|
+
Allows the user to update their subnet symbol to a different available symbol. The full list of available symbols can be found here:
|
6088
|
+
[#8CB9E9]https://github.com/opentensor/subtensor/blob/main/pallets/subtensor/src/subnets/symbols.rs#L8[/#8CB9E9]
|
6089
|
+
|
6090
|
+
|
6091
|
+
EXAMPLE
|
6092
|
+
|
6093
|
+
[green]$[/green] btcli subnets set-symbol [dark_orange]--netuid 1 シ[/dark_orange]
|
6094
|
+
|
6095
|
+
|
6096
|
+
JSON OUTPUT:
|
6097
|
+
If --json-output is used, the output will be in the following schema:
|
6098
|
+
[#AFEFFF]{success: [dark_orange]bool[/dark_orange], message: [dark_orange]str[/dark_orange]}[/#AFEFFF]
|
6099
|
+
"""
|
6100
|
+
self.verbosity_handler(quiet, verbose, json_output)
|
6101
|
+
if len(symbol) > 1:
|
6102
|
+
err_console.print("Your symbol must be a single character.")
|
6103
|
+
return False
|
6104
|
+
wallet = self.wallet_ask(
|
6105
|
+
wallet_name,
|
6106
|
+
wallet_path,
|
6107
|
+
wallet_hotkey,
|
6108
|
+
ask_for=[WO.NAME, WO.HOTKEY],
|
6109
|
+
validate=WV.WALLET_AND_HOTKEY,
|
6110
|
+
)
|
6111
|
+
return self._run_command(
|
6112
|
+
subnets.set_symbol(
|
6113
|
+
wallet=wallet,
|
6114
|
+
subtensor=self.initialize_chain(network),
|
6115
|
+
netuid=netuid,
|
6116
|
+
symbol=symbol,
|
6117
|
+
prompt=prompt,
|
6118
|
+
json_output=json_output,
|
6119
|
+
)
|
6120
|
+
)
|
6121
|
+
|
5766
6122
|
def weights_reveal(
|
5767
6123
|
self,
|
5768
6124
|
network: Optional[list[str]] = Options.network,
|
@@ -5848,7 +6204,6 @@ class CLIManager:
|
|
5848
6204
|
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
|
5849
6205
|
validate=WV.WALLET_AND_HOTKEY,
|
5850
6206
|
)
|
5851
|
-
|
5852
6207
|
return self._run_command(
|
5853
6208
|
weights_cmds.reveal_weights(
|
5854
6209
|
self.initialize_chain(network),
|
@@ -6094,7 +6449,14 @@ class CLIManager:
|
|
6094
6449
|
if price_low >= price_high:
|
6095
6450
|
err_console.print("The low price must be lower than the high price.")
|
6096
6451
|
return False
|
6097
|
-
|
6452
|
+
logger.debug(
|
6453
|
+
f"args:\n"
|
6454
|
+
f"hotkey: {hotkey}\n"
|
6455
|
+
f"netuid: {netuid}\n"
|
6456
|
+
f"liquidity: {liquidity_}\n"
|
6457
|
+
f"price_low: {price_low}\n"
|
6458
|
+
f"price_high: {price_high}\n"
|
6459
|
+
)
|
6098
6460
|
return self._run_command(
|
6099
6461
|
liquidity.add_liquidity(
|
6100
6462
|
subtensor=self.initialize_chain(network),
|
@@ -6195,6 +6557,14 @@ class CLIManager:
|
|
6195
6557
|
validate=WV.WALLET,
|
6196
6558
|
return_wallet_and_hotkey=True,
|
6197
6559
|
)
|
6560
|
+
logger.debug(
|
6561
|
+
f"args:\n"
|
6562
|
+
f"network: {network}\n"
|
6563
|
+
f"hotkey: {hotkey}\n"
|
6564
|
+
f"netuid: {netuid}\n"
|
6565
|
+
f"position_id: {position_id}\n"
|
6566
|
+
f"all_liquidity_ids: {all_liquidity_ids}\n"
|
6567
|
+
)
|
6198
6568
|
return self._run_command(
|
6199
6569
|
liquidity.remove_liquidity(
|
6200
6570
|
subtensor=self.initialize_chain(network),
|
@@ -6259,6 +6629,14 @@ class CLIManager:
|
|
6259
6629
|
f"[blue]{position_id}[/blue] (can be positive or negative)",
|
6260
6630
|
negative_allowed=True,
|
6261
6631
|
)
|
6632
|
+
logger.debug(
|
6633
|
+
f"args:\n"
|
6634
|
+
f"network: {network}\n"
|
6635
|
+
f"hotkey: {hotkey}\n"
|
6636
|
+
f"netuid: {netuid}\n"
|
6637
|
+
f"position_id: {position_id}\n"
|
6638
|
+
f"liquidity_delta: {liquidity_delta}"
|
6639
|
+
)
|
6262
6640
|
|
6263
6641
|
return self._run_command(
|
6264
6642
|
liquidity.modify_liquidity(
|
@@ -6274,7 +6652,6 @@ class CLIManager:
|
|
6274
6652
|
)
|
6275
6653
|
|
6276
6654
|
@staticmethod
|
6277
|
-
@utils_app.command("convert")
|
6278
6655
|
def convert(
|
6279
6656
|
from_rao: Optional[str] = typer.Option(
|
6280
6657
|
None, "--rao", help="Convert amount from Rao"
|
@@ -6304,6 +6681,66 @@ class CLIManager:
|
|
6304
6681
|
f"{Balance.from_tao(tao).rao}{Balance.rao_unit}",
|
6305
6682
|
)
|
6306
6683
|
|
6684
|
+
def best_connection(
|
6685
|
+
self,
|
6686
|
+
additional_networks: Optional[list[str]] = typer.Option(
|
6687
|
+
None,
|
6688
|
+
"--network",
|
6689
|
+
help="Network(s) to test for the best connection",
|
6690
|
+
),
|
6691
|
+
):
|
6692
|
+
"""
|
6693
|
+
This command will give you the latency of all finney-like network in additional to any additional networks you specify via the '--network' flag
|
6694
|
+
|
6695
|
+
The results are three-fold. One column is the overall time to initialise a connection, send the requests, and wait for the results. The second column measures single ping-pong speed once connected. The third makes a real world call to fetch the chain head.
|
6696
|
+
|
6697
|
+
EXAMPLE
|
6698
|
+
|
6699
|
+
[green]$[/green] btcli utils latency --network ws://189.234.12.45 --network wss://mysubtensor.duckdns.org
|
6700
|
+
|
6701
|
+
"""
|
6702
|
+
additional_networks = additional_networks or []
|
6703
|
+
if any(not x.startswith("ws") for x in additional_networks):
|
6704
|
+
err_console.print(
|
6705
|
+
"Invalid network endpoint. Ensure you are specifying a valid websocket endpoint"
|
6706
|
+
f" (starting with [{COLORS.G.LINKS}]ws://[/{COLORS.G.LINKS}] or "
|
6707
|
+
f"[{COLORS.G.LINKS}]wss://[/{COLORS.G.LINKS}]).",
|
6708
|
+
)
|
6709
|
+
return False
|
6710
|
+
results: dict[str, list[float]] = self._run_command(
|
6711
|
+
best_connection(Constants.lite_nodes + additional_networks)
|
6712
|
+
)
|
6713
|
+
sorted_results = {
|
6714
|
+
k: v for k, v in sorted(results.items(), key=lambda item: item[1][0])
|
6715
|
+
}
|
6716
|
+
table = Table(
|
6717
|
+
Column("Network"),
|
6718
|
+
Column("End to End Latency", style="cyan"),
|
6719
|
+
Column("Single Request Ping", style="cyan"),
|
6720
|
+
Column("Chain Head Request Latency", style="cyan"),
|
6721
|
+
title="Connection Latencies (seconds)",
|
6722
|
+
caption="lower value is faster",
|
6723
|
+
)
|
6724
|
+
for n_name, (
|
6725
|
+
overall_latency,
|
6726
|
+
single_request,
|
6727
|
+
chain_head,
|
6728
|
+
) in sorted_results.items():
|
6729
|
+
table.add_row(
|
6730
|
+
n_name, str(overall_latency), str(single_request), str(chain_head)
|
6731
|
+
)
|
6732
|
+
console.print(table)
|
6733
|
+
fastest = next(iter(sorted_results.keys()))
|
6734
|
+
if conf_net := self.config.get("network", ""):
|
6735
|
+
if not conf_net.startswith("ws") and conf_net in Constants.networks:
|
6736
|
+
conf_net = Constants.network_map[conf_net]
|
6737
|
+
if conf_net != fastest:
|
6738
|
+
console.print(
|
6739
|
+
f"The fastest network is {fastest}. You currently have {conf_net} selected as your default network."
|
6740
|
+
f"\nYou can update this with {arg__(f'btcli config set --network {fastest}')}"
|
6741
|
+
)
|
6742
|
+
return True
|
6743
|
+
|
6307
6744
|
def run(self):
|
6308
6745
|
self.app()
|
6309
6746
|
|