From 78ec7f8d6dc5c7302a0f26665f99251c5cd45456 Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Mon, 4 Nov 2024 16:50:40 -0800 Subject: [PATCH 01/20] Bumps version and adds changelog --- CHANGELOG.md | 17 +++++++++++++++++ bittensor_cli/__init__.py | 2 +- bittensor_cli/cli.py | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43ae097d..f8206b59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 8.3.0 /2024-11-06 + +## What's Changed + +* Better handle incorrect password by @thewhaleking in https://github.com/opentensor/btcli/pull/187 +* Fixes success path of pow register by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/189 +* Adds `--all` flag to transfer by @thewhaleking in https://github.com/opentensor/btcli/pull/181 +* Various fixes by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Fix wallets in overview by @thewhaleking in https://github.com/opentensor/btcli/pull/197 +* fix handling null neurons by @thewhaleking in https://github.com/opentensor/btcli/pull/214 +* Fix cuda pow registration by @thewhaleking in https://github.com/opentensor/btcli/pull/215 +* Adds confirmation after each successful regen by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/203 +* Removes wallet path prompt by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/205 +* Support hotkey names for include/exclude in st add/remove by @thewhaleking in https://github.com/opentensor/btcli/pull/216 + +**Full Changelog**: https://github.com/opentensor/btcli/compare/v8.2.0...v8.3.0 + ## 8.2.0 /2024-10-10 ## What's Changed diff --git a/bittensor_cli/__init__.py b/bittensor_cli/__init__.py index 8fff761c..6eaa6edc 100644 --- a/bittensor_cli/__init__.py +++ b/bittensor_cli/__init__.py @@ -18,6 +18,6 @@ from .cli import CLIManager -__version__ = "8.2.0" +__version__ = "8.3.0" __all__ = ["CLIManager", "__version__"] diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index e0609e03..db87ca6b 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -57,7 +57,7 @@ class GitError(Exception): pass -__version__ = "8.2.0" +__version__ = "8.3.0" _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0) From 458269a4b84c41301db712620fe395ad7652f619 Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Wed, 6 Nov 2024 13:54:05 -0800 Subject: [PATCH 02/20] Updates changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8206b59..a8b0c3be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ * Adds confirmation after each successful regen by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/203 * Removes wallet path prompt by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/205 * Support hotkey names for include/exclude in st add/remove by @thewhaleking in https://github.com/opentensor/btcli/pull/216 +* Subvortex network added by @thewhaleking in https://github.com/opentensor/btcli/pull/223 +* Add prompt option to all commands which use Confirm prompts by @thewhaleking in https://github.com/opentensor/btcli/pull/227 **Full Changelog**: https://github.com/opentensor/btcli/compare/v8.2.0...v8.3.0 From 1cd1f8ab0b90ba4c7bba505ac64114c0351ff9de Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Wed, 6 Nov 2024 14:58:34 -0800 Subject: [PATCH 03/20] Updates changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b0c3be..e3eeac9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Support hotkey names for include/exclude in st add/remove by @thewhaleking in https://github.com/opentensor/btcli/pull/216 * Subvortex network added by @thewhaleking in https://github.com/opentensor/btcli/pull/223 * Add prompt option to all commands which use Confirm prompts by @thewhaleking in https://github.com/opentensor/btcli/pull/227 +* Update local subtensor port by @distributedstatemachine in https://github.com/opentensor/btcli/pull/228 **Full Changelog**: https://github.com/opentensor/btcli/compare/v8.2.0...v8.3.0 From 534bdd0e5c1b83507afaf857d116213719768ef0 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 13 Nov 2024 19:13:34 +0200 Subject: [PATCH 04/20] Bump versions, add previous release notes. --- CHANGELOG.md | 10 ++++++++-- bittensor_cli/__init__.py | 2 +- bittensor_cli/cli.py | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3eeac9b..cc39f899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ # Changelog + ## 8.3.0 /2024-11-06 ## What's Changed - * Better handle incorrect password by @thewhaleking in https://github.com/opentensor/btcli/pull/187 * Fixes success path of pow register by @ibraheem-opentensor in https://github.com/opentensor/btcli/pull/189 * Adds `--all` flag to transfer by @thewhaleking in https://github.com/opentensor/btcli/pull/181 -* Various fixes by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* In `do_transfer`, we check the balance with coldkeypub.ss58, but then retrieve it from the dict with coldkey.ss58. Resolve this. by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Handle KeyboardInterrupt in CLI to gracefully exit (no traceback) by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Handle race conditions where self.metadata may not be set before finishing initialising runtime (this may need optimised in the future) by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Error description output by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Taostats link fixed by @thewhaleking in https://github.com/opentensor/btcli/pull/199 +* Fixes not showing confirmation if --no-prompt is specified on stake remove by @thewhaleking in https://github.com/opentensor/btcli/pull/199 * Fix wallets in overview by @thewhaleking in https://github.com/opentensor/btcli/pull/197 * fix handling null neurons by @thewhaleking in https://github.com/opentensor/btcli/pull/214 * Fix cuda pow registration by @thewhaleking in https://github.com/opentensor/btcli/pull/215 @@ -16,6 +21,7 @@ * Support hotkey names for include/exclude in st add/remove by @thewhaleking in https://github.com/opentensor/btcli/pull/216 * Subvortex network added by @thewhaleking in https://github.com/opentensor/btcli/pull/223 * Add prompt option to all commands which use Confirm prompts by @thewhaleking in https://github.com/opentensor/btcli/pull/227 +* fix: local subtensor port by @distributedstatemachine in https://github.com/opentensor/btcli/pull/228 * Update local subtensor port by @distributedstatemachine in https://github.com/opentensor/btcli/pull/228 **Full Changelog**: https://github.com/opentensor/btcli/compare/v8.2.0...v8.3.0 diff --git a/bittensor_cli/__init__.py b/bittensor_cli/__init__.py index 6eaa6edc..165a7ac2 100644 --- a/bittensor_cli/__init__.py +++ b/bittensor_cli/__init__.py @@ -18,6 +18,6 @@ from .cli import CLIManager -__version__ = "8.3.0" +__version__ = "8.3.1" __all__ = ["CLIManager", "__version__"] diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 3a312d45..08f8cb08 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -58,7 +58,7 @@ class GitError(Exception): pass -__version__ = "8.3.0" +__version__ = "8.3.1" _core_version = re.match(r"^\d+\.\d+\.\d+", __version__).group(0) From 886909d9714e398ccf54098f178c23ea3beaaa11 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 13 Nov 2024 19:49:17 +0200 Subject: [PATCH 05/20] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50f54414..604e5666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 8.3.1 /2024-11-13 + +## What's Changed +* Better handle incorrect file path for wallets. by @thewhaleking in https://github.com/opentensor/btcli/pull/230 +* Handle websockets version 14, verbose error output by @thewhaleking in https://github.com/opentensor/btcli/pull/236 +* Handles the new PasswordError from bt-wallet by @thewhaleking in https://github.com/opentensor/btcli/pull/232 + +**Full Changelog**: https://github.com/opentensor/btcli/compare/v8.3.0...v.8.3.1 + ## 8.3.0 /2024-11-06 ## What's Changed From d65ca598755c21f68884a3679b7ceff59c2c6d0a Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Fri, 22 Nov 2024 15:20:09 +0200 Subject: [PATCH 06/20] Upgrade websockets --- .../bittensor/async_substrate_interface.py | 37 ++++++++++--------- requirements.txt | 3 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bittensor_cli/src/bittensor/async_substrate_interface.py b/bittensor_cli/src/bittensor/async_substrate_interface.py index 82bfc9d0..2dfd43e5 100644 --- a/bittensor_cli/src/bittensor/async_substrate_interface.py +++ b/bittensor_cli/src/bittensor/async_substrate_interface.py @@ -4,12 +4,11 @@ from collections import defaultdict from dataclasses import dataclass from hashlib import blake2b -from typing import Optional, Any, Union, Callable, Awaitable, cast +from typing import Optional, Any, Union, Callable, Awaitable, cast, TYPE_CHECKING from async_property import async_property from bt_decode import PortableRegistry, decode as decode_by_type_string, MetadataV15 from bittensor_wallet import Keypair -from packaging import version from scalecodec import GenericExtrinsic from scalecodec.base import ScaleBytes, ScaleType, RuntimeConfigurationObject from scalecodec.type_registry import load_type_registry_preset @@ -20,10 +19,14 @@ BlockNotFound, ) from substrateinterface.storage import StorageKey -import websockets +from websockets.asyncio.client import connect +from websockets.exceptions import ConnectionClosed from bittensor_cli.src.bittensor.utils import hex_to_bytes +if TYPE_CHECKING: + from websockets.asyncio.client import ClientConnection + ResultHandler = Callable[[dict, Any], Awaitable[tuple[dict, bool]]] @@ -627,7 +630,7 @@ def __init__( # TODO allow setting max concurrent connections and rpc subscriptions per connection # TODO reconnection logic self.ws_url = ws_url - self.ws: Optional[websockets.WebSocketClientProtocol] = None + self.ws: Optional[ClientConnection] = None self.id = 0 self.max_subscriptions = max_subscriptions self.max_connections = max_connections @@ -655,7 +658,7 @@ async def __aenter__(self): async def _connect(self): self.ws = await asyncio.wait_for( - websockets.connect(self.ws_url, **self._options), timeout=10 + connect(self.ws_url, **self._options), timeout=10 ) async def __aexit__(self, exc_type, exc_val, exc_tb): @@ -698,9 +701,7 @@ async def shutdown(self): async def _recv(self) -> None: try: - response = json.loads( - await cast(websockets.WebSocketClientProtocol, self.ws).recv() - ) + response = json.loads(await cast(ClientConnection, self.ws).recv()) async with self._lock: self._open_subscriptions -= 1 if "id" in response: @@ -709,7 +710,7 @@ async def _recv(self) -> None: self._received[response["params"]["subscription"]] = response else: raise KeyError(response) - except websockets.ConnectionClosed: + except ConnectionClosed: raise except KeyError as e: raise e @@ -720,7 +721,7 @@ async def _start_receiving(self): await self._recv() except asyncio.CancelledError: pass - except websockets.ConnectionClosed: + except ConnectionClosed: # TODO try reconnect, but only if it's needed raise @@ -737,7 +738,7 @@ async def send(self, payload: dict) -> int: try: await self.ws.send(json.dumps({**payload, **{"id": original_id}})) return original_id - except websockets.ConnectionClosed: + except ConnectionClosed: raise async def retrieve(self, item_id: int) -> Optional[dict]: @@ -774,13 +775,13 @@ def __init__( """ self.chain_endpoint = chain_endpoint self.__chain = chain_name - options = { - "max_size": 2**32, - "write_limit": 2**16, - } - if version.parse(websockets.__version__) < version.parse("14.0"): - options.update({"read_limit": 2**16}) - self.ws = Websocket(chain_endpoint, options=options) + self.ws = Websocket( + chain_endpoint, + options={ + "max_size": 2**32, + "write_limit": 2**16, + }, + ) self._lock = asyncio.Lock() self.last_block_hash: Optional[str] = None self.config = { diff --git a/requirements.txt b/requirements.txt index bb50a3a7..268d40ce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,6 @@ fuzzywuzzy~=0.18.0 netaddr~=1.3.0 numpy>=2.0.1 Jinja2 -packaging pycryptodome # Crypto PyYAML~=6.0.1 pytest @@ -16,6 +15,6 @@ rich~=13.7 scalecodec==1.2.11 substrate-interface~=1.7.9 typer~=0.12 -websockets>=12.0 +websockets>=14.1 bittensor-wallet>=2.1.0 bt-decode==0.2.0a0 \ No newline at end of file From 4e5c3cb1bb3c95311bb0c5d51f6745208759813a Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Fri, 22 Nov 2024 16:13:15 +0200 Subject: [PATCH 07/20] Better-improved the asyncio websocket connection. --- .../src/bittensor/async_substrate_interface.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/bittensor_cli/src/bittensor/async_substrate_interface.py b/bittensor_cli/src/bittensor/async_substrate_interface.py index 2dfd43e5..869de573 100644 --- a/bittensor_cli/src/bittensor/async_substrate_interface.py +++ b/bittensor_cli/src/bittensor/async_substrate_interface.py @@ -652,15 +652,12 @@ async def __aenter__(self): self._exit_task.cancel() if not self._initialized: self._initialized = True - await self._connect() + self.ws = await asyncio.wait_for( + connect(self.ws_url, **self._options), timeout=10 + ) self._receiving_task = asyncio.create_task(self._start_receiving()) return self - async def _connect(self): - self.ws = await asyncio.wait_for( - connect(self.ws_url, **self._options), timeout=10 - ) - async def __aexit__(self, exc_type, exc_val, exc_tb): async with self._lock: self._in_use -= 1 @@ -701,7 +698,7 @@ async def shutdown(self): async def _recv(self) -> None: try: - response = json.loads(await cast(ClientConnection, self.ws).recv()) + response = json.loads(await self.ws.recv()) async with self._lock: self._open_subscriptions -= 1 if "id" in response: From c79a81600d2af3233b3335218f49a93b8304dd05 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Fri, 22 Nov 2024 16:24:19 +0200 Subject: [PATCH 08/20] Synced with bittensor implementation. --- bittensor_cli/src/bittensor/async_substrate_interface.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bittensor_cli/src/bittensor/async_substrate_interface.py b/bittensor_cli/src/bittensor/async_substrate_interface.py index 869de573..d9ea3765 100644 --- a/bittensor_cli/src/bittensor/async_substrate_interface.py +++ b/bittensor_cli/src/bittensor/async_substrate_interface.py @@ -439,7 +439,7 @@ def add_item( self.block_hashes[block_hash] = runtime def retrieve( - self, block: Optional[int], block_hash: Optional[str] + self, block: Optional[int] = None, block_hash: Optional[str] = None ) -> Optional["Runtime"]: if block is not None: return self.blocks.get(block) @@ -630,7 +630,7 @@ def __init__( # TODO allow setting max concurrent connections and rpc subscriptions per connection # TODO reconnection logic self.ws_url = ws_url - self.ws: Optional[ClientConnection] = None + self.ws: Optional["ClientConnection"] = None self.id = 0 self.max_subscriptions = max_subscriptions self.max_connections = max_connections @@ -1135,7 +1135,7 @@ async def create_storage_key( ------- StorageKey """ - runtime = await self.init_runtime(block_hash=block_hash) + await self.init_runtime(block_hash=block_hash) return StorageKey.create_from_storage_function( pallet, @@ -1555,7 +1555,7 @@ async def _process_response( self, response: dict, subscription_id: Union[int, str], - value_scale_type: Optional[str], + value_scale_type: Optional[str] = None, storage_item: Optional[ScaleType] = None, runtime: Optional[Runtime] = None, result_handler: Optional[ResultHandler] = None, From 8932194f23fd6229de2b89d92890f807f131241e Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Fri, 22 Nov 2024 16:52:34 +0200 Subject: [PATCH 09/20] Remove is_flag and flag_value deprecated Typer args --- bittensor_cli/cli.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 08f8cb08..26fff060 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -127,8 +127,6 @@ class Options: use_password = typer.Option( True, help="Set this to `True` to protect the generated Bittensor key with a password.", - is_flag=True, - flag_value=False, ) public_hex_key = typer.Option(None, help="The public key in hex format.") ss58_address = typer.Option( @@ -1843,8 +1841,6 @@ def wallet_regen_hotkey( use_password: bool = typer.Option( False, # Overriden to False help="Set to 'True' to protect the generated Bittensor key with a password.", - is_flag=True, - flag_value=True, ), quiet: bool = Options.quiet, verbose: bool = Options.verbose, @@ -1901,8 +1897,6 @@ def wallet_new_hotkey( use_password: bool = typer.Option( False, # Overriden to False help="Set to 'True' to protect the generated Bittensor key with a password.", - is_flag=True, - flag_value=True, ), quiet: bool = Options.quiet, verbose: bool = Options.verbose, From 63917abe375af14095b75bcf424212f62cc86f03 Mon Sep 17 00:00:00 2001 From: Benjamin Himes <37844818+thewhaleking@users.noreply.github.com> Date: Mon, 25 Nov 2024 14:27:18 +0200 Subject: [PATCH 10/20] Speed up faucet (#245) --- .../bittensor/async_substrate_interface.py | 7 ++---- .../src/bittensor/extrinsics/registration.py | 22 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/bittensor_cli/src/bittensor/async_substrate_interface.py b/bittensor_cli/src/bittensor/async_substrate_interface.py index d9ea3765..af54b531 100644 --- a/bittensor_cli/src/bittensor/async_substrate_interface.py +++ b/bittensor_cli/src/bittensor/async_substrate_interface.py @@ -1769,7 +1769,6 @@ async def compose_call( call_params = {} await self.init_runtime(block_hash=block_hash) - call = self.runtime_config.create_scale_object( type_string="Call", metadata=self.metadata ) @@ -2087,7 +2086,8 @@ async def create_signed_extrinsic( :return: The signed Extrinsic """ - await self.init_runtime() + if not self.metadata: + await self.init_runtime() # Check requirements if not isinstance(call, GenericCall): @@ -2140,7 +2140,6 @@ async def create_signed_extrinsic( extrinsic = self.runtime_config.create_scale_object( type_string="Extrinsic", metadata=self.metadata ) - value = { "account_id": f"0x{keypair.public_key.hex()}", "signature": f"0x{signature.hex()}", @@ -2158,9 +2157,7 @@ async def create_signed_extrinsic( signature_cls = self.runtime_config.get_decoder_class("ExtrinsicSignature") if issubclass(signature_cls, self.runtime_config.get_decoder_class("Enum")): value["signature_version"] = signature_version - extrinsic.encode(value) - return extrinsic async def get_chain_finalised_head(self): diff --git a/bittensor_cli/src/bittensor/extrinsics/registration.py b/bittensor_cli/src/bittensor/extrinsics/registration.py index 33c9c156..84f761a8 100644 --- a/bittensor_cli/src/bittensor/extrinsics/registration.py +++ b/bittensor_cli/src/bittensor/extrinsics/registration.py @@ -18,7 +18,6 @@ from typing import Optional import subprocess -import backoff from bittensor_wallet import Wallet from Crypto.Hash import keccak import numpy as np @@ -688,7 +687,7 @@ async def run_faucet_extrinsic( tpb: int = 256, num_processes: Optional[int] = None, update_interval: Optional[int] = None, - log_verbose: bool = False, + log_verbose: bool = True, max_successes: int = 3, ) -> tuple[bool, str]: r"""Runs a continual POW to get a faucet of TAO on the test net. @@ -736,8 +735,12 @@ async def run_faucet_extrinsic( # Attempt rolling registration. attempts = 1 successes = 1 + pow_result: Optional[POWSolution] while True: try: + account_nonce = await subtensor.substrate.get_account_nonce( + wallet.coldkey.ss58_address + ) pow_result = None while pow_result is None or await pow_result.is_stale(subtensor=subtensor): # Solve latest POW. @@ -746,7 +749,7 @@ async def run_faucet_extrinsic( if prompt: err_console.print("CUDA is not available.") return False, "CUDA is not available." - pow_result: Optional[POWSolution] = await create_pow( + pow_result = await create_pow( subtensor, wallet, -1, @@ -759,7 +762,7 @@ async def run_faucet_extrinsic( log_verbose=log_verbose, ) else: - pow_result: Optional[POWSolution] = await create_pow( + pow_result = await create_pow( subtensor, wallet, -1, @@ -779,7 +782,7 @@ async def run_faucet_extrinsic( }, ) extrinsic = await subtensor.substrate.create_signed_extrinsic( - call=call, keypair=wallet.coldkey + call=call, keypair=wallet.coldkey, nonce=account_nonce ) response = await subtensor.substrate.submit_extrinsic( extrinsic, @@ -1246,8 +1249,6 @@ def _terminate_workers_and_wait_for_exit( worker.terminate() -# TODO verify this works with async -@backoff.on_exception(backoff.constant, Exception, interval=1, max_tries=3) async def _get_block_with_retry( subtensor: "SubtensorInterface", netuid: int ) -> tuple[int, int, str]: @@ -1262,10 +1263,9 @@ async def _get_block_with_retry( :raises Exception: If the block hash is None. :raises ValueError: If the difficulty is None. """ - block_number = await subtensor.substrate.get_block_number(None) - block_hash = await subtensor.substrate.get_block_hash( - block_number - ) # TODO check if I need to do all this + block = await subtensor.substrate.get_block() + block_hash = block["header"]["hash"] + block_number = block["header"]["number"] try: difficulty = ( 1_000_000 From 086dda51325a7a6ff954b83076c2cdb2d24f9d48 Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Mon, 25 Nov 2024 15:10:19 -0800 Subject: [PATCH 11/20] Fixed overview message descripancy --- bittensor_cli/src/commands/wallets.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index 322b9538..9a8b0bfa 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -656,8 +656,13 @@ async def overview( neurons ) + has_alerts = False alerts_table = Table(show_header=True, header_style="bold magenta") alerts_table.add_column("🥩 alert!") + alerts_table.add_row( + "[bold]Detected the following stake(s) associated with coldkey(s) that are not linked to any local hotkeys:[/bold]" + ) + alerts_table.add_row("") coldkeys_to_check = [] ck_stakes = await subtensor.get_total_stake_for_coldkey( @@ -680,12 +685,23 @@ async def overview( if difference == 0: continue # We have all our stake registered. + has_alerts = True coldkeys_to_check.append(coldkey_wallet) alerts_table.add_row( - "Found [light_goldenrod2]{}[/light_goldenrod2] stake with coldkey [bright_magenta]{}[/bright_magenta] that is not registered.".format( - abs(difference), coldkey_wallet.coldkeypub.ss58_address + "[light_goldenrod2]{}[/light_goldenrod2] stake associated with coldkey [bright_magenta]{}[/bright_magenta] (ss58: [bright_magenta]{}[/bright_magenta])".format( + abs(difference), + coldkey_wallet.name, + coldkey_wallet.coldkeypub.ss58_address, ) ) + if has_alerts: + alerts_table.add_row("") + alerts_table.add_row( + "[bold yellow]Note:[/bold yellow] This stake might be delegated, staked to another user's hotkey, or associated with a hotkey not present in your wallet." + ) + alerts_table.add_row( + "You can find out more by executing `[bold]btcli wallet inspect[/bold]` command." + ) if coldkeys_to_check: # We have some stake that is not with a registered hotkey. @@ -739,7 +755,7 @@ async def overview( grid = Table.grid(pad_edge=True) # If there are any alerts, add them to the grid - if len(alerts_table.rows) > 0: + if has_alerts: grid.add_row(alerts_table) # Add title From 31adc4cdf2918b5ed8a5a1f602aee2589b399c0e Mon Sep 17 00:00:00 2001 From: Benjamin Himes <37844818+thewhaleking@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:01:39 +0200 Subject: [PATCH 12/20] Fix hyperparams setting. (#252) * Fix hyperparams setting. * Updates check for registration_allowed --------- Co-authored-by: ibraheem-opentensor --- bittensor_cli/cli.py | 10 ++++++++++ bittensor_cli/src/__init__.py | 22 +++++++++++++--------- bittensor_cli/src/commands/sudo.py | 7 ++++--- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 26fff060..55eb4098 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3904,6 +3904,16 @@ def sudo_set( ) param_name = hyperparam_list[choice - 1] + if param_name in ["alpha_high", "alpha_low"]: + param_name = "alpha_values" + low_val = FloatPrompt.ask( + "Enter the new value for [dark_orange]alpha_low[/dark_orange]" + ) + high_val = FloatPrompt.ask( + "Enter the new value for [dark_orange]alpha_high[/dark_orange]" + ) + param_value = f"{low_val},{high_val}" + if not param_value: param_value = Prompt.ask( f"Enter the new value for [dark_orange]{param_name}[/dark_orange] in the VALUE column format" diff --git a/bittensor_cli/src/__init__.py b/bittensor_cli/src/__init__.py index 8cf6aeff..a5ca2170 100644 --- a/bittensor_cli/src/__init__.py +++ b/bittensor_cli/src/__init__.py @@ -318,28 +318,32 @@ class WalletValidationTypes(Enum): HYPERPARAMS = { - "serving_rate_limit": "sudo_set_serving_rate_limit", + "rho": "sudo_set_rho", + "kappa": "sudo_set_kappa", + "immunity_period": "sudo_set_immunity_period", + "min_allowed_weights": "sudo_set_min_allowed_weights", + "max_weights_limit": "sudo_set_max_weight_limit", + "tempo": "sudo_set_tempo", "min_difficulty": "sudo_set_min_difficulty", "max_difficulty": "sudo_set_max_difficulty", "weights_version": "sudo_set_weights_version_key", "weights_rate_limit": "sudo_set_weights_set_rate_limit", - "max_weight_limit": "sudo_set_max_weight_limit", - "immunity_period": "sudo_set_immunity_period", - "min_allowed_weights": "sudo_set_min_allowed_weights", + "adjustment_interval": "sudo_set_adjustment_interval", "activity_cutoff": "sudo_set_activity_cutoff", - "network_registration_allowed": "sudo_set_network_registration_allowed", - "network_pow_registration_allowed": "sudo_set_network_pow_registration_allowed", + "target_regs_per_interval": "sudo_set_target_registrations_per_interval", "min_burn": "sudo_set_min_burn", "max_burn": "sudo_set_max_burn", + "bonds_moving_avg": "sudo_set_bonds_moving_average", + "max_regs_per_block": "sudo_set_max_registrations_per_block", + "serving_rate_limit": "sudo_set_serving_rate_limit", + "max_validators": "sudo_set_max_allowed_validators", "adjustment_alpha": "sudo_set_adjustment_alpha", - "rho": "sudo_set_rho", - "kappa": "sudo_set_kappa", "difficulty": "sudo_set_difficulty", - "bonds_moving_avg": "sudo_set_bonds_moving_average", "commit_reveal_weights_interval": "sudo_set_commit_reveal_weights_interval", "commit_reveal_weights_enabled": "sudo_set_commit_reveal_weights_enabled", "alpha_values": "sudo_set_alpha_values", "liquid_alpha_enabled": "sudo_set_liquid_alpha_enabled", + "registration_allowed": "sudo_set_network_registration_allowed", } # Help Panels for cli help diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 5711a3c2..5c0057ce 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -178,19 +178,20 @@ async def sudo_set_hyperparameter( normalized_value: Union[str, bool] if param_name in [ - "network_registration_allowed", + "registration_allowed", "network_pow_registration_allowed", "commit_reveal_weights_enabled", "liquid_alpha_enabled", ]: - normalized_value = param_value.lower() in ["true", "1"] + normalized_value = param_value.lower() in ["true", "True", "1"] else: normalized_value = param_value is_allowed_value, value = allowed_value(param_name, normalized_value) if not is_allowed_value: err_console.print( - f"Hyperparameter {param_name} value is not within bounds. Value is {normalized_value} but must be {value}" + f"Hyperparameter [dark_orange]{param_name}[/dark_orange] value is not within bounds. " + f"Value is {normalized_value} but must be {value}" ) return From 3eef3b6490db81c629f4a6e33fd715c9d6e6e1e1 Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Wed, 27 Nov 2024 10:43:23 -0800 Subject: [PATCH 13/20] Bumps btwallet to 2.1.2 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 268d40ce..83283c9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,5 +16,5 @@ scalecodec==1.2.11 substrate-interface~=1.7.9 typer~=0.12 websockets>=14.1 -bittensor-wallet>=2.1.0 +bittensor-wallet>=2.1.2 bt-decode==0.2.0a0 \ No newline at end of file From 9dd967ccf49e2861f8910110c9c4330a7f8809d8 Mon Sep 17 00:00:00 2001 From: ibraheem-opentensor Date: Wed, 27 Nov 2024 13:34:18 -0800 Subject: [PATCH 14/20] Bumps btwallet to 2.1.3 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 83283c9c..c35276f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,5 +16,5 @@ scalecodec==1.2.11 substrate-interface~=1.7.9 typer~=0.12 websockets>=14.1 -bittensor-wallet>=2.1.2 +bittensor-wallet>=2.1.3 bt-decode==0.2.0a0 \ No newline at end of file From 80ba1c9bbe246ef0f5310501556076fa2caaa664 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Fri, 29 Nov 2024 12:32:51 +0200 Subject: [PATCH 15/20] Sorted netuids in `btcli r get-weights` --- bittensor_cli/src/commands/root.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/bittensor_cli/src/commands/root.py b/bittensor_cli/src/commands/root.py index 0af9c4eb..1dde73df 100644 --- a/bittensor_cli/src/commands/root.py +++ b/bittensor_cli/src/commands/root.py @@ -866,11 +866,13 @@ async def get_weights( uid_to_weights[uid][netuid] = normalized_weight rows: list[list[str]] = [] + sorted_netuids: list = list(netuids) + sorted_netuids.sort() for uid in uid_to_weights: row = [str(uid)] uid_weights = uid_to_weights[uid] - for netuid in netuids: + for netuid in sorted_netuids: if netuid in uid_weights: row.append("{:0.2f}%".format(uid_weights[netuid] * 100)) else: @@ -879,24 +881,23 @@ async def get_weights( if not no_cache: db_cols = [("UID", "INTEGER")] - for netuid in netuids: + for netuid in sorted_netuids: db_cols.append((f"_{netuid}", "TEXT")) create_table("rootgetweights", db_cols, rows) - netuids = list(netuids) update_metadata_table( "rootgetweights", - {"rows": json.dumps(rows), "netuids": json.dumps(netuids)}, + {"rows": json.dumps(rows), "netuids": json.dumps(sorted_netuids)}, ) else: metadata = get_metadata_table("rootgetweights") rows = json.loads(metadata["rows"]) - netuids = json.loads(metadata["netuids"]) + sorted_netuids = json.loads(metadata["netuids"]) _min_lim = limit_min_col if limit_min_col is not None else 0 - _max_lim = limit_max_col + 1 if limit_max_col is not None else len(netuids) - _max_lim = min(_max_lim, len(netuids)) + _max_lim = limit_max_col + 1 if limit_max_col is not None else len(sorted_netuids) + _max_lim = min(_max_lim, len(sorted_netuids)) - if _min_lim is not None and _min_lim > len(netuids): + if _min_lim is not None and _min_lim > len(sorted_netuids): err_console.print("Minimum limit greater than number of netuids") return @@ -915,8 +916,7 @@ async def get_weights( style="rgb(50,163,219)", no_wrap=True, ) - netuids = list(netuids) - for netuid in netuids[_min_lim:_max_lim]: + for netuid in sorted_netuids[_min_lim:_max_lim]: table.add_column( f"[white]{netuid}", header_style="overline white", @@ -939,7 +939,7 @@ async def get_weights( else: html_cols = [{"title": "UID", "field": "UID"}] - for netuid in netuids[_min_lim:_max_lim]: + for netuid in sorted_netuids[_min_lim:_max_lim]: html_cols.append({"title": str(netuid), "field": f"_{netuid}"}) render_table( "rootgetweights", From fc48a28a68d8ae876a3c3ddda85c08790fc4a737 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Mon, 2 Dec 2024 15:03:22 +0200 Subject: [PATCH 16/20] Sometimes err_docs is a string. We want to handle this properly. --- bittensor_cli/src/bittensor/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index 69d26515..88cfff7b 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -536,7 +536,12 @@ def format_error_message( err_type = error_message.get("type", err_type) err_name = error_message.get("name", err_name) err_docs = error_message.get("docs", [err_description]) - err_description = err_docs[0] if err_docs else err_description + if not err_docs: + err_description = err_description + elif isinstance(err_docs, str): + err_description = err_docs + else: + err_description = err_docs[0] return f"Subtensor returned `{err_name}({err_type})` error. This means: '{err_description}'." From 4f3e351de8a5c7d5774c375f6006fa0be1f98876 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Mon, 2 Dec 2024 18:13:23 +0200 Subject: [PATCH 17/20] Changes hyperparams to list whether they need to be run sudo, and handles this. --- bittensor_cli/src/__init__.py | 53 +++++++++++++++--------------- bittensor_cli/src/commands/sudo.py | 10 ++++-- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/bittensor_cli/src/__init__.py b/bittensor_cli/src/__init__.py index a5ca2170..bba2fdc3 100644 --- a/bittensor_cli/src/__init__.py +++ b/bittensor_cli/src/__init__.py @@ -318,32 +318,33 @@ class WalletValidationTypes(Enum): HYPERPARAMS = { - "rho": "sudo_set_rho", - "kappa": "sudo_set_kappa", - "immunity_period": "sudo_set_immunity_period", - "min_allowed_weights": "sudo_set_min_allowed_weights", - "max_weights_limit": "sudo_set_max_weight_limit", - "tempo": "sudo_set_tempo", - "min_difficulty": "sudo_set_min_difficulty", - "max_difficulty": "sudo_set_max_difficulty", - "weights_version": "sudo_set_weights_version_key", - "weights_rate_limit": "sudo_set_weights_set_rate_limit", - "adjustment_interval": "sudo_set_adjustment_interval", - "activity_cutoff": "sudo_set_activity_cutoff", - "target_regs_per_interval": "sudo_set_target_registrations_per_interval", - "min_burn": "sudo_set_min_burn", - "max_burn": "sudo_set_max_burn", - "bonds_moving_avg": "sudo_set_bonds_moving_average", - "max_regs_per_block": "sudo_set_max_registrations_per_block", - "serving_rate_limit": "sudo_set_serving_rate_limit", - "max_validators": "sudo_set_max_allowed_validators", - "adjustment_alpha": "sudo_set_adjustment_alpha", - "difficulty": "sudo_set_difficulty", - "commit_reveal_weights_interval": "sudo_set_commit_reveal_weights_interval", - "commit_reveal_weights_enabled": "sudo_set_commit_reveal_weights_enabled", - "alpha_values": "sudo_set_alpha_values", - "liquid_alpha_enabled": "sudo_set_liquid_alpha_enabled", - "registration_allowed": "sudo_set_network_registration_allowed", + # btcli name: (subtensor method, sudo bool) + "rho": ("sudo_set_rho", False), + "kappa": ("sudo_set_kappa", False), + "immunity_period": ("sudo_set_immunity_period", False), + "min_allowed_weights": ("sudo_set_min_allowed_weights", False), + "max_weights_limit": ("sudo_set_max_weight_limit", False), + "tempo": ("sudo_set_tempo", True), + "min_difficulty": ("sudo_set_min_difficulty", False), + "max_difficulty": ("sudo_set_max_difficulty", False), + "weights_version": ("sudo_set_weights_version_key", False), + "weights_rate_limit": ("sudo_set_weights_set_rate_limit", False), + "adjustment_interval": ("sudo_set_adjustment_interval", True), + "activity_cutoff": ("sudo_set_activity_cutoff", False), + "target_regs_per_interval": ("sudo_set_target_registrations_per_interval", True), + "min_burn": ("sudo_set_min_burn", False), + "max_burn": ("sudo_set_max_burn", False), + "bonds_moving_avg": ("sudo_set_bonds_moving_average", False), + "max_regs_per_block": ("sudo_set_max_registrations_per_block", True), + "serving_rate_limit": ("sudo_set_serving_rate_limit", False), + "max_validators": ("sudo_set_max_allowed_validators", True), + "adjustment_alpha": ("sudo_set_adjustment_alpha", False), + "difficulty": ("sudo_set_difficulty", False), + "commit_reveal_weights_interval": ("sudo_set_commit_reveal_weights_interval", False), + "commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False), + "alpha_values": ("sudo_set_alpha_values", False), + "liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False), + "registration_allowed": ("sudo_set_network_registration_allowed", False), } # Help Panels for cli help diff --git a/bittensor_cli/src/commands/sudo.py b/bittensor_cli/src/commands/sudo.py index 5c0057ce..2be3c0f6 100644 --- a/bittensor_cli/src/commands/sudo.py +++ b/bittensor_cli/src/commands/sudo.py @@ -104,7 +104,7 @@ async def set_hyperparameter_extrinsic( if not unlock_key(wallet).success: return False - extrinsic = HYPERPARAMS.get(parameter) + extrinsic, sudo_ = HYPERPARAMS.get(parameter, ("", False)) if extrinsic is None: err_console.print(":cross_mark: [red]Invalid hyperparameter specified.[/red]") return False @@ -144,11 +144,17 @@ async def set_hyperparameter_extrinsic( call_params[str(value_argument["name"])] = value # create extrinsic call - call = await substrate.compose_call( + call_ = await substrate.compose_call( call_module="AdminUtils", call_function=extrinsic, call_params=call_params, ) + if sudo_: + call = await substrate.compose_call( + call_module="Sudo", call_function="sudo", call_params={"call": call_} + ) + else: + call = call_ success, err_msg = await subtensor.sign_and_send_extrinsic( call, wallet, wait_for_inclusion, wait_for_finalization ) From 3765a7e8c3b037d7e20940213c75ffb4bc2f141c Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Tue, 3 Dec 2024 22:07:21 +0200 Subject: [PATCH 18/20] Only show hyperparams during `sudo set` if param name and value are not specified. --- bittensor_cli/cli.py | 12 ++++++------ bittensor_cli/src/__init__.py | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 55eb4098..98d58375 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3884,12 +3884,12 @@ def sudo_set( """ self.verbosity_handler(quiet, verbose) - hyperparams = self._run_command( - sudo.get_hyperparameters(self.initialize_chain(network), netuid) - ) - - if not hyperparams: - raise typer.Exit() + if not param_name and not param_value: + hyperparams = self._run_command( + sudo.get_hyperparameters(self.initialize_chain(network), netuid) + ) + if not hyperparams: + raise typer.Exit() if not param_name: hyperparam_list = [field.name for field in fields(SubnetHyperparameters)] diff --git a/bittensor_cli/src/__init__.py b/bittensor_cli/src/__init__.py index bba2fdc3..0d3e67de 100644 --- a/bittensor_cli/src/__init__.py +++ b/bittensor_cli/src/__init__.py @@ -340,7 +340,10 @@ class WalletValidationTypes(Enum): "max_validators": ("sudo_set_max_allowed_validators", True), "adjustment_alpha": ("sudo_set_adjustment_alpha", False), "difficulty": ("sudo_set_difficulty", False), - "commit_reveal_weights_interval": ("sudo_set_commit_reveal_weights_interval", False), + "commit_reveal_weights_interval": ( + "sudo_set_commit_reveal_weights_interval", + False, + ), "commit_reveal_weights_enabled": ("sudo_set_commit_reveal_weights_enabled", False), "alpha_values": ("sudo_set_alpha_values", False), "liquid_alpha_enabled": ("sudo_set_liquid_alpha_enabled", False), From abf8a344823ba1363fc40a468a65a29d922cc378 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Tue, 3 Dec 2024 22:07:21 +0200 Subject: [PATCH 19/20] Only show hyperparams during `sudo set` if param name and value are not specified. --- bittensor_cli/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 98d58375..29e095e8 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3884,7 +3884,7 @@ def sudo_set( """ self.verbosity_handler(quiet, verbose) - if not param_name and not param_value: + if not param_name or not param_value: hyperparams = self._run_command( sudo.get_hyperparameters(self.initialize_chain(network), netuid) ) From 0b8782e8f631d125adb37a7779cdd432258213cf Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 4 Dec 2024 18:34:10 +0200 Subject: [PATCH 20/20] Updates the `--help` for `st children set` and `st children revoke`. --- bittensor_cli/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 55eb4098..e14d6bfe 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -3659,7 +3659,7 @@ def stake_set_children( prompt: bool = Options.prompt, ): """ - Set child hotkeys on specified subnets. + Set child hotkeys on a specified subnet (or all). Overrides currently set children. Users can specify the 'proportion' to delegate to child hotkeys (ss58 address). The sum of proportions cannot be greater than 1. @@ -3744,7 +3744,7 @@ def stake_revoke_children( prompt: bool = Options.prompt, ): """ - Remove all children hotkeys on a specified subnet. + Remove all children hotkeys on a specified subnet (or all). This command is used to remove delegated authority from all child hotkeys, removing their position and influence on the subnet.