Skip to content

Commit 65f4d1c

Browse files
authored
Merge pull request #343 from opentensor/release/9.0.3
Release/9.0.3
2 parents 68cb48a + 9340202 commit 65f4d1c

File tree

12 files changed

+169
-65
lines changed

12 files changed

+169
-65
lines changed

.github/workflows/e2e-subtensor-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
timeout-minutes: 180
3131
env:
3232
RELEASE_NAME: development
33-
RUSTV: nightly-2024-03-05
33+
RUSTV: stable
3434
RUST_BACKTRACE: full
3535
RUST_BIN_DIR: target/x86_64-unknown-linux-gnu
3636
TARGET: x86_64-unknown-linux-gnu

CHANGELOG.md

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

3+
## 9.0.3 /2025-02-26
4+
5+
## What's Changed
6+
* Update wording for burn for sn registration by @thewhaleking in https://github.com/opentensor/btcli/pull/333
7+
* [fix] use chk_take = 0 if None by @camfairchild in https://github.com/opentensor/btcli/pull/335
8+
* Use `unlock_key` fn globally by @thewhaleking in https://github.com/opentensor/btcli/pull/336
9+
* Updates Rust version to stable by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/339
10+
* Warn Users When Setting Root-Only Hyperparams by @thewhaleking in https://github.com/opentensor/btcli/pull/337
11+
* st transfer allow hotkey ss58 by @thewhaleking in https://github.com/opentensor/btcli/pull/338
12+
* Git not required by @thewhaleking in https://github.com/opentensor/btcli/pull/341
13+
* Adds limit of ss58 addresses per call when fetching total_stake by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/340
14+
* Backmerge/main staging 902 by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/342
15+
16+
**Full Changelog**: https://github.com/opentensor/btcli/compare/v9.0.2...v9.0.3
17+
318
## 9.0.2 /2025-02-20
419

520
## What's Changed

bittensor_cli/cli.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ class GitError(Exception):
7474
pass
7575

7676

77-
78-
7977
_epilog = "Made with [bold red]:heart:[/bold red] by The Openτensor Foundaτion"
8078

8179
np.set_printoptions(precision=8, suppress=True, floatmode="fixed")
@@ -481,7 +479,7 @@ def version_callback(value: bool):
481479
f"{repo.active_branch.name}/"
482480
f"{repo.commit()}"
483481
)
484-
except (NameError, GitError):
482+
except (TypeError, GitError):
485483
version = f"BTCLI version: {__version__}"
486484
typer.echo(version)
487485
raise typer.Exit()
@@ -3323,9 +3321,9 @@ def stake_remove(
33233321
def stake_move(
33243322
self,
33253323
network: Optional[list[str]] = Options.network,
3326-
wallet_name=Options.wallet_name,
3327-
wallet_path=Options.wallet_path,
3328-
wallet_hotkey=Options.wallet_hotkey,
3324+
wallet_name: Optional[str] = Options.wallet_name,
3325+
wallet_path: Optional[str] = Options.wallet_path,
3326+
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
33293327
origin_netuid: Optional[int] = typer.Option(
33303328
None, "--origin-netuid", help="Origin netuid"
33313329
),
@@ -3535,14 +3533,45 @@ def stake_transfer(
35353533
)
35363534
self.verbosity_handler(quiet, verbose)
35373535

3536+
if not wallet_name:
3537+
wallet_name = Prompt.ask(
3538+
"Enter the [blue]origin wallet name[/blue]",
3539+
default=self.config.get("wallet_name") or defaults.wallet.name,
3540+
)
35383541
wallet = self.wallet_ask(
3539-
wallet_name,
3540-
wallet_path,
3541-
wallet_hotkey,
3542-
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3543-
validate=WV.WALLET_AND_HOTKEY,
3542+
wallet_name, wallet_path, wallet_hotkey, ask_for=[WO.NAME]
35443543
)
35453544

3545+
if not wallet_hotkey:
3546+
origin_hotkey = Prompt.ask(
3547+
"Enter the [blue]origin hotkey[/blue] name or "
3548+
"[blue]ss58 address[/blue] where the stake will be moved from",
3549+
default=self.config.get("wallet_hotkey") or defaults.wallet.hotkey,
3550+
)
3551+
if is_valid_ss58_address(origin_hotkey):
3552+
origin_hotkey = origin_hotkey
3553+
else:
3554+
wallet = self.wallet_ask(
3555+
wallet_name,
3556+
wallet_path,
3557+
origin_hotkey,
3558+
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
3559+
validate=WV.WALLET_AND_HOTKEY,
3560+
)
3561+
origin_hotkey = wallet.hotkey.ss58_address
3562+
else:
3563+
if is_valid_ss58_address(wallet_hotkey):
3564+
origin_hotkey = wallet_hotkey
3565+
else:
3566+
wallet = self.wallet_ask(
3567+
wallet_name,
3568+
wallet_path,
3569+
wallet_hotkey,
3570+
ask_for=[],
3571+
validate=WV.WALLET_AND_HOTKEY,
3572+
)
3573+
origin_hotkey = wallet.hotkey.ss58_address
3574+
35463575
if not dest_ss58:
35473576
dest_ss58 = Prompt.ask(
35483577
"Enter the [blue]destination wallet name[/blue] or [blue]coldkey SS58 address[/blue]"
@@ -3580,6 +3609,7 @@ def stake_transfer(
35803609
move_stake.transfer_stake(
35813610
wallet=wallet,
35823611
subtensor=self.initialize_chain(network),
3612+
origin_hotkey=origin_hotkey,
35833613
origin_netuid=origin_netuid,
35843614
dest_netuid=dest_netuid,
35853615
dest_coldkey_ss58=dest_ss58,

bittensor_cli/src/bittensor/subtensor_interface.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,20 +1327,29 @@ async def get_stake_for_coldkeys(
13271327
This function is useful for analyzing the stake distribution and delegation patterns of multiple
13281328
accounts simultaneously, offering a broader perspective on network participation and investment strategies.
13291329
"""
1330-
result = await self.query_runtime_api(
1331-
runtime_api="StakeInfoRuntimeApi",
1332-
method="get_stake_info_for_coldkeys",
1333-
params=[coldkey_ss58_list],
1334-
block_hash=block_hash,
1335-
)
1336-
if result is None:
1337-
return None
1338-
1330+
BATCH_SIZE = 60
1331+
1332+
tasks = []
1333+
for i in range(0, len(coldkey_ss58_list), BATCH_SIZE):
1334+
ss58_chunk = coldkey_ss58_list[i : i + BATCH_SIZE]
1335+
tasks.append(
1336+
self.query_runtime_api(
1337+
runtime_api="StakeInfoRuntimeApi",
1338+
method="get_stake_info_for_coldkeys",
1339+
params=[ss58_chunk],
1340+
block_hash=block_hash,
1341+
)
1342+
)
1343+
results = await asyncio.gather(*tasks)
13391344
stake_info_map = {}
1340-
for coldkey_bytes, stake_info_list in result:
1341-
coldkey_ss58 = decode_account_id(coldkey_bytes)
1342-
stake_info_map[coldkey_ss58] = StakeInfo.list_from_any(stake_info_list)
1343-
return stake_info_map
1345+
for result in results:
1346+
if result is None:
1347+
continue
1348+
for coldkey_bytes, stake_info_list in result:
1349+
coldkey_ss58 = decode_account_id(coldkey_bytes)
1350+
stake_info_map[coldkey_ss58] = StakeInfo.list_from_any(stake_info_list)
1351+
1352+
return stake_info_map if stake_info_map else None
13441353

13451354
async def all_subnets(self, block_hash: Optional[str] = None) -> list[DynamicInfo]:
13461355
result = await self.query_runtime_api(

bittensor_cli/src/commands/stake/add.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
is_valid_ss58_address,
1818
print_error,
1919
print_verbose,
20+
unlock_key,
2021
)
2122
from bittensor_wallet import Wallet
2223
from bittensor_wallet.errors import KeyFileError
@@ -338,10 +339,7 @@ async def stake_extrinsic(
338339
if prompt:
339340
if not Confirm.ask("Would you like to continue?"):
340341
raise typer.Exit()
341-
try:
342-
wallet.unlock_coldkey()
343-
except KeyFileError:
344-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
342+
if not unlock_key(wallet).success:
345343
return False
346344

347345
if safe_staking:

bittensor_cli/src/commands/stake/children_hotkeys.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,8 @@ async def display_chk_take(ss58, netuid):
671671
chk_take = await get_childkey_take(
672672
subtensor=subtensor, netuid=netuid, hotkey=ss58
673673
)
674+
if chk_take is None:
675+
chk_take = 0
674676
chk_take = u16_to_float(chk_take)
675677
console.print(
676678
f"Child take for {ss58} is: {chk_take * 100:.2f}% on netuid {netuid}."

bittensor_cli/src/commands/stake/move.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
format_error_message,
1818
group_subnets,
1919
get_subnet_name,
20+
unlock_key,
2021
)
2122

2223
if TYPE_CHECKING:
@@ -621,10 +622,7 @@ async def move_stake(
621622
raise typer.Exit()
622623

623624
# Perform moving operation.
624-
try:
625-
wallet.unlock_coldkey()
626-
except KeyFileError:
627-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
625+
if not unlock_key(wallet).success:
628626
return False
629627
with console.status(
630628
f"\n:satellite: Moving [blue]{amount_to_move_as_balance}[/blue] from [blue]{origin_hotkey}[/blue] on netuid: [blue]{origin_netuid}[/blue] \nto "
@@ -697,6 +695,7 @@ async def transfer_stake(
697695
wallet: Wallet,
698696
subtensor: "SubtensorInterface",
699697
amount: float,
698+
origin_hotkey: str,
700699
origin_netuid: int,
701700
dest_netuid: int,
702701
dest_coldkey_ss58: str,
@@ -709,6 +708,7 @@ async def transfer_stake(
709708
wallet (Wallet): Bittensor wallet object.
710709
subtensor (SubtensorInterface): Subtensor interface instance.
711710
amount (float): Amount to transfer.
711+
origin_hotkey (str): The hotkey SS58 to transfer the stake from.
712712
origin_netuid (int): The netuid to transfer stake from.
713713
dest_netuid (int): The netuid to transfer stake to.
714714
dest_coldkey_ss58 (str): The destination coldkey to transfer stake to.
@@ -739,16 +739,15 @@ async def transfer_stake(
739739
return False
740740

741741
# Get current stake balances
742-
hotkey_ss58 = wallet.hotkey.ss58_address
743742
with console.status(f"Retrieving stake data from {subtensor.network}..."):
744743
current_stake = await subtensor.get_stake(
745744
coldkey_ss58=wallet.coldkeypub.ss58_address,
746-
hotkey_ss58=hotkey_ss58,
745+
hotkey_ss58=origin_hotkey,
747746
netuid=origin_netuid,
748747
)
749748
current_dest_stake = await subtensor.get_stake(
750749
coldkey_ss58=dest_coldkey_ss58,
751-
hotkey_ss58=hotkey_ss58,
750+
hotkey_ss58=origin_hotkey,
752751
netuid=dest_netuid,
753752
)
754753
amount_to_transfer = Balance.from_tao(amount).set_unit(origin_netuid)
@@ -768,19 +767,16 @@ async def transfer_stake(
768767
subtensor=subtensor,
769768
origin_netuid=origin_netuid,
770769
destination_netuid=dest_netuid,
771-
origin_hotkey=hotkey_ss58,
772-
destination_hotkey=hotkey_ss58,
770+
origin_hotkey=origin_hotkey,
771+
destination_hotkey=origin_hotkey,
773772
amount_to_move=amount_to_transfer,
774773
)
775774

776775
if not Confirm.ask("Would you like to continue?"):
777776
raise typer.Exit()
778777

779778
# Perform transfer operation
780-
try:
781-
wallet.unlock_coldkey()
782-
except KeyFileError:
783-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
779+
if not unlock_key(wallet).success:
784780
return False
785781

786782
with console.status("\n:satellite: Transferring stake ..."):
@@ -789,7 +785,7 @@ async def transfer_stake(
789785
call_function="transfer_stake",
790786
call_params={
791787
"destination_coldkey": dest_coldkey_ss58,
792-
"hotkey": hotkey_ss58,
788+
"hotkey": origin_hotkey,
793789
"origin_netuid": origin_netuid,
794790
"destination_netuid": dest_netuid,
795791
"alpha_amount": amount_to_transfer.rao,
@@ -820,12 +816,12 @@ async def transfer_stake(
820816
new_stake, new_dest_stake = await asyncio.gather(
821817
subtensor.get_stake(
822818
coldkey_ss58=wallet.coldkeypub.ss58_address,
823-
hotkey_ss58=hotkey_ss58,
819+
hotkey_ss58=origin_hotkey,
824820
netuid=origin_netuid,
825821
),
826822
subtensor.get_stake(
827823
coldkey_ss58=dest_coldkey_ss58,
828-
hotkey_ss58=hotkey_ss58,
824+
hotkey_ss58=origin_hotkey,
829825
netuid=dest_netuid,
830826
),
831827
)
@@ -933,10 +929,7 @@ async def swap_stake(
933929
raise typer.Exit()
934930

935931
# Perform swap operation
936-
try:
937-
wallet.unlock_coldkey()
938-
except KeyFileError:
939-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
932+
if not unlock_key(wallet).success:
940933
return False
941934

942935
with console.status(

bittensor_cli/src/commands/stake/remove.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
is_valid_ss58_address,
2222
format_error_message,
2323
group_subnets,
24+
unlock_key,
2425
)
2526

2627
if TYPE_CHECKING:
@@ -268,10 +269,7 @@ async def unstake(
268269
raise typer.Exit()
269270

270271
# Execute extrinsics
271-
try:
272-
wallet.unlock_coldkey()
273-
except KeyFileError:
274-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
272+
if not unlock_key(wallet).success:
275273
return False
276274

277275
with console.status("\n:satellite: Performing unstaking operations...") as status:
@@ -465,10 +463,7 @@ async def unstake_all(
465463
):
466464
return False
467465

468-
try:
469-
wallet.unlock_coldkey()
470-
except KeyFileError:
471-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
466+
if not unlock_key(wallet).success:
472467
return False
473468

474469
with console.status("Unstaking all stakes...") as status:

bittensor_cli/src/commands/subnets/subnets.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ async def _find_event_attributes_in_extrinsic_receipt(
9797
sn_burn_cost = await burn_cost(subtensor)
9898
if sn_burn_cost > your_balance:
9999
err_console.print(
100-
f"Your balance of: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}[{COLOR_PALETTE['POOLS']['TAO']}] is not enough to pay the subnet lock cost of: "
101-
f"[{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}[{COLOR_PALETTE['POOLS']['TAO']}]"
100+
f"Your balance of: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}[{COLOR_PALETTE['POOLS']['TAO']}]"
101+
f" is not enough to burn "
102+
f"[{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}[{COLOR_PALETTE['POOLS']['TAO']}] "
103+
f"to register a subnet."
102104
)
103105
return False
104106

@@ -107,7 +109,7 @@ async def _find_event_attributes_in_extrinsic_receipt(
107109
f"Your balance is: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}"
108110
)
109111
if not Confirm.ask(
110-
f"Do you want to register a subnet for [{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}?"
112+
f"Do you want to burn [{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost} to register a subnet?"
111113
):
112114
return False
113115

@@ -145,10 +147,7 @@ async def _find_event_attributes_in_extrinsic_receipt(
145147
)
146148
return False
147149

148-
try:
149-
wallet.unlock_coldkey()
150-
except KeyFileError:
151-
err_console.print("Error decrypting coldkey (possibly incorrect password)")
150+
if not unlock_key(wallet).success:
152151
return False
153152

154153
with console.status(":satellite: Registering subnet...", spinner="earth"):

bittensor_cli/src/commands/sudo.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ async def set_hyperparameter_extrinsic(
189189
":cross_mark: [red]Invalid hyperparameter specified.[/red]"
190190
)
191191
return False
192+
if sudo_:
193+
if not Confirm.ask(
194+
"This hyperparam is only settable by root sudo users. If you are not, this will fail. Please confirm"
195+
):
196+
return False
192197

193198
substrate = subtensor.substrate
194199
msg_value = value if not arbitrary_extrinsic else call_params

0 commit comments

Comments
 (0)